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

dr-sm

Новичок
помоему, очень хороший вопрос:
типа продемонстрируйте возникновение deadlock'a на обычной базе InnoDB.
 

DiMA

php.spb.ru
Команда форума
> fisher вот или знал или профессионализм интуитивно подсказывает ему, что именованные локи - более правильно.

Не выдумывай за него то, чего он не говорил.

Ты еще афтарам ANSI SQL/9x напиши (и заодно всем разработчикам всех *SQL) - вот лохи, зачем вы SELECT ... FOR UPDATE придумали, когда можно все на семафорах сделать. И вообще, транзакции не нужны, есть же локи.

Я смотрю тут умных развелось. Особенно, после чтения доки. Напомню, на вопрос ответили сходу только 2 человека. Остальные (я записывал, кто был в онлайне) - тихо слились .-)

> Ничего, т.к. в постгресе нет средств MySQL ;)

Там все есть. А стандарты так и вообще - 10-20 лет назад придумали.
 

Sherman

Mephi
DiMA

Ну может хоть ты на мой вопрос про insert ответишь(лучше куском кода).
 

Sherman

Mephi
Автор оригинала: DiMA
ты про какой именно вопрос?
Я спрашивал про insert. В pg например, если ты в одной транзакции что-то сделал, то пока не сказал commit изменения видны не будут.

Пример:

Транзакция 1.

begin;
select * from table where column = 'key';
insert into table (column) values ('key');

Транзакция 2.

begin;
select * from table where column = 'key' for update;
insert into table (column) values ('key'); // dupe here

Пока в первой не сказали коммит, никак ты не увидишь эту запись, что является основой любого версионника.

Если теперь добавить unique индекс на column, то вторая вставка пройдет только в том случае, если первая транзакция(в котором insert был раньше) была откачена. А пока первая транзакция(которая сделала insert первой) не решит что делать, вторая будет висеть в row lock.

В mysql не так?
 

DiMA

php.spb.ru
Команда форума
tf
Че, думаешь никто прочитать не успел? У нас все записано .-)

Sherman
Я не эксперт, чтобы отвечать не проверяя, могу ошибиться и с PG не работал.

1. С какой целью ты делаешь два РАЗНЫХ селекса - один без FOR UPDATE, другой с ним? Используй в осбоих случаях FOR UPDATE, тогда поведение будет 100% предсказуемым.

2. Данная задача решается без транзакций вообще. На основе первичного/уникального индекса + проверки affected rows (выкини селекст и сразу делай инсерт).
 

Sherman

Mephi
DiMA
В pg нету lock если записи не сущестует, поэтому insert сделать без uniq key не выйдет описанным выше способом, только update.

p.s. Про индексы я знаю, но в условиях сказано, что их использовать нельзя :)
 

MiksIr

miksir@home:~$
DiMA, а ты не отвечай за него - вопрос не тебе был.

Вот и получается... что select for update есть - знаем, а как он работает - не задумываемся. Так это, DiMA, мы то доку почитали, теперь и ты можешь. В частности на предмет gap lock. Может тогда поймешь, почему не все ринулись отвечать.
 

whirlwind

TDD infected, paranoid
Автор оригинала: Sherman

Пока в первой не сказали коммит, никак ты не увидишь эту запись, что является основой любого версионника.

Если теперь добавить unique индекс на column, то вторая вставка пройдет только в том случае, если первая транзакция(в котором insert был раньше) была откачена. А пока первая транзакция(которая сделала insert первой) не решит что делать, вторая будет висеть в row lock.
Зависит от уровня изоляции. SERIALIZABLE избавляет от всех проблем путем забоя конкурентности. По-умолчанию обычно тот уровень, что ты привел т.е. REPEATABLE READ.
 

Sad Spirit

мизантроп (Старожил PHPClub)
Команда форума
Локи на строки работают в том случае, если есть чё лочить, собственно, а если строки нету?.. Я тут потестировал в Постгресе, конец немного предсказуем:
Код:
Консоль раз:

postgres=# create table dima (a text, b text, c text);
CREATE TABLE
postgres=# begin work;
BEGIN
postgres=# set transaction isolation level serializable;
SET
postgres=# select c from dima where a = 'stupid' and b = 'question' for update;
 c
---
(0 rows)
postgres=# insert into dima values ('stupid', 'question', 'stupid answer');
INSERT 0 1

Открываем вторую консоль:
postgres=# begin work;
BEGIN
postgres=# set transaction isolation level serializable;
SET
postgres=# select c from dima where a = 'stupid' and b = 'question' for update;
 c
---
(0 rows)

postgres=# insert into dima values ('stupid', 'question', 'stupid answer');
INSERT 0 1

В первой консоли:
postgres=# commit;
COMMIT

Ну и во второй консоли:

postgres=# commit;
COMMIT
postgres=# select * from dima;
   a    |    b     |       c
--------+----------+---------------
 stupid | question | stupid answer
 stupid | question | stupid answer
(2 rows)
А MySQL залочит несуществующую строку?

-~{}~ 29.09.09 01:16:

Т.е. кагбэ методы борьбы с конкурентным апдейтом нам продемонстрированы и признаны годными. Теперь ждём на арене цирка Диму с демонстрацией борьбы с конкурентным insert'ом без накладывания блокировки на таблицу и без наличия уникального индекса.
 

whirlwind

TDD infected, paranoid
блин, все туплю уже :) спать пора

в муське точно такой же результат
 

MiksIr

miksir@home:~$
Ну... как сказать =)
Работает это и без установленных руками индексов, однако если таковых нет - они прозрачно создаются. Это в 2-х словах если, а подробнее в доке по мускулю в разделе про локи и транзакции в InnoDB.
 

tf

крылья рулят
DiMA, мне плевать успел не успел, мне стало не интересно
а то что ты написал, тот же бред, на который я и забил
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
забудьте про postres, наконец, это вопрос на знание тонкостей локов InnoDB в MySQL

в PG не бывает запросов "без транзакций вообще" - есть коммит после каждого запроса

кому очень интересно, почитайте
http://www.postgresql.org/docs/8.4/static/mvcc.html
как там реализуется Concurrency Control разными способами

я бы лично на вопрос ТС не ответил просто потому что в своих проектах никогда не видел смысла в InnoDB - если уж я жертвую скоростью, то причин жертвовать целостностью и инструментарием PG у меня нет
(хотя, видимо, на практике случаев много)
а на postgres для такой задачи больше десятка способов можно найти: проверки (check), транзакции, триггеры, локи, хранимые процедуры с глобальными переменными, etc
 

Sad Spirit

мизантроп (Старожил PHPClub)
Команда форума
Автор оригинала: MiksIr
Да, в InnoDB есть gap lock - позволет блокировать несуществующее.
Ну то есть gap lock нам точно поможет в борьбе с конкурентными insert'ами? А то вот whirlwind пишет, что результат АНАЛогичный, а у меня MySQL не установлен, чтобы на ём проверить.

Ну и к тому же, хочу обратить внимание, что в исходной постановке ZOGдачи не было слова "InnoDB", а MySQL, как известно, славится своим зоопарком табличных движков с абсолютно разным поведением.
 
Сверху