25.2.7.3 Ограничения, связанные с обработкой транзакций в NDB Cluster
Существует ряд ограничений в NDB Cluster, касающихся обработки транзакций. К ним относятся следующие:
-
Уровень изоляции транзакций. Двигатель хранения
NDBCLUSTERподдерживает только уровень изоляции транзакцийREAD COMMITTED. (Например,InnoDBподдерживаетREAD COMMITTED,READ UNCOMMITTED,REPEATABLE READиSERIALIZABLE.) Следует помнить, чтоNDBреализуетREAD COMMITTEDна уровне каждой строки; когда запрос чтения попадает в узел данных, хранящий строку, возвращается последняя зафиксированная версия строки на тот момент.Незафиксированные данные никогда не возвращаются, но когда транзакция, изменяющая несколько строк, фиксируется одновременно с транзакцией, считывающей те же строки, транзакция, выполняющая чтение, может наблюдать значения “до”, “после” или и то, и другое для разных строк из-за того, что запрос чтения конкретной строки может быть обработан до или после фиксации другой транзакции.
Чтобы гарантировать, что данная транзакция читает только значения до или после, вы можете наложить блокировки на строки с помощью
SELECT ... LOCK IN SHARE MODE. В таких случаях блокировка удерживается до фиксации транзакции-владельца. Использование блокировок строк также может привести к следующим проблемам:Чаще возникают ошибки таймаута ожидания блокировки и снижается конкурентность
Увеличивается накладные расходы на обработку транзакций из-за того, что чтение требует фазы фиксации
Возможна исчерпанность доступного количества одновременных блокировок, ограниченное параметром
MaxNoOfConcurrentOperations
NDBиспользуетREAD COMMITTEDдля всех чтений, если не используется модификатор, такой какLOCK IN SHARE MODEилиFOR UPDATE.LOCK IN SHARE MODEприводит к использованию общих блокировок строк;FOR UPDATEприводит к использованию эксклюзивных блокировок строк. Чтения по уникальному ключу автоматически повышают свои блокировки с помощьюNDB, чтобы обеспечить согласованность чтения; чтенийBLOBтакже используют дополнительные блокировки для обеспечения согласованности.См. Раздел 25.6.8.4, «Устранение неполадок резервного копирования NDB Cluster», чтобы узнать, как реализация NDB Cluster уровня изоляции транзакций может повлиять на резервное копирование и восстановление баз данных
NDB. -
Транзакции и столбцы BLOB или TEXT.
NDBCLUSTERхранит только часть значения столбца, использующего любой из типов данных MySQLBLOBилиTEXTв таблице, видимой MySQL; остальная частьBLOBилиTEXTхранится в отдельной внутренней таблице, недоступной для MySQL. Это приводит к двум взаимосвязанным проблемам, о которых следует знать при выполненииSELECTна таблицах, содержащих столбцы этих типов:Для любого
SELECTиз таблицы NDB Cluster: ЕслиSELECTвключает столбецBLOBилиTEXT, уровень изоляции транзакцийREAD COMMITTEDпреобразуется в чтение с блокировкой чтения. Это делается для обеспечения согласованности.-
Для любого
SELECT, который использует поиск по уникальному ключу для извлечения столбцов, использующих любой из типов данныхBLOBилиTEXT, и который выполняется в рамках транзакции, общая блокировка чтения удерживается на таблице в течение всей транзакции — то есть, до тех пор, пока транзакция не будет зафиксирована или прервана.Эта проблема не возникает для запросов, использующих сканирование индексов или таблиц, даже для
NDBтаблиц, имеющих столбцыBLOBилиTEXT.Например, рассмотрим таблицу
t, определенную следующимCREATE TABLE:CREATE TABLE t ( a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, b INT NOT NULL, c INT NOT NULL, d TEXT, INDEX i(b), UNIQUE KEY u(c) ) ENGINE = NDB,Следующий запрос к
tвызывает общую блокировку чтения, так как он использует поиск по уникальному ключу:SELECT * FROM t WHERE c = 1;
Однако ни один из четырех показанных здесь запросов не вызывает общей блокировки чтения:
SELECT * FROM t WHERE b = 1; SELECT * FROM t WHERE d = '1'; SELECT * FROM t; SELECT b,c WHERE a = 1;
Это потому, что из этих четырех запросов первый использует сканирование индекса, второй и третий — сканирование таблиц, а четвертый, хотя и использует поиск по первичному ключу, не извлекает значения столбцов
BLOBилиTEXT.Вы можете минимизировать проблемы с общими блокировками чтения, избегая запросов, использующих поиск по уникальному ключу, извлекающих столбцы
BLOBилиTEXT, или, в тех случаях, когда такие запросы избежать невозможно, фиксировать транзакции как можно скорее.
-
Поиск по уникальному ключу и изоляция транзакций. Уникальные индексы реализованы в
NDBс использованием скрытой индексной таблицы, которая поддерживается внутри. Когда к таблицеNDBпользователя осуществляется доступ с помощью уникального индекса, сначала считывается скрытая индексная таблица, чтобы найти первичный ключ, который затем используется для считывания таблицы пользователя. Чтобы избежать изменения индекса во время этой двойной операции чтения, строка, найденная в скрытой индексной таблице, блокируется. Когда строка, на которую ссылается уникальный индекс в таблицеNDBпользователя, обновляется, скрытая индексная таблица блокируется эксклюзивно транзакцией, в которой выполняется обновление. Это означает, что любой операция чтения той же (таблицы пользователя)NDBтаблицы должна дождаться завершения обновления. Это справедливо даже в том случае, когда уровень транзакции операции чтения —READ COMMITTED.Одно из решений, которое можно использовать для обхода потенциально блокирующих чтений, заключается в том, чтобы заставить узел SQL игнорировать уникальный индекс при выполнении чтения. Это можно сделать, используя подсказку индекса
IGNORE INDEXв качестве частиSELECTзапроса, читающего таблицу (см. Раздел 10.9.4, «Подсказки индексов»). Поскольку сервер MySQL создаёт отбрасывающую упорядоченную индексную таблицу для каждого уникального индекса, созданного вNDB, это позволяет считывать упорядоченный индекс вместо этого, и избежать блокировки доступа по уникальному индексу. Результирующее чтение будет таким же согласованным, как и зафиксированное чтение по первичному ключу, возвращая последнее зафиксированное значение на момент чтения строки.Чтение через упорядоченный индекс делает менее эффективным использование ресурсов в кластере и может иметь большую задержку.
Также можно избежать использования уникального индекса для доступа, выполняя запросы по диапазонам, а не по уникальным значениям.
-
Откаты. Нет частичных транзакций и частичных откатов транзакций. Ошибка дублирования ключа или подобная ошибка приводит к откату всей транзакции.
Это поведение отличается от других движков хранения с поддержкой транзакций, таких как
InnoDB, которые могут откатывать отдельные операторы.
-
Транзакции и использование памяти. Как отмечалось в других разделах этой главы, NDB Cluster не хорошо обрабатывает большие транзакции; лучше выполнить несколько небольших транзакций с несколькими операциями каждая, чем пытаться выполнить одну большую транзакцию, содержащую множество операций. Среди прочих соображений, для больших транзакций требуется очень большой объем памяти. Из-за этого поведение транзакции ряда операторов MySQL затронуто, как описано в следующем списке:
TRUNCATE TABLEне является транзакционной, когда используется с таблицамиNDB. Если операцияTRUNCATE TABLEне удаляет таблицу, то ее необходимо повторно запустить до тех пор, пока она не завершится успешно.DELETE FROM(даже безWHERE) является транзакционной. Для таблиц, содержащих большое количество строк, вы можете обнаружить, что производительность улучшается при использовании нескольких операторовDELETE FROM ... LIMIT ...для “разбиения” операции удаления. Если ваша цель — очистить таблицу, то вы можете использоватьTRUNCATE TABLEвместо этого.-
Операторы LOAD DATA.
LOAD DATAне является транзакционной, когда используется с таблицамиNDB. Операторы ALTER TABLE и транзакции. При копировании таблицы
NDBв рамках оператораALTER TABLE, создание копии происходит вне транзакции. (В любом случае, эта операция отменяется при удалении копии.)
Транзакции и функция COUNT(). При использовании NDB Cluster Replication невозможно гарантировать транзакционную согласованность функции
COUNT()на реплике. Другими словами, при выполнении на источнике серии операторов (INSERT,DELETEили обоих), которые изменяют количество строк в таблице в рамках одной транзакции, выполнение запросовSELECT COUNT(*) FROMна реплике может давать промежуточные результаты. Это связано с тем, чтоtableSELECT COUNT(...)может выполнять грязные чтения, и это не ошибка в хранилищеNDB. (См. ошибку #31321 для получения дополнительной информации.)
© 2025 Oracle
Licensed under the GPLv2 License.