2010-01-26 2 views
3
insert into table1 ...; 
update table2 set count=count+1; 

Вышеуказанное вставляет что-то в table1, и если оно завершается успешно, обновляет поле counttable2.Есть ли более эффективный метод, чем транзакции?

Конечно, такие вещи могут обрабатываться транзакциями, но транзакции должны блокировать таблицу, которая не будет эффективной в высокой параллельной системе. И это может быть еще хуже, если вам нужно обновить несколько таблиц в этой транзакции.

Какое у вас решение?

Я использую PHP, и я осуществляю сделки таким образом:

mysql_query('begin'); 

mysql_query($statement1); 

mysql_query($statement2); 
... 
mysql_query('commit'); 

Так это выглядит, как все таблицы, указанные в этих $statement будет заблокированы?

ответ

1

Это больше похоже на работу «Триггеры» для меня. onInsert что-то делать.

+0

В какой версии MySQL установлен стабильный триггер? – user198729

+0

> = 5.1.6 http://dev.mysql.com/doc/refman/5.1/en/create-trigger.html – Rufinus

3

Сделка (которая в контексте MySQL предполагает InnoDB) не потребуется блокировать всю таблицу.

INSERT заблокирует отдельный ряд без зазоров.

UPDATE не будет блокировать любые промежутки, если вы предоставите условие равенства или IN в индексированном поле в предложении WHERE.

Это означает, что с правильно проиндексированной таблицей INSERTs не будет блокировать друг друга, а UPDATEs будет блокировать друг друга только в том случае, если они влияют на одну и ту же строку.

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

Фактически требуется сама блокировка, чтобы два параллельных обновления последовательно увеличивали количество отсчетов.

+0

INSERT не могут блокировать друг друга с помощью блокировок строк, но они все еще могут бороться с блокировками на индексы в таблице и, действительно, тупик друг с другом. Я видел это. – MarkR

+0

'@ MarkR': вы правы, и именно поэтому я специально упомянул« правильно проиндексированную таблицу ». Вот вопрос о проблеме, о которой вы говорите: http://stackoverflow.com/questions/1974890/mysql-stored-procedure-causing-problems – Quassnoi

2

Используйте двигатель хранения InnoDB. Это блокировка уровня строки вместо MyISAM, которая является блокировкой на уровне таблицы.

+0

Или вы можете переключиться на Oracle, который (в большинстве случаев) выполняет блокировку NO. :) – LBushkin

+0

'@ LBushkin': любая операция' DML' на постоянной таблице в 'Oracle' блокирует затронутые строки до конца транзакции. – Quassnoi

+0

Oracle будет блокировать строки, где это необходимо, - необходимо получить правильное транзакционное поведение. – MarkR

1

Сделки прекрасны, чтобы обеспечить поведение «все или ничего» - даже если в вашей системе существует высокая загрузка или высокий уровень параллелизма, вы не должны прекращать использовать транзакции, по крайней мере, если вам нужны ваши данные, чтобы оставаться согласованными !

(А сделки не обязательно заблокировать всю таблицу (ы))

0

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

Как указывали другие, использование базы данных, поддерживающей блокировку на уровне строк, и просто использование явной (или неявной с помощью триггера) транзакции, вероятно, проще. Это определенно более точно и безопасно.