Конкретный вопрос на собеседовании, на который никто не может ответить

DiMA

php.spb.ru
Команда форума
Конкретный вопрос на собеседовании, на который никто не может ответить

Я всех спрашиваю, как в MySQL эмулировать (средствами MySQL) запрет на использования индексов, чтобы:

(а) реализовать поведение AUTO_INCREMENT: скрипты вставляют что-то в базу (сообщение), при этом в колонке ID должен записываться последовательно увеличающийся номер, без дыр, без наложения данных, без дублирования ID.

(б) вставить новую строку (x="y") в базу, если ее там еще нет и сообщить на экран - удалось ли вставить, либо же нет (другой поток первым успел вставить *эту* же строку).

Вариант (б) я даю, чтобы за автоинкременте люди не зацикливались. Напоминаю, индексы запрещены условиями задачи.

Все выполняется в 1000 параллельных потоков (возможно, не только на PHP, а сразу на PHP+C+JAVA+...). Ваще никто ни разу не ответил на этот примитивный вопрос.

Если 1 поток, то все элементарно:
(а)
$max=$db("SELECT max(id) ") + 1;
$db("INSERT ... SET id=$max")

(б)
if ($db("SELECT ... WHERE x='y' ")) { $db("INSERT ... SET x='y' "); echo "готово!"; } else { echo "облом"; }

Если же это работает в 2 и более потоков, то естественно, между двумя запросами вклинятся другие потоки и все будет испорчено (несколько потоков сделают INSERT, создав дублирующиеся строки с одинаковыми ID или X="Y").

Есть куча идиотских вариантов ответа, да и то от очень небольшого числа кандидатов: вложенные запросы, блокировка таблицы целиком (это я засчитываю за отдаленный ответ), задействовать другие таблицы, лок в файлы/мемкеш/семафоры, изменить характер запросов и логику программы (например, вставлять ID пустым,и потом че-то доделывать) и т.д.

Я думаю, здесь тоже никто ответа не знает (кроме, человек 5 с форума). Почему это такой трудный вопрос?..
 

Zh0rzh

Новичок
Re: Конкретный вопрос на собеседовании, на который никто не может ответить

******
здесь не подойдет?


Чую, что не все так просто :)
 

fisher

накатила суть
Мне кажется, я знаю минимум два корректных способа это сделать, не озвученных в "куче идиотских вариантов ответа".

Сначала я было подумал, что задача дурацкая. Но вообще говоря, это не так. Но она точно не простая - очень мало веб-разработчиков думает про "конкурентность" просто потому что задач в среднем по больнице таких мало.
 

DiMA

php.spb.ru
Команда форума
С инкрементом - задача высосана из пальца (либо auto_increment, либо сиквенсы). Но вариант (б) реален. Индексов на все поля таблиц не запасешься, когда условие дальнейшей логики приложения охватывает сразу несколько колонок.

Я знаю только одно решение, которым черным по белому описано в документации, причем продробно разжевано на несколько страниц. Поделись вторым .-)
 

DiMA

php.spb.ru
Команда форума
fisher естественно тоже правильно ответил .-)
 

whirlwind

TDD infected, paranoid
да нет, вроде все должно работать insert select

-~{}~ 26.09.09 16:18:

PS. долго ломал голову, но так и не понял смысла всех этих телодвижений. Почему нельзя сделать все по-нормальному? Насколько я понимаю, любой изврат убъет конкурентность. Так почему нельзя сделать в транзе с максимальным уровнем изоляции? Я в чудеса не верю :)

PPS. а самое непонятное для меня - при чем тут индексы?
 

Splurov

Новичок
whirlwind, как ты вопрос «б» через insert select сделаешь?
Индексы при том, что с ними этих задач не возникнет.
Правда, зачем такие извращения, я тоже не представляю.
 

whirlwind

TDD infected, paranoid
Splurov это не важно. Когда в теме засвечиваються хайлоадщики с правильными ответами, сразу начинаеш искать подвох.

ЗЫ. ыыы, до меня только что дошло, что за индексы имел в виду тс. И потом удивляется, что никто правильно ответить не может.
 

Beavis

Banned
я так понимаю, этот вопрос предполагает использование InnoDB ?
 

Gas

может по одной?
Почему это такой трудный вопрос?..
потому что 99% пользователей mysql знают в базах данных только:
- самый простой синтаксис insert/update/delete
- select...where...order...limit

многие не поборят group by и having, какие индексы бывают, транзакции считаются высшими материями, а уровни изоляции,mvcc - "а шо это?"

Так что результат, неудивительный. Web-dev - это easy money, занимаются все подряд, "мне и за `лапшу` платят, а голова вон к лошади большая, пусть она учится"
 

nirex

Новичок
LOCK TABLES auto READ;
LOCK TABLES auto WRITE;
Update auto set i = i+1;
select @i:=i from auto;
UNLOCK TABLES;
INSERT INTO ttt (`id`) VALUES(@i);
 

nerezus

Вселенский отказник
Я думаю, здесь тоже никто ответа не знает (кроме, человек 5 с форума). Почему это такой трудный вопрос?..
Я хотел ответить вариант с локом, как дали выше(только переменную через MAX получать). Разве он не верный?
 

nerezus

Вселенский отказник
подзапросом в постгресе можно, в mysql не получилось - типа не могу инсертить в таблицу, по которой подзапрос.
 

john.brown

просто кулибин
nerezus
А вот так можно ;)
Код:
INSERT INTO ttt (id, val) VALUES ((SELECT IFNULL(MAX(id)+1,1) FROM ttt AS t1), 222)
Правда, далеко не уверен, что такой способ решит поставленную задачу. Имхо, способ nirex надежнее будет.
 

nerezus

Вселенский отказник
> AS t1
Добавил в неполучившийся запрос это и заработало ) А ведь такая проблема на практике уже решалась =\
 

DiMA

php.spb.ru
Команда форума
whirlwind
john.brown
nirex
Beavis

Этот вопрос на знание блокировок внутри транзакций.

Вложенные запросы, триггеры, хранимые процедуры, переменные и т.д. и т.п. - не по теме. Можно так извратиться, но это костыли. Зная, как поставить блокировку именно на то, что надо, можно решить задачу (а) и (б).

Про задачу (б) все забыли?

У вас есть таблица с колонками A, B, C. В ней любое число любых строк. Задача: если в строке A=1 && B=2 не найдется варианта, где C=3, то нужно либо вставить новую строку (SET A=1, B=2, C=3), либо модифицировать (SET C=3) ту стоку(и), где A=1 && B=2 && C<>3. И самое главное - это должен сделать только один из потоков.
 
Сверху