Будь-який спосіб вибрати, не викликаючи блокування в MySQL?


126

Запит:

SELECT COUNT(online.account_id) cnt from online;

Але онлайн-таблиця також змінюється подією, тому часто я бачу блокування, бігаючи show processlist.

Чи є в MySQL граматика, яка може зробити оператор select не викликаючи блокування?

І я забув вище згадати, що це в підлеглій базі даних MySQL.

Після того, як я доданий у my.cnf:transaction-isolation = READ-UNCOMMITTED раб, зустрінеться з помилкою:

Помилка 'Двійковий журнал неможливий. Повідомлення: Рівень транзакції "ПРОЧИТАНО-НЕЗАБАВЛЕНО" в InnoDB не є безпечним для бінарного режиму "ЗАЯВКА" 'на запит

Отже, чи є сумісний спосіб це зробити?


3
Для інших, хто стикається з цим питанням і не має труднощів із блокуваннями на своїх таблицях: те, як mySQL використовує блокування внутрішньо, залежить від механізму зберігання даних. Прочитайте відповідь @zombat нижче.
Саймон Форсберг

Відповіді:


169

Знайдено статтю під назвою "MYSQL С НОЛОК"

https://web.archive.org/web/20100814144042/http://sqldba.org/articles/22-mysql-with-nolock.aspx

в MS SQL Server ви зробите наступне:

SELECT * FROM TABLE_NAME WITH (nolock)

і еквівалент MYSQL дорівнює

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
SELECT * FROM TABLE_NAME ;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ ;

EDIT

Майкл Міор запропонував таке (з коментарів)

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
SELECT * FROM TABLE_NAME ;
COMMIT ;

54
Просто примітка до майбутніх читачів, яку ви, можливо, захочете усунути SESSIONі, таким чином, мати рівень транзакції, стосується лише наступної транзакції. Потім просто замініть третє вищевикладене на COMMIT. У цьому випадку це буде нооп, але матиме побічний ефект від припинення транзакції та відновлення до рівня ізоляції за замовчуванням.
Майкл Міор

3
Лише зауважте, що посилання мертве ... :(
longda

5
Вибачте, але я маю спростувати цю відповідь, оскільки тут не згадуються про дуже важливі відмінності між InnoDB та MyISAM. Як зазначено вище @omg, це буде працювати для InnoDB, але не для таблиць MyISAM.
Саймон Форсберг

4
@Craig Безумовно, неточно, що MyISAM не видає блоки READ під час SELECT запитів - є блоки та протилежні InnoDB ці блокування - це столові блоки, що блокують усі запитувані WRITE блокування та всі наступні запити під час виконання. Очевидно, що початкове запитання стосується InnoDB, проте рівні ізоляції також не існують для MyISAM - документи для SET TRANSACTIONтвердження : "Цей оператор встановлює рівень ізоляції транзакцій, який використовується для операцій над таблицями InnoDB."
syneticon-dj

1
Точка поступилася. :-) Я дуже намагався посилатися на поведінку фіксації MyISAM проти InnoDB. Ці рішення рівня на основі ізоляції , не застосовуються до MyISAM, який не є транзакционной, тому він використовує в просту блокування таблиці. Оновлення MyISAM та DELETE повинні чекати, коли блокування таблиці очиститься, тому будь-яка наступна черга SELECT, що стоїть за запитом запису, заблокована, поки запис не закінчиться. MyISAM не має "брудних зчитувань" і не дозволяє дозволити більшості записів одночасно з читаннями, таким чином, немає жодного сенсу заперечувати будь-які коментарі тут "не в змозі звернутися до MyISAM". Я думаю, що саме до цього я потрапив. :-)
Крейг

24

Якщо таблиця InnoDB, див. Http://dev.mysql.com/doc/refman/5.1/en/innodb-consistent-read.html - вона використовує послідовне читання (режим без блокування) для SELECTs ", які роблять не вказувати ДЛЯ ОНОВЛЕННЯ або ЗАКЛЮЧЕННЯ В РЕЖИМІ ПОДІЛЕННЯ, якщо встановлено параметр innodb_locks_unsafe_for_binlog, а рівень ізоляції транзакції не встановлений на СЕРІАЛІЗАЦІЙНИЙ. Таким чином, жодних блоків не встановлюється на рядки, прочитані з вибраної таблиці ".


16

Використовуйте

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED.

Версія 5.0 Документи знаходяться тут .

Версія 5.1 тут доступні документи .


2
Дякую, я думаю, що це вже поруч, але як довго ця заява буде впливати? Я буду використовувати цей вислів у програмі PHP, і його слід найкраще скинути. РІВНЯ ІЗОЛЯЦІЇ ТРАНЗАКЦІЇ автоматично, коли запит буде завершений
omg

14

Ви можете прочитати цю сторінку посібника з MySQL. Як блокується таблиця, залежить від типу таблиці.

MyISAM використовує блокування таблиць для досягнення дуже високої швидкості читання, але якщо у вас очікується операція UPDATE, тоді майбутні SELECTS будуть стояти в черзі за UPDATE.

У таблицях InnoDB використовується блокування на рівні рядків, і ви не будете блокувати всю таблицю позаду UPDATE. Є й інші проблеми з блокуванням, пов’язані з InnoDB, але ви можете виявити, що він відповідає вашим потребам.


1
Чи буде "НАСТРОЙКА РОЗВИТКУ ІЗОЛЯЦІЇ ТРАНЗАКЦІЇ ЧИТАТИ НЕЗАКОМНОГО" для таблиць MyISAM?
omg

5
Таблиці MyISAM не підтримують транзакції в будь-якій формі. Транзакційний запит буде виконуватися на таблиці MyISAM, тому запит, який ви згадали вище, буде виконуватися, але він не має ефекту.
зомбат

1
Тоді що я можу зробити, щоб уникнути черги SELECTS у випадку MyISAM?
omg

6
що я можу зробити, щоб уникнути черги SELECTS у випадку MyISAM? Перейти до innodb. MyISAM використовує блокування рівня таблиці для кожного запиту. Це головна вада.
Френк Фермер

2

Залежно від типу вашої таблиці, блокування буде виконуватись по-різному, але так само буде ВИБІР СЧАТКОВО. Для таблиць MyISAM проста таблиця SELECT (*) ВІД таблиці не повинна блокувати таблицю, оскільки вона отримує доступ до метаданих для витягування кількості записів. Innodb займе більше часу, оскільки йому доведеться захоплювати таблицю на знімку для підрахунку записів, але це не повинно викликати блокування.

Ви повинні принаймні встановити concurrent_insert 1 (за замовчуванням). Потім, якщо у файлі даних не буде «прогалин» для заповнення таблиці, до файлу додаються вставки, а SELECT та INSERT можуть відбутися одночасно з таблицями MyISAM. Зауважте, що видалення запису ставить «пробіл» у файл даних, який буде намагатися заповнити майбутніми вставками та оновленнями.

Якщо ви рідко видаляєте записи, то ви можете встановити concurrent_insert рівним 2, а вставки завжди додаватимуться в кінці файлу даних. Тоді вибір і вставлення можуть відбуватися одночасно, але ваш файл даних ніколи не зменшиться, незалежно від того, скільки записів ви видалите (крім усіх записів).

Підсумок, якщо у вас багато оновлень, вставок та виборів у таблиці, вам слід зробити це InnoDB. Тим не менш, можна вільно змішувати типи таблиць у системі.


1

Ще один спосіб включення брудного читання в mysql - це додавання підказки: ЗАКЛЮЧЕННЯ В РОБОТІ

SELECT * FROM TABLE_NAME LOCK IN SHARE MODE; 

"Якщо для автокомісії встановлено значення 1, пункти ЗАКЛЮЧЕННЯ В СПІЛЬНОМУ ПІДПРИЄМЦІ та НА ОНОВЛЕННЯ не впливають." ... і autocommit = 1 за замовчуванням
Martin Zvarík

0

З цієї довідки:

Якщо ви придбаєте блокування таблиці явно з LOCK TABLES, ви можете попросити блокування READ LOCAL, а не блокування READ, щоб дозволити іншим сеансам виконувати паралельні вставки, коли таблиця заблокована.


0

SELECTs зазвичай не роблять жодного блокування, яке вас цікавить у таблицях InnoDB. Рівень ізоляції транзакцій за замовчуванням означає, що вибраний елемент не блокує.

Звичайно, суперечки все-таки трапляються.


1
Я знаю, що ця публікація є давньою, але ця відповідь занадто загальна і є лише іноді правдивою. Див. Dev.mysql.com/doc/refman/5.0/en/innodb-locks-set.html . Блоки, безумовно , набуваються для читання, залежно від рівня ізоляції. Зокрема, у цьому випадку плакат має справу з реплікаційними базами даних і чітко заявляє, що він може використовувати show processlistдля фактичного перегляду блокування. Тож можна з упевненістю припустити, що насправді проводяться замки.
Крейг

1
Відповідь завжди правдива. Звичайно, є деяке блокування - деякі внутрішні мютекси всередині innodb, які використовуються (наприклад, mutex пулу буфера innodb, наприклад). Більшість користувачів не переймаються та не помічають ці блокування, і вони, як правило, змагаються лише під час операцій DDL (наприклад, якщо у вас буфер 16G буфера і "випадає таблиця" в інший потік). Але за замовчуванням він не бере жодних блоків рядків. Це я мав на увазі. Хоча відповідь була досить невиразною.
MarkR

1
Завжди завжди? Що робити, якщо рівень ізоляції транзакцій встановлений на серіалізацію, або оператор select використовує режим LOCK IN SHARE MODE, а автокомісія відключена? Я знаю, що багато (більшість / все?) Серверів баз даних зараз використовують ізоляцію знімків за замовчуванням замість справжньої серіалізації, але хіба ще не виникають випадкові виправдання для примусового читання серіалізаційних читань? Але це здається, що ви говорили, що у всіх віддалених нормальних випадках умови за замовчуванням у MySQL не викликають блокування читання, які впливають на інші потоки, тому не переживайте про проблему, якої у вас немає? Я спробував скасувати свій протокол, BTW. Вибачте ...
Крейг

3
Я сказав "не нормально". Я мав на увазі, якщо ви вибираєте звичайний вибір (без ДЛЯ ОНОВЛЕННЯ або ЗАКЛЮЧЕННЯ В РЕЖИМІ ПОДІЛЕННЯ) і використовуєте стандартний рівень ізоляції транзакцій. Існують кілька дійсних випадків зміни рівня ізоляції, але я б робив це лише за сеансом, ніколи за замовчуванням.
MarkR
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.