Любой способ выбрать без блокировки в MySQL?


126

Запрос:

SELECT COUNT(online.account_id) cnt from online;

Но онлайн-таблица также изменяется событием, поэтому часто я вижу блокировку при запуске show processlist.

Есть ли в MySQL какая-либо грамматика, которая может заставить оператор select не вызывать блокировки?

И я забыл упомянуть выше, что он находится в подчиненной базе данных MySQL.

После того, как я добавлю в my.cnf:transaction-isolation = READ-UNCOMMITTED раб, выйдет ошибка:

Ошибка 'Двоичное ведение журнала невозможно. Сообщение: уровень транзакции 'READ-UNCOMMITTED' в InnoDB небезопасен для режима binlog 'STATEMENT' по запросу

Итак, есть ли совместимый способ сделать это?


3
Для других, которые сталкиваются с этим вопросом и испытывают трудности с блокировками своих таблиц: Как mySQL использует блокировки внутри, зависит от механизма хранения. Читайте ответ @zombat ниже.
Саймон Форсберг

Ответы:


169

Нашел статью под названием "MYSQL WITH NOLOCK"

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 ;

РЕДАКТИРОВАТЬ

Майкл Миор предложил следующее (из комментариев)

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

54
Просто примечание для будущих читателей, что вы, возможно, захотите исключить SESSIONи, таким образом, применить уровень транзакции только к следующей транзакции. Затем просто замените третий оператор выше на COMMIT. В этом случае это будет пустым звуком, но побочным эффектом будет завершение транзакции и возврат к уровню изоляции по умолчанию.
Michael Mior 04

3
Замечу, что ссылка мертва ... :(
longda

5
Извините, но я должен проголосовать против этого ответа за то, что не упомянул здесь очень важные различия между InnoDB и MyISAM. Как указано выше в @omg, это будет работать для InnoDB, но не для таблиц MyISAM.
Саймон Форсберг

4
@Craig Это , безусловно , является неточным , что MyISAM не выдавать блокировки чтения во время запросов SELECT , - там есть замки и противостоящие InnoDB эти блокировки таблиц замки, блокирующие все запрошенные блокировки записи и все последующие запросы во время выполнения. Первоначальный вопрос, кажется, касается InnoDB, хотя уровни изоляции также отсутствуют для MyISAM - документы дляSET TRANSACTION состояния оператора : «Этот оператор устанавливает уровень изоляции транзакции, используемый для операций с таблицами InnoDB».
syneticon-dj

1
Точка сдана. :-) Я действительно пытался сослаться на поведение блокировки MyISAM против InnoDB. Эти решения уровня на основе изоляции , не применяются к MyISAM, который не является транзакционной, поэтому он использует в простую блокировку таблицы. MyISAM UPDATE и DELETE должны дождаться снятия блокировки таблицы, поэтому любая последующая очередь SELECT, стоящая за запросом на запись, блокируется до завершения записи. MyISAM не имеет "грязных чтений" и не имеет возможности разрешить выполнение большинства операций записи одновременно с чтениями, поэтому нет смысла беспокоиться о каких-либо комментариях здесь "неспособность адресовать MyISAM". Я думаю, это то, что я имел в виду. :-)
Craig

24

Если таблица InnoDB, см. Http://dev.mysql.com/doc/refman/5.1/en/innodb-consistent-read.html - он использует согласованное чтение (режим без блокировки) для SELECT, "которые делают не указывайте FOR UPDATE или LOCK IN SHARE MODE, если установлена ​​опция innodb_locks_unsafe_for_binlog и уровень изоляции транзакции не установлен на SERIALIZABLE. Таким образом, для строк, считываемых из выбранной таблицы, не устанавливаются блокировки ».


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

В зависимости от типа вашей таблицы блокировка будет выполняться по-разному, но также будет счетчик SELECT. Для таблиц MyISAM простая таблица SELECT count (*) FROM не должна блокировать таблицу, поскольку она обращается к метаданным для получения счетчика записей. Innodb займет больше времени, так как ему нужно захватить таблицу в снимке для подсчета записей, но это не должно вызывать блокировки.

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

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

Суть в том, что если у вас много обновлений, вставок и выборок в таблице, вы должны сделать это InnoDB. Однако вы можете свободно смешивать типы таблиц в системе.


1

Другой способ включить грязное чтение в mysql - добавить подсказку: LOCK IN SHARE MODE

SELECT * FROM TABLE_NAME LOCK IN SHARE MODE; 

«Если autocommit установлен в 1, предложения LOCK IN SHARE MODE и FOR UPDATE не действуют». ... и autocommit = 1 по умолчанию
Мартин Зварик,

0

Из этой ссылки:

Если вы получаете блокировку таблицы явно с помощью LOCK TABLES, вы можете запросить блокировку READ LOCAL, а не блокировку READ, чтобы позволить другим сеансам выполнять параллельные вставки, пока таблица заблокирована.


0

SELECT обычно не выполняет никаких блокировок, о которых вы заботитесь, в таблицах InnoDB. Уровень изоляции транзакции по умолчанию означает, что выбор не блокирует данные.

Конечно, раздоры все еще случаются.


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

1
Ответ всегда верный. Конечно, есть некоторая блокировка - некоторые внутренние мьютексы внутри innodb, которые используются (например, мьютекс пула буферов innodb). Большинство пользователей не заботятся об этих блокировках и не замечают их, и они обычно состязаются только во время операций DDL (например, если у вас есть буферный пул 16 ГБ и вы выполняете «удаление таблицы» в другом потоке). Но по умолчанию никаких блокировок строк не требуется. Это то, что я имел в виду. Однако ответ был довольно расплывчатым.
MarkR

1
Всегда всегда? Что делать, если уровень изоляции транзакции установлен на сериализуемый или в инструкции select используется LOCK IN SHARE MODE, а автоматическая фиксация отключена? Я знаю, что многие (большинство / все?) Серверы баз данных теперь по умолчанию используют изоляцию моментальных снимков вместо истинной сериализации, но разве не существует случайных оправданий для принудительного сериализуемого чтения? Но похоже, что вы говорили, что во всех отдаленно нормальных случаях условия по умолчанию в MySQL не вызывают блокировки чтения, которые влияют на другие потоки, поэтому не беспокойтесь о проблеме, которой у вас нет? Кстати, я пытался отменить свой голос против. Извините ...
Craig

3
Я сказал: «Обычно нет». Я имел в виду, если вы делаете обычный выбор (без FOR UPDATE или LOCK IN SHARE MODE) и используете уровень изоляции транзакции по умолчанию. Есть несколько допустимых случаев изменения уровня изоляции, но я бы делал это только для каждого сеанса, а не по умолчанию.
MarkR
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.