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хранит только часть значения столбца, использующего любой из типов данныхBLOBилиTEXTMySQL в таблице, видимой 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.