Ето моите бележки от работата с поддръжката на MySQL относно скорошен, странен проблем със заключване (версия 5.1.37):
Всички редове и индексни записи, преминати, за да се стигне до редовете, които се променят, ще бъдат заключени. Това е обхванато на:
http://dev.mysql.com/doc /refman/5.1/en/innodb-locks-set.html
„Заключващо четене, UPDATE или DELETE обикновено заключва запис на всеки запис на индекс, който се сканира при обработката на SQL израза. Няма значение дали има условия WHERE в израза, които биха изключили реда. InnoDB прави не си спомня точното условие WHERE, а знае само кои диапазони на индекси са били сканирани... Ако нямате индекси, подходящи за вашия израз и MySQL трябва да сканира цялата таблица, за да обработи оператора, всеки ред от таблицата се заключва, което в turn блокира всички вмъквания от други потребители към таблицата."
То е. Заобиколно решение, което често е полезно, е да направите:
АКТУАЛИЗАЦИЯ коя таблица зададе каквото и да е нещо, където е първичен ключ (изберете първичен ключ от коя таблица, където ограниченията се подреждат по първичен ключ);
Вътрешният избор не трябва да приема ключалки и след това актуализацията ще има по-малко работа за актуализирането. Клаузата за подреждане гарантира, че актуализацията се извършва в ред на първичен ключ, за да съответства на физическия ред на InnoDB, най-бързият начин да го направите.
Когато има голям брой редове, както във вашия случай, може да е по-добре да съхраните резултата от избора във временна таблица с добавена колона за флаг. След това изберете от временната таблица, където флагът не е зададен, за да получите всяка партида. Пуснете актуализации с ограничение да кажем 1000 или 10000 и задайте флага за партидата след актуализацията. Ограниченията ще поддържат количеството на заключване до приемливо ниво, докато работата по избор ще трябва да се извърши само веднъж. Задължете след всяка партида да освободите ключалките.
Можете също да ускорите тази работа, като направите избрана сума от неиндексирана колона, преди да извършите всяка партида актуализации. Това ще зареди страниците с данни в буферния пул, без да взема ключалки. Тогава заключването ще продължи за по-кратък период от време, защото няма да има четене на диск.
Това не винаги е практично, но когато е така, може да бъде много полезно. Ако не можете да го правите на партиди, можете поне да опитате да изберете първо, за да заредите предварително данните, ако са достатъчно малки, за да се поберат в буферния пул.
Ако е възможно, използвайте режима на изолация на транзакция ПРОЧЕТЕТЕ COMMITTED. Вижте:
http://dev.mysql.com/doc/refman /5.1/bg/set-transaction.html
За да получите това намалено заключване, е необходимо използване на базирано на ред двоично регистриране (вместо двоично регистриране, базирано на изрази по подразбиране).
Два известни проблема:
-
Понякога подзаявките могат да бъдат по-малко от идеално оптимизирани. В този случай това беше нежелана зависима подзаявка – предложението, което направих да използвам подзаявка, се оказа безполезно в сравнение с алтернативата в този случай поради това.
-
Изтриванията и актуализациите нямат същия диапазон от планове за заявки като избраните изрази, така че понякога е трудно да ги оптимизирате правилно, без да измервате резултатите, за да разберете какво точно правят.
И двете постепенно се подобряват. Тази грешка е един пример, при който току-що подобрихме наличните оптимизации за актуализация, въпреки че промените са значителни и все още преминава през QA, за да сме сигурни, че няма големи неблагоприятни ефекти:
http://bugs.mysql.com/bug.php?id=36569