Глава 16. Механизм хранения InnoDB

16.1. Введение в InnoDB

InnoDB механизм хранения общего назначения, который балансирует высокую надежность и высокую производительность. В MySQL 8.0 механизм хранения по умолчанию. Если Вы не сконфигурировали иной механизм хранения значения по умолчанию, CREATE TABLE без предложения ENGINE= создает таблицу InnoDB.

Главные преимущества InnoDB

Главные преимущества InnoDB:

Table 16.1. Особенности механизма хранения InnoDB

Пределы хранения 64TBТранзакцииДа Блокировка степени детализации Строка
MVCCДа Поддержка геоданныхДа Индексирование геоданныхДа
Индексы B-treeДа Индексы T-treeНет Индексы HashНет
Полнотекстовый поиск ДаКластеризируемый индекс ДаКэширование данных Да
Кэширование индексовДа Сжатие данныхДа ШифрованиеДа
Поддержка базы данных кластера НетРепликацияДа Внешние ключиДа
Резервное копирование/восстановление момента времени ДаКэш запросов ДаСтатистика обновления словаря данных Да

Чтобы сравнить особенности InnoDB с другими механизмами хранения, предоставленными MySQL, см. главу 17.

Улучшения InnoDB и новые особенности

Для информации об улучшениях InnoDB и новых особенностях в MySQL 8.0 обратитесь к:

Дополнительная информация о InnoDB и ресурсы

16.1.1. Выгода от использования таблиц InnoDB

Если Вы используете таблицы MyISAM, Вы можете счесть InnoDB выгодными по следующим причинам:

Для InnoDB-специфичных методов тюнинга, которые Вы можете применить в своем коде программы, см. раздел 9.5.

16.1.2. Лучшие методы для таблиц InnoDB

Этот раздел описывает лучшие методы использования таблиц InnoDB.

16.1.3. Проверка, что InnoDB механизм хранения по умолчанию

Чтобы проверить, что InnoDB механизм хранения по умолчанию, используйте команду SHOW ENGINES , чтобы рассмотреть различные механизмы хранения MySQL. Ищите DEFAULT в строке InnoDB. Альтернативно, запросите из INFORMATION_SCHEMA таблицу ENGINES.

16.1.4. Тестирование и сопоставительный анализ с InnoDB

Если InnoDB не механизм хранения по умолчанию, Вы можете определить, работают ли Ваш сервер базы данных или приложения правильно с InnoDB перезапуская сервер с опцией --default-storage-engine=InnoDB, определенной в командной строке или с default-storage-engine=innodb в разделе [mysqld] конфигурационного файла my.cnf.

Если Вы не принимали преднамеренное решение относительно механизма хранения, и Вы только хотите посмотреть, как определенные таблицы работают, когда они создаются под InnoDB, скомандуйте ALTER TABLE table_name ENGINE=InnoDB; для каждой таблицы. Или, чтобы выполнить испытательные запросы, не нарушая оригинальную таблицу, сделайте копию:

CREATE TABLE InnoDB_Table (...) ENGINE=InnoDB AS SELECT * FROM MyISAM_Table;

Проверьте полный жизненный цикл приложения от установки, посредством тяжелого использования и перезапуска сервера. Уничтожьте процесс сервера в то время, как база данных занята, чтобы моделировать перебой в питании и проверить, что данные восстановлены успешно, когда Вы перезапускаете сервер.

Проверьте любые конфигурации репликации, особенно если Вы используете различные версии MySQL и опции на ведущем устройстве и ведомых устройствах.

16.2. InnoDB и модель ACID

Модель ACID ряд принципов проектирования баз данных, которые подчеркивают аспекты надежности, которые важны для коммерческой информации и приложений критического назначения. MySQL включает такие компоненты, как механизм хранения InnoDB, которые придерживаются близко к ACID, чтобы данные не были повреждены и результаты не искажены исключительными условиями, такими как катастрофические отказы программного обеспечения и сбои аппаратных средств. Когда Вы полагаетесь на ACID, Вы не должны повторно изобрести колесо проверки последовательности и механизмы восстановления катастрофического отказа. В случаях, где у Вас есть дополнительные гарантии программного обеспечения, ультранадежные аппаратные средства или приложение, которое может терпеть небольшое количество потерь данных, Вы можете скорректировать настройки MySQL, чтобы обменять часть надежности ACID для большей работы или пропускной способности.

Следующие разделы обсуждают, как MySQL, в особенности механизм хранения InnoDB, взаимодействует с категориями ACID:

Атомность

Атомность аспект ACID, главным образом, вовлекает InnoDB транзакции. Связанные особенности MySQL включают:

Последовательность

Последовательность аспект ACID, главным образом, вовлекает внутреннюю обработку InnoDB, чтобы защитить данные от катастрофических отказов. Связанные особенности MySQL включают:

Изоляция

Изоляция аспект ACID, главным образом, вовлекает InnoDB транзакции, в особенности уровень изоляции, который относится к каждой транзакции. Связанные особенности MySQL включают:

Длительность

Длительность аспект ACID вовлекает характеристики программного обеспечения MySQL, взаимодействующие с Вашей особой конфигурацией аппаратных средств. Из-за многих возможностей в зависимости от способностей Вашего центрального процессора, сети и устройств хранения данных, этот аспект наиболее сложен, чтобы обеспечить конкретные советы. Связанные особенности MySQL включают:

16.3. Мультиверсии InnoDB

InnoDB мультиверсионный механизм хранения: это хранит информацию о старых версиях измененных строк, чтобы поддерживать транзакционные функции, такие как параллелизм и отмену. Эта информация хранится в табличном пространстве в структуре данных, названной сегмент отмены (после аналогичной структуры данных в Oracle). InnoDB использует информацию в сегменте отмены, чтобы выполнить операции отмены, необходимые в работе. Это также использует информацию, чтобы создать более ранние версии строки для последовательного чтения.

Внутренне InnoDB добавляют три поля к каждой строке, сохраненной в базе данных. Поле 6-byte DB_TRX_ID указывает на операционный идентификатор для последней транзакции, которая вставила или обновила строку. Кроме того, удаление обработано внутренне как обновление, где специальный бит в строке установлен, чтобы отметить ее как удаленную. Каждая строка также содержит 7 байтов DB_ROLL_PTR указателя пересчета. Он указывает на запись журнала отмены, записанную в сегмент отмены. Если строка была обновлена, запись журнала отмены содержит информацию, необходимую, чтобы восстановить контент строки прежде, чем это было обновлено. 6 байтов DB_ROW_ID содержит ID строки, который увеличивается монотонно, по мере вставки новых строк. Если InnoDB производит кластеризируемый индекс автоматически, индексирование содержит значения идентификаторов строки. Иначе столбец DB_ROW_ID не появляется ни в каком индексе.

Отмена входит в систему, сегмент отмены разделен на журналы отмены вставки и обновления. Журналы отмены вставки необходимы только в операционной отмене и могут быть стерты, как только транзакция передана. Журналы отмены обновления используются также в последовательных чтениях, но от них можно отказаться только после того, как нет никакой транзакции, к которой InnoDB назначил снимок, который в последовательном чтении мог нуждаться в информации в журнале отмены обновления, чтобы создать более раннюю версию строки базы данных.

Передавайте свои транзакции регулярно, включая те транзакции, которые используют только последовательные чтения. Иначе InnoDB не сможет отказаться от данных журналов отмены обновления, и сегмент отмены может стать слишком большим, заполняя Ваше табличное пространство.

Физический размер записи журнала отмены в сегменте отмены как правило меньше чем соответствующая вставленная или обновленная строка. Вы можете использовать эту информацию, чтобы вычислить пространство, необходимое для Вашего сегмента отмены.

В мультиверсионной схеме InnoDB строка физически немедленно не удалена из базы данных, когда Вы удаляете это запросом SQL. InnoDB физически удаляет соответствующую строку и индексные записи только когда отказывается от записи журнала отмены обновления, записанной для удаления. Эту работу удаления называют чисткой и она довольно быстра, обычно берет тот же самый порядок времени, как запрос SQL, который сделал удаление.

Если Вы вставляете и удаляете строки в небольших пакетах на приблизительно том же самом уровне в таблице, поток чистки может начать отставать, и таблица может стать больше и больше из-за стертых строк, делая работу с диском очень медленной. В таком случае приостановите новые операции строк и выделите больше ресурсов потоку чистки, настраивая переменную innodb_max_purge_lag . См. раздел 16.13.

Мультиверсии и вторичный индекс

InnoDB multiversion concurrency control (MVCC) обрабатывает вторичный индекс по-другому, чем кластеризируемый. Записи в кластеризируемом индексе обновлены оперативнее, и их скрытые системные записи журнала отмены указывают на столбцы, от которых могут быть восстановлены более ранние версии записи. В отличие от кластеризируемого индекса, записи вторичного индекса не содержат скрытые системные столбцы.

Когда столбец вторичного индекса обновлен, старые записи вторичного индекса, отмеченные как удаленные, удаляются, новые вставлены и отмеченные как удаленные в конечном счете очищены. Когда запись вторичного индекса отмечена как удаленная или индексная страница обновлена более новой транзакцией, InnoDB ищет запись базы данных в кластеризируемом индексе. Там запись DB_TRX_ID проверена и правильная версия получена от журнала отмены, если запись была изменена после того, как транзакция чтения была начата.

Если запись вторичного индекса помечена для удаления или индексная страница обновлена более новой транзакцией, метод индексного покрытия не используется. Вместо этого, чтобы возвратить значения из индекса структуры InnoDB ищет запись в кластеризируемом индексе.

Однако, если оптимизация index condition pushdown (ICP) разрешена, и часть выражения WHERE может быть оценена, используя только поля индекса, сервер MySQL передает эту часть WHERE механизму хранения, где это оценено, используя индексирование. Если никакие записи соответствия не найдены, поиск по кластеризируемому индексу не проводится. Если соответствие найдено, даже среди отмеченных для удаления, InnoDB ищет запись в кластеризируемом индексе.

16.4. Архитектура InnoDB

Этот раздел обеспечивает введение в главные компоненты архитектуры механизма хранения InnoDB.

16.4.1. Буферный пул

Буферный пул область в основной памяти, где InnoDB кэширует таблицы и индексы, с которыми работает. Буферный пул позволяет часто используемым данным быть обработанными непосредственно в памяти, что ускоряет обработку. На специализированных серверах базы данных до 80% физической памяти часто назначаются буфрному пулу InnoDB.

Для эффективности большого объема операций чтения буферный пул разделен на страницы, которые могут потенциально содержать много строк. Для эффективности управления кэшем буферный пул осуществлен как связанный список страниц, данные, которые редко используются, удаляются из кэша, используя вариант алгоритма LRU.

Подробности в разделе 16.6.3.

16.4.2. Буфер изменения

Буфер изменения специальная структура данных, которая кэширует изменения в страницах вторичного индекса, когда затронутые страницы не находятся в буферному пуле. Буферизованные изменения, которые могут следовать из операций INSERT, UPDATE или DELETE (DML), слиты позже, когда страницы загружены в буферный пул другими операциями чтения.

В отличие от кластеризируемого индекса, вторичный индекс обычно групповой, и вставки во вторичный индекс происходят в относительно случайном порядке. Точно так же удаления и обновления могут затронуть вторичные индексные страницы, которые рядом не расположены в индексном дереве. Слияние кэшируемых изменений идет в более позднее время, когда затронутые страницы считаны в буферный пул другими операциями, это позволяет избегать существенного ввода/вывода произвольного доступа, который был бы обязан читать вторичные индексные страницы с диска.

Периодически чистка, которая работает, когда система главным образом неактивна, или во время медленного завершения работы, пишет обновленные индексные страницы на диск. Работа чистки может записать дисковые блоки для серии индексируемых значений более эффективно, чем если бы каждое значение было немедленно написано на диск.

Буферное слияние изменения может занять несколько часов, когда есть много вторичных индексов, чтобы обновить, и много затронутых строк. В это время дисковый ввод/вывод увеличен, что может вызвать существенное замедление для запросов к диску. Слияние буферных изменений может также продолжить происходить после того, как транзакция передана. Фактически, слияние буферных изменений может продолжить происходить после завершения работы сервера и перезапуска (см. раздел 16.20.2 ).

В памяти буфер изменения занимает часть буферного пула InnoDB. На диске буфер изменения часть системного табличного пространства, так что индексные изменения остаются буферизованными между перезапусками базы данных.

Типом данных, кэшируемых в буфере изменения, управляет параметр конфигурации innodb_change_buffering. Плдробности в разделе 16.6.4. Вы можете также сконфигурировать максимальный размер буфера изменения. Для получения дополнительной информации см. раздел 16.6.4.1.

Контроль буфера изменения

Следующие опции доступны для контроля буфера изменения:

16.4.3. Адаптивный хеш-индекс

Адаптивный хеш-индекс (AHI) позволяет InnoDB выступить больше как база данных в памяти на системах с соответствующими комбинациями рабочей нагрузки и вполне достаточной памяти для буферного пула, не жертвуя никакими особенностями или надежностью. Эта опция активирована опцией innodb_adaptive_hash_index или выключена при старте сервера параметром --skip-innodb_adaptive_hash_index.

Основанный на наблюдаемом образце поисков, MySQL создает хеш, индексиря использование префикса ключа индекса. Префикс ключа может быть любой длины, и может случиться так, что только некоторые из значений в B-дереве появляются в хеш-индексе. Хеш-индекс создан по требованию для тех страниц индекса, к которым часто получают доступ.

Если таблица почти полностью расположена в основной памяти, хеш-индекс может ускорить запросы, включая прямой поиск любого элемента, разворачивая значение в своего рода указатель. InnoDB имеет механизм, который отслеживает поиски в индексе. Если InnoDB находит, которые запросы могли получить пользу из создания хеш-индекса, это делается автоматически.

С некоторыми рабочими нагрузками ускорение от хеш-индекса очень перевешивает дополнительную работу, чтобы контролировать индекные поиски и поддерживать структуру. Иногда блокировка чтения-записи, которая контролирует доступ к адаптивному хешу может стать источником проблем при тяжелых рабочих нагрузках, таких как многократные параллельные соединения. Запросы с операторами LIKE и подстановочными знаками % также имеют тенденцию не извлекать выгоду из AHI. Для рабочих нагрузок, где адаптивный хеш не нужен, выключение его уменьшает ненужную работу. Поскольку трудно предсказать заранее, является ли эта особенность подходящей для особой системы, считайте рабочие точки отсчета с включенным и отключенным хэшем, используя реалистическую рабочую нагрузку. Архитектурные изменения в MySQL 5.6 и выше делают больше рабочих нагрузок подходящими для того, чтобы запретить адаптивный хеш, чем в более ранних выпусках, хотя это все еще включено по умолчанию.

Адаптивный хеш индекс разделен. Каждый индекс связан с определенным разделением, и каждое разделение защищено отдельным замком. Разделением управляет опция innodb_adaptive_hash_index_parts. По умолчанию это 8. Максимум 512.

Хеш-индекс всегда создается основанный на существующем индексе B-tree для таблицы. InnoDB может создать хеш-индекс на префиксе любой длины ключа, определенного для B-дерева, в зависимости от образца поисков, который InnoDB наблюдает для индекса B-дерева. Хеш-индекс может быть частичным, покрывая только те страницы индексирования, к которым часто получают доступ.

Вы можете контролировать использование адаптивного хеш-индекса и утверждение для его использования в разделе SEMAPHORES вывода команды SHOW ENGINE INNODB STATUS . Если Вы видите, что много потоков ждут на RW-замке, создаваемом в btr0sea.c, тогда могло бы быть полезно отключить адаптивную хеш-индексацию.

Подробности в разделе 9.3.8.

16.4.4. Буфер журнала Redo

Буфер журнала Redo область памяти, которая хранит данные, которые записаны в журнал redo. Размер буфера журнала, определен опцией innodb_log_buffer_size. Буфер журнала периодически сбрасывается к файлу системного журнала на диске. Большой буфер позволяет большим транзакциям работать без потребности записать журнал на диск прежде, чем транзакции передадут. Таким образом, если у Вас есть транзакции, которые обновляют, вставляют или удаляют много строк, увеличение буфера экономит дисковый ввод/вывод.

Опция innodb_flush_log_at_trx_commit управляет, как содержание буфера журнала записано в файл системного журнала. Опция innodb_flush_log_at_timeout управляет тем, как часто буфер сбрасывается на диск.

16.4.5. Системное табличное пространство

Системное табличное пространство InnoDB содержит словарь данных (метаданные для объектов InnoDB), область хранения для буфера doublewrite, буфер изменения и журнал отмены. Системное табличное пространство также содержит таблицу и индексные данные для любых создаваемых пользователем таблиц, которые составлены в системном табличном пространстве. Системное табличное пространство считают совместно используемым табличным пространством, так как оно совместно использовано многими таблицами.

Системное табличное пространство представлено одним или более файлами с данными. По умолчанию, один системный файл с данными, названный ibdata1, создается в каталоге MySQL data. Размером и числом системных файлов с данными управляет опция innodb_data_file_path.

Подробности в разделах 16.6.1 и 16.7.1.

16.4.6. Буфер Doublewrite

Буфер doublewrite это область хранения, расположенная в системном табличном пространстве, где InnoDB пишет страницы, которые сбрасываются из буферного пула InnoDB прежде, чем страницы будут записаны их надлежащим позициям в файле с данными. Только после сброса и записи в буфер doublewrite, InnoDB запишет страницы на их надлежащие позиции. Если есть катастрофический отказ операционной системы, подсистемы хранения или процесса mysqld в середине записи страницы, InnoDB может позже найти хорошую копию страницы в буфере doublewrite во время восстановления катастрофического отказа.

Хотя данные всегда пишутся дважды, буфер doublewrite не требует вдвое большего количества ввода/вывода или вдвое большего количества операций ввода/вывода. Данные записаны в буфер doublewrite непосредственно как большой последовательный кусок одним вызовом fsync().

Буфер doublewrite включен по умолчанию в большинстве случаев. Чтобы отключить буфер doublewrite, надо установить опцию innodb_doublewrite в 0.

Если системные файлы табличного пространства (файлы ibdata ) расположены на устройствах Fusion-io, которые поддерживают атомную запись буфер doublewrite автоматически отключен, и атомная запись Fusion-io используются для всех файлов с данными. Поскольку буферная установка doublewrite глобальна, буферизация doublewrite также отключена для файлов с данными, находящихся на не Fusion-io аппаратных средствах. Эта функция поддерживается только на аппаратных средствах Fusion-io и включена только для Fusion-io NVMFS в Linux. Чтобы в полной мере воспользоваться этой особенностью рекомендуется установка innodb_flush_method в O_DIRECT.

16.4.7. Журнал отмены

Журнал отмены (или сегмент отмены) является областью хранения, которая хранит копии данных, измененных активными транзакциями. Если другая транзакция должна видеть оригинальные данные (как часть последовательной работы чтения), неизмененные данные получены от этой области хранения. По умолчанию эта область физически часть системного табличного пространства. Однако, журналы отмены могут также находиться в отдельных табличных пространствах отмены. Для получения дополнительной информации см. разделы 16.7.7 и 16.3.

InnoDB поддерживает 128 журналов отмены. Однако, 32 из 128 журналов отмены зарезервированы для временных табличных транзакций. Каждой транзакции, которая обновляет временную таблицу (исключая транзакции только для чтения) назначают два журнала отмены, один просто отмены, второй с поддержкой redo. Транзакции только для чтения получают один журнал отмены, поскольку транзакциям только для чтения разрешают изменить только временные таблицы.

Это оставляет 96 доступных журналов отмены, каждый из которых поддерживает до 1023 параллельных изменяющих данные транзакций, для полного предела приблизительно 96k параллельных изменяющих данные транзакций. 96K предела предполагает, что транзакции не изменяют временные таблицы. Если все изменяющие данные транзакции также изменяют временные таблицы, полный предел составляет приблизительно 32k параллельных транзакций изменения данных. Для получения дополнительной информации о журналах отмены, которые сохранены для временных табличных транзакций, см. раздел 16.4.11.1.

Опция innodb_undo_logs определяет число журналов отмены, используемых InnoDB.

16.4.8. Табличные пространства File-Per-Table

Табличное пространство File-Per-Table однотабличное пространство, которое создается в его собственном файле с данными, а не в системном табличном пространстве. Таблицы составлены в табличных пространствах file-per-table, когда включена опция innodb_file_per_table. Иначе таблицы InnoDB составлены в системном табличном пространстве. Каждое табличное пространство file-per-table представлено файлом данных .ibd, который создается в каталоге базы данных по умолчанию.

Табличные пространства per-table допускают форматы строк DYNAMIC и COMPRESSED, которые поддерживают функции, такие как хранение вне страницы для данных переменной длины и табличное сжатие. Для информации об этих особенностях и о других преимуществах табличных пространств file-per-table см. раздел 16.7.4.

16.4.9. Общие табличные пространства

Совместно используемое InnoDB табличное пространство создано с помощью CREATE TABLESPACE . Общие табличные пространства могут быть созданы за пределами каталога данных MySQL, способны к хранению многих таблиц и поддерживают таблицы всех форматов строк.

Таблицы добавлены к общему табличному пространству через CREATE TABLE tbl_name ... TABLESPACE [=] tablespace_name или ALTER TABLE tbl_name TABLESPACE [=] tablespace_name.

16.4.10. Табличное пространство отмены

Табличное пространство отмены состоит из одного или более файлов, содержащих журнал отмены. Табличное пространство отмены создается только когда журнал отмены отделен от системного табличного пространства, используя опции innodb_undo_tablespaces и innodb_undo_directory .

16.4.11. Временное табличное пространство

Временное табличное пространство это табличное пространство для несжатых временных таблиц и связанных объектов. Параметр конфигурации innodb_temp_data_file_path определяет относительный путь для временного файла с данными табличного пространства. Если innodb_temp_data_file_path не задан, в каталоге данных создается единственный авторасширяемый файл с данными в 12 МБ и именем ibtmp1. Временное табличное пространство обновлено при каждом старте сервера и получает динамически произведенный ID пространства, который помогает избежать конфликтов с существующими ID. Временное табличное пространство не может находиться на сыром устройстве. Сервер не стартует, если временное табличное пространство не может быть создано.

Временное табличное пространство удалено при нормальном завершении работы или прерванной инициализации. Временное табличное пространство не удалено, когда катастрофический отказ происходит. В этом случае администратор базы данных может удалить временное табличное пространство вручную или перезапустить сервер с той же самой конфигурацией, которая удаляет и обновляет временное табличное пространство.

16.4.11.1. Временные табличные журналы отмены InnoDB

Временные табличные журналы отмены используются для временных таблиц и связанных объектов. Этот тип журнала отмены не redo-журнал, поскольку временные таблицы не восстановлены во время восстановления катастрофического отказа и не требуют такого журнала. Временные табличные журналы отмены, однако, используются для отмены, в то время как сервер работает. Этот специальный тип журнала позволяет обойтись без redo-протоколов ввода/вывода для временных таблиц и связанных объектов. Временные табличные журналы отмены находятся во временном табличном пространстве. Значение по умолчанию: временный файл табличного пространства, ibtmp1, расположенный в каталоге данных по умолчанию и всегда обновляется при запуске сервера. Определяемое пользователем местоположение для временного файла табличного пространства может быть определено, устанавливая опцию конфигурации innodb_temp_data_file_path.

32 сегмента отмены отведены для временных табличных журналов отмены для транзакций, которые изменяют временные таблицы и связанные объекты, что означает, что максимальное количество сегментов отмены, доступных для изменяющих данные транзакций, которые производят отчеты отмены, 96. С 96 доступными сегментами отмены предел параллельных изменяющих данные транзакциях составляет 96K. Для получения дополнительной информации см. разделы 16.3 и 16.8.7.

16.4.12. Журнал redo

Журнал redo это основанная на диске структура данных, используемая во время восстановления катастрофического отказа, чтобы исправить данные, написанные неполными транзакциями. Во время нормального функционирования журнал кодирует просьбы изменить табличные данные, которые следуют из запросов SQL или вызовов низкого уровня API. Модификации, которые не закончили обновлять файлы с данными перед неожиданным завершением работы, переигрываются автоматически во время инициализации, прежде, чем соединения будут приняты. Для информации о роли журналов redo в восстановлении после катастрофического отказа см. раздел 16.17.1.

По умолчанию журнал физически представлен на диске как ряд файлов, названных ib_logfile0 и ib_logfile1. MySQL пишет файлы системного журнала круговым способом. Данные в журнале закодированы с точки зрения затронутых записей, эти данные все вместе упоминаются как redo. Проход данных через журнал представлен постоянно увеличивающимся значением LSN.

Для соответствующей информации см.:

16.4.12.1. Групповой Commit для сброса Redo-журнала

InnoDB, как ACID-совместимый механизм базы данных, сбрасывает redo-журнал транзакций прежде, чем это будет передано. InnoDB использует групповой commit, чтобы сгруппировать много таких запросов вместе. Из-за этого InnoDB делает одну запись в файл журнала, чтобы выполнить действие для многих транзакций, которые идут приблизительно в то же самое время, значительно улучшая пропускную способность.

Для получения дополнительной информации об исполнении COMMIT и других действий с транзакциями см. see раздел 9.5.2.

16.5. Блокировка InnoDB и операционная модель

Чтобы осуществить крупномасштабное или очень надежное приложение базы данных или настроить работу MySQL, важно понять блокировку и операционную модель InnoDB.

Этот раздел обсуждает несколько тем, связанных с блокировкой и операционной моделью, с которой Вы должны быть знакомы.

16.5.1. Блокировка InnoDB

Этот раздел описывает типы блокировки, используемые InnoDB.

Совместно использованные и исключительные блокировки

InnoDB реализует стандартные блокировки уровня строки, где есть два типа блокировок, совместно использованные (S) и исключительные (X).

Если транзакция T1 держит совместно используемую (S) блокировку на строке r, тогда запросы от некоторой отличной транзакции T2 для блокировки на строке r обработаны следующим образом:

Если транзакция T1 держит исключительную (X) блокировку строки r, запрос от некоторой отличной транзакции T2 для блокировки любого типа на r не может быть немедленно предоставлен. Вместо этого транзакция T2 должна ждать, пока транзакция T1 выпустит блокировку на строке r.

Блокировки намерения

InnoDB допускает многократные блокировки степени детализации, которые разрешают сосуществование блокировок на уровне строки и соединяет все таблицы. Чтобы сделать блокировку на многих уровнях степени детализации дополнительные типы блокировок, названных блокировками намерения, используются. Блокировки намерения это блокировки на уровне таблицы в InnoDB, которые указывают, какого типа блокировки (совместно используемые или исключительные) транзакция потребует позже для строки в той таблице. Есть два типа блокировок намерения, используемых в InnoDB (предположим, что транзакция T требует блокировку обозначенного типа на таблице t):

Например, SELECT ... LOCK IN SHARE MODE поставит IS, а SELECT ... FOR UPDATE поставит IX.

Протокол блокировки намерения:

Эти правила могут быть удобно получены в итоге посредством следующей матрицы совместимости типа блокировки.

X IXS IS
XКонфликтуют КонфликтуютКонфликтуютКонфликтуют
IXКонфликтуютСовместимы КонфликтуютСовместимы
SКонфликтуютКонфликтуют СовместимыСовместимы
ISКонфликтуютСовместимы СовместимыСовместимы

Блокировку предоставляют транзакции требования, если это совместимо с существующими блокировками, но не предоставляют, если это находится в противоречии с существующими блокировками. Тогда транзакция ждет, пока противоречивая существующая блокировка не будет выпущена. Если запрос блокировки находится в противоречии с существующей блокировкой и не может быть предоставлен, потому что он вызвал бы тупик, происходит ошибка.

Таким образом, блокировки намерения не блокируют ничего кроме полных табличных запросов (например, LOCK TABLES ... WRITE). Основная цель IX и IS показать, что кто-то блокирует строку или собирается заблокировать строку в таблице.

Блокировка записей

Блокировка записей это блокировка на индексной записи. Например, SELECT c1 FOR UPDATE FROM t WHERE c1 = 10; препятствует тому, чтобы любая другая транзакция вставила, обновила или удалила строки, где значение t.c1 = 10.

Такие блокировки всегда блокируют индексные записи, даже если таблица определена без индекса. Для таких случаев InnoDB создает кластеризируемый скрытый индекс и использует его. См. раздел 16.8.8.

Блокировки промежутка

Блокировки промежутка это блокировка на промежутке между индексными записями или блокировка на промежутке перед первой или после последней индексной записью. Например, SELECT c1 FOR UPDATE FROM t WHERE c1 BETWEEN 10 and 20; препятствует тому, чтобы другие транзакции вставили значение 15 в столбец t.c1 независимо от того, было ли уже какое-либо такое значение в столбце, потому что промежутки между всеми существующими значениями в диапазоне заблокированы.

Промежуток может охватить одно значение, несколько значений или даже быть пустым.

Блокировки промежутка это часть компромисса между производительностью и параллелизмом и используются в некоторых операционных уровнях изоляции.

Блокировка промежутка не необходима для запросов, которые блокируют строки, используя уникальный индекс, чтобы искать уникальную строку. Это не включает случай, что условие поиска включает только некоторые столбцы уникального многостолбцового индекса, в этом случае блокировка промежутка действительно происходит. Например, если столбец id имеет уникальный индекс, следующий запрос использует только блокировку записи индекса для строки с id 100, и не имеет значения, вставляют ли другие сеансы строки в предыдущий промежуток:

SELECT * FROM child WHERE id = 100;

Если id не индексирован или имеет неуникальный индекс, запрос действительно блокирует предыдущий промежуток.

Также стоит отметить здесь, что противоречивые блокировки могут быть проведены на промежутке различными транзакциями. Например, транзакция A может держать совместно используемую блокировку промежутка (S-блокировка промежутка) на промежутке, в то время как транзакция B держит исключительную блокировку промежутка (X-блокировка промежутка) на том же самом промежутке. Причина, по которой позволены противоречивые блокировки промежутка, состоит в том, что если запись очищена из индекса, блокировки промежутка для записи, которые держат разные транзакции, должны быть слиты.

Блокировки промежутка в InnoDB только мешают другим транзакциям вставить в промежуток. Они не препятствуют тому, чтобы различные транзакции работали с ним как-то иначе. Таким образом, X-блокировка промежутка имеет тот же самый эффект как S-блокировка.

Блокировка промежутка может быть отключена явно. Это происходит, если Вы изменяете операционный уровень изоляции на READ COMMITTED. При этих обстоятельствах блокировка промежутка отключена для поисков и сканирований индексов и используется только для проверки ограничения внешнего ключа и дублирования ключей.

Есть также другие эффекты использования уровня изоляции READ COMMITTED. Блокировки записи для того, чтобы несоответствующие строки были выпущены после того, как MySQL оценил WHERE. Для UPDATE InnoDB делает такое чтение, что это возвращает последнюю переданную версию в MySQL так, чтобы MySQL мог определить, соответствует ли строка WHERE выражению в UPDATE.

Блокировки следующего ключа

Это комбинация блокировки записи на записи индекса и блокировки промежутка перед этой записью.

InnoDB выполняет блокировку на уровне строки таким способом, что когда это ищет или просматривает индекс таблицы, то устанавливает совместно использованные или исключительные блокировки на индексных записях. Таким образом, блокировки на уровне строки фактически блокировки индекса. Блокировка следующего ключа также затрагивает промежуток перед этой записью. Если у одного сеанса есть совместно используемая или исключительная блокировка на записи R в индексе, другой сеанс не может вставить новую индексную запись в промежутке сразу перед R в порядке индекса.

Предположите, что индекс содержит значения 10, 11, 13 и 20. Возможные блокировки для этого индекса покрывают следующие интервалы, где круглая скобка обозначает исключение конечной точки интервала, а квадратная скобка обозначает включение конечной точки:

(минус бесконечность, 10]
(10, 11]
(11, 13]
(13, 20]
(20, бесконечность)

Для последнего интервала это блокирует промежуток выше самого большого значения в индексе и виртуальную запись, имеющую значение выше, чем любое значение фактически в индексе. Такой записи на самом деле нет, таким образом, в действительности, это блокировка только промежутка после самого большого значения индекса.

По умолчанию InnoDB работает на уровне изоляции REPEATABLE READ . В этом случае InnoDB использует такую блокировку для поисков и индексных просмотров, что предотвращает появление призрачных строк (см. раздел 16.5.4).

Блокировки намерения вставки

Блокировки намерения вставки это тип блокировки промежутка, установленной операцией INSERT до вставки строки. Эта блокировка сигнализирует намерение вставить таким способом, что многие транзакции, вставляющие в то же самый промежуток, не должны ждать друг друга, если они не вставляют в ту же самую позицию в пределах промежутка. Предположите, что есть индексные записи со значениями 4 и 7. Отдельные транзакции, которые пытаются вставить значения 5 и 6, соответственно, каждая блокировка промежуток между 4 и 7 с блокировками намерения вставки до получения исключительной блокировки на вставленной строке, но не блокируют друг друга, потому что строки не находятся в противоречии.

Следующий пример демонстрирует транзакцию, берущую блокировку намерения вставки до получения исключительной блокировки на вставленной записи. Пример вовлекает двух клиентов A и B.

Клиент А составляет таблицу, содержащую две записи в индексе (90 и 102) и затем запускает транзакцию, которая помещает исключительную блокировку на записи индекса с ID больше 100. Исключительная блокировка включает блокировку промежутка перед записью 102:

mysql> CREATE TABLE child (id int(11) NOT NULL, PRIMARY KEY(id))
                 ENGINE=InnoDB;
mysql> INSERT INTO child (id) values (90),(102);
mysql> START TRANSACTION;
mysql> SELECT * FROM child WHERE id > 100 FOR UPDATE;
+-----+
| id  |
+-----+
| 102 |
+-----+

Клиент B начинает транзакцию, чтобы вставить отчет в промежуток. Транзакция берет блокировку намерения вставки, в то время как она ждет, чтобы получить исключительную блокировку.

mysql> START TRANSACTION;
mysql> INSERT INTO child (id) VALUES (101);

Чтобы рассмотреть данные о блокировке намерения вставки, выполните SHOW ENGINE INNODB STATUS. Данные, подобные следующим, появляются под заголовком TRANSACTIONS:

mysql> SHOW ENGINE INNODB STATUS\G
...
SHOW ENGINE INNODB STATUS
---TRANSACTION 8731, ACTIVE 7 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 3, OS thread handle 0x7f996beac700, query id 30 localhost root update
INSERT INTO child (id) VALUES (101)
------- TRX HAS BEEN WAITING 7 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 31 page no 3 n bits 72 index `PRIMARY` of table `test`.`child`
trx id 8731 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 80000066; ascf;;
 1: len 6; hex 000000002215; asc " ;;
 2: len 7; hex 9000000172011c; asc r  ;;...

Блокировка AUTO-INC

Блокировка AUTO-INC это специальная блокировка на уровне таблицы, взятая транзакциями, вставляющими в таблицы со столбцами AUTO_INCREMENT. В самом простом случае, если одна транзакция вставляет значения в таблицу, любые другие транзакции должны ждать, чтобы сделать их собственные вставки в эту таблицу так, чтобы строки, вставленные первой транзакцией, получили последовательные значения первичного ключа.

Параметр конфигурации innodb_autoinc_lock_mode управляет алгоритмом, используемым для блокировки автоинкремента. Это позволяет Вам выбирать, как балансировать между предсказуемыми последовательностями значений автоинкремента и максимальным параллелизмом для операций вставки.

Подробности в разделе 16.8.5.

Блокировка предиката для пространственного индекса

InnoDB поддерживает индексацию столбцов с пространственными данными (см. раздел 12.5.3.5 ).

Чтобы обработать блокировку для вовлечения операций с индексами SPATIAL, блокировка следующего ключа не работает хорошо, чтобы поддержать уровни изоляции REPEATABLE READ или SERIALIZABLE. В многомерных данных нет никакого абсолютного понятия упорядочивания, таким образом, не ясно, что является следующим ключом.

Чтобы обеспечить поддержку уровней изоляции для таблиц с индексами SPATIAL, InnoDB применяет блокировки предиката. Индекс SPATIAL содержит минимальный ограничительный прямоугольник (MBR) значения, таким образом, InnoDB проводит в жизнь последовательное чтение на индексе, устанавливая предикат, на значении MBR, используемом для запроса. Другие транзакции не могут вставить или изменить строку, которая соответствовала бы условию запроса.

16.5.2. Транзакционная модель InnoDB

В транзакционной модели InnoDB цель состоит в том, чтобы объединить лучшие свойства мультиверсионной базы данных с традиционной двухфазовой блокировкой. InnoDB выполняет блокировку на уровне строки и выполняет запросы как последовательные чтения без блокировки по умолчанию в стиле Oracle. Информация о блокировке в InnoDB сохранена пространственно-эффективно так, чтобы эскалация блокировки не была необходима. Как правило, нескольким пользователям разрешают блокировать каждую строку таблицы InnoDB или любое случайное подмножество строк без истощения памяти InnoDB.

16.5.2.1. Операционные уровни изоляции

Операционная изоляция это одна из основ обработки базы данных. Изоляция это I в ACID, уровень изоляции это установка, которая точно настраивает баланс между работой и надежностью, последовательностью и воспроизводимостью результатов, когда многократные транзакции производят изменения и выполняют запросы в то же самое время.

InnoDB реализует все четыре операционных уровня изоляции, которые описаны стандартом SQL:1992: READ UNCOMMITTED , READ COMMITTED , REPEATABLE READ и SERIALIZABLE. По умолчанию используется REPEATABLE READ .

Пользователь может изменить уровень изоляции для единственного сеанса или для всех последующих соединений командой SET TRANSACTION. Чтобы установить уровень изоляции по умолчанию сервера для всех соединений, используйте параметр --transaction-isolation. Для получения дальнейшей информации об уровнях изоляции и устанавливающем уровень синтаксисе см. раздел 14.3.6.

InnoDB реализует каждый из операционных уровней изоляции, описанных здесь, используя различные стратегии блокировки. Вы можете провести в жизнь высокую степень последовательности с уровнем по умолчанию REPEATABLE READ , для операций на решающих данных, где совместимость с ACID принципиальна. Или Вы можете расслабить правила последовательности с READ COMMITTED или READ UNCOMMITTED в ситуациях, где точная последовательность и повторимые результаты менее важны, чем уменьшение количества издержек блокировки. SERIALIZABLE проводит в жизнь еще более строгие правила, чем REPEATABLE READ , и используется, главным образом, в специализированных ситуациях, таких как транзакции XA и для того, чтобы расследовать проблемы с параллелизмом и тупиками.

Следующий список описывает, как MySQL поддерживает различные операционные уровни. Список идет от обычно используемого уровня до наименее используемого.

16.5.2.2. autocommit, Commit и Rollback

В InnoDB вся пользовательская деятельность происходит в транзакции. Если режим autocommit включен, каждый запрос SQL формирует единственную транзакцию самостоятельно. По умолчанию MySQL запускает сеанс для каждого нового соединения с включенным autocommit, таким образом, MySQL делает передачу после каждого запроса SQL, если запрос не возвращал ошибку. См. раздел 16.20.4.

Сеанс, который имеет включенную опцию autocommit, может выполнить транзакцию из многих запросов, запуская это с явной командой START TRANSACTION или BEGIN и завершая COMMIT или ROLLBACK. См. раздел 14.3.1.

Если autocommit выключен в пределах сеанса с помощью SET autocommit = 0, у сеанса всегда есть открытая транзакция. COMMIT или ROLLBACK заканчивает текущую транзакцию, и новая запускается.

Если сеанс, который имеет выключенный autocommit завершается, явно не передавая заключительную транзакцию, MySQL отменяет эту транзакцию до прежнего состояния.

Некоторые запросы неявно заканчивают транзакцию, как будто Вы сделали a COMMIT. См. раздел 14.3.3.

COMMIT означает, что изменения, сделанные в текущей транзакции, делаются постоянными и становятся видимыми другим сеансам. ROLLBACK отменяет все модификации, сделанные текущей транзакцией. COMMIT и ROLLBACK снимают все блокировки, которые были установлены во время текущей транзакции.

Группировка операций DML с транзакциями

По умолчанию соединение с сервером MySQL начинается с включенным режимом autocommit, который автоматически передает каждый запрос SQL, когда Вы выполняете это. Этот режим работы мог бы быть незнакомым, если у Вас есть опыт работы с другими системами базы данных, где общепринятой практикой является последовательность запросов DML и передача или отмена их все вместе.

Чтобы использовать транзакцию из многих запросов, выключите режим командой SET autocommit = 0 и заканчивайте каждую транзакцию командой COMMIT или ROLLBACK. Чтобы это сделать при включенном autocommit, начинайте каждую транзакцию с START TRANSACTION и заканчивайте COMMIT или ROLLBACK. Следующий пример показывает две транзакции. Первая передана, вторая отменена.

shell> mysql test
mysql> CREATE TABLE customer (a INT, b CHAR (20), INDEX (a));
Query OK, 0 rows affected (0.00 sec)
mysql> -- Do a transaction with autocommit turned on.
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO customer VALUES (10, 'Heikki');
Query OK, 1 row affected (0.00 sec)
mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)
mysql> -- Do another transaction with autocommit turned off.
mysql> SET autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO customer VALUES (15, 'John');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO customer VALUES (20, 'Paul');
Query OK, 1 row affected (0.00 sec)
mysql> DELETE FROM customer WHERE b = 'Heikki';
Query OK, 1 row affected (0.00 sec)
mysql> -- Now we undo those last 2 inserts and the delete.
mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM customer;
+----+--------+
| a  | b      |
+----+--------+
| 10 | Heikki |
+----+--------+
1 row in set (0.00 sec)
mysql>
Транзакции на клиентских языках

В таких API, как PHP, Perl DBI, JDBC, ODBC или обычный интерфейс C Вы можете послать команду управления транзакцией серверу как строку точно так же, как любые другие запросы SQL, такие как SELECT или INSERT. Некоторые API также предлагает отдельные специальные функции или методы.

16.5.2.3. Последовательные чтения без блокировки

Последовательное чтение означает, что InnoDB использует мультиверсии, чтобы представить запросу снимок базы данных в момент времени. Запрос видит изменения, произведенные транзакциями, которые передали перед тем моментом времени, но никаких изменений, произведенных позже или нейтральными транзакциями. Исключение: запрос видит изменения, произведенные более ранними запросами в пределах той же самой транзакции. Это исключение вызывает следующую аномалию: если Вы обновляете некоторые строки в таблице, SELECT видит последнюю версию обновленных строк, но мог бы также видеть более старые версии любых строк. Если другие сеансы одновременно обновляют ту же самую таблицу, аномалия означает, что Вы могли бы видеть таблицу в статусе, который никогда не существовал в базе данных.

Если операционный уровень изоляции REPEATABLE READ (по умолчанию), все последовательные чтения в пределах той же самой транзакции читают снимок, установленный первым таким чтением в этой транзакции. Вы можете получить более новый снимок для своих запросов, передавая текущую транзакцию и выдавая новые запросы.

На уровне READ COMMITTED каждое последовательное чтение в пределах транзакции устанавливает и читает свой собственный новый снимок.

Последовательное чтение это режим по умолчанию, в котором InnoDB обрабатывает запросы SELECT на уровнях READ COMMITTED и REPEATABLE READ . Последовательное чтение не устанавливает блокировок на таблицы, к которым оно получает доступ, и поэтому другие сеансы свободны изменить те таблицы в то же самое время, когда последовательное чтение выполняется на таблице.

Предположите, что Вы работаете на уровне REPEATABLE READ . Когда Вы выпускаете последовательное чтение (то есть, одиночный SELECT), InnoDB дает Вашей транзакции точку времени, согласно которой Ваш запрос видит базу данных. Если другая транзакция удаляет строку и передает после того, как Ваша точка была назначена, Вы не видите строку как удаленную. Вставки и обновления обработаны так же.

Снимок базы данных относится к SELECT в пределах транзакции, не обязательно к запросам DML. Если Вы вставляете или изменяете некоторые строки и затем передаете транзакцию, запросы DELETE или UPDATE от другой параллельной транзакции REPEATABLE READ могут затронуть те переданные строки, даже при том, что сеанс не мог запросить их. Если транзакция действительно обновляет или удаляет строки, переданные иной транзакцией, те изменения действительно становятся видимыми к текущей транзакции. Например, Вы могли бы столкнуться с такой ситуацией:

SELECT COUNT(c1) FROM t1 WHERE c1 = 'xyz';
-- Returns 0: no rows match.
DELETE FROM t1 WHERE c1 = 'xyz';
-- Deletes several rows recently committed by other transaction.

SELECT COUNT(c2) FROM t1 WHERE c2 = 'abc';
-- Returns 0: no rows match.
UPDATE t1 SET c2 = 'cba' WHERE c2 = 'abc';
-- Affects 10 rows: another txn just committed 10 rows with 'abc' values.
SELECT COUNT(c2) FROM t1 WHERE c2 = 'cba';
-- Returns 10: this txn can now see the rows it just updated.

Вы можете обновить точку времени, передавая Вашу транзакцию и затем делая другой запрос SELECT или START TRANSACTION WITH CONSISTENT SNAPSHOT .

В следующем примере сеанс A видит строку, вставленную B, только когда B передал вставку, а A передал также, чтобы точка времени обновилась.

      Сеанс A            Сеанс B

 SET autocommit=0;  SET autocommit=0;
time
| SELECT * FROM t;
| empty set
|   INSERT INTO t VALUES (1, 2);
|
v SELECT * FROM t;
  empty set
COMMIT;

  SELECT * FROM t;
  empty set

  COMMIT;

  SELECT * FROM t;
  ---------------------
  | 1    | 2          |
  ---------------------

Если Вы хотите видеть свежее состояние базы данных, используйте любой уровень изоляции READ COMMITTED или блокировку чтения:

SELECT * FROM t LOCK IN SHARE MODE;

На уровне READ COMMITTED каждое последовательное чтение в пределах транзакции устанавливает и читает свой собственный новый снимок. С LOCK IN SHARE MODE блокировка чтения происходит вместо этого: SELECT блокирует до транзакции, содержащей самые новые концы строк (см. раздел 16.5.2.4).

Последовательное чтение не работает по определенным запросам DDL:

Тип чтения изменяется для выбора в запросах INSERT INTO ... SELECT, UPDATE ... (SELECT) и CREATE TABLE ... SELECT, которые не определяют FOR UPDATE или LOCK IN SHARE MODE:

16.5.2.4. Блокировка чтений

Если Вы запрашиваете данные и затем вставляете или обновляете связанные данные в пределах той же самой транзакции, запрос SELECT не дает достаточную защиту. Другие транзакции могут обновить или удалить те же самые строки, которые Вы только что запросили. InnoDB понимает два типа блокировки чтений, которые предлагают дополнительную безопасность:

Эти пункты прежде всего полезны, имея дело со структурированными деревом или структурированными данными графика в единственной таблице или в разделении на несколько таблиц. Вы пересекаете края или ответвления дерева от одного места до другого, резервируя право возвратиться и изменить любой из этих указателей.

Все блокировки, установленные LOCK IN SHARE MODE и FOR UPDATE выпущены, когда транзакция передана или отменена.

Блокировка строк для использования обновления SELECT FOR UPDATE применяется, когда autocommit отключен любым способом (START TRANSACTION или установкой autocommit в 0). Если autocommit включен, строки, соответствующие спецификации, не заблокированы.

Примеры использования

Предположите, что Вы хотите вставить новую строку в таблицу child и удостоверьтесь, что дочерняя строка имеет родительскую строку в таблице parent. Ваш код программы может гарантировать ссылочную целостность всюду по этой последовательности операций.

Во-первых, используйте последовательное чтение, чтобы запросить таблицу PARENT и проверьте, что родительская строка существует. Можете Вы безопасно вставлять дочернюю строку в таблицу CHILD? Нет, потому что некоторый другой сеанс мог удалить родительскую строку в момент между Вашими SELECT и INSERT.

Чтобы избежать этой потенциальной проблемы, используйте SELECT с LOCK IN SHARE MODE:

SELECT * FROM parent WHERE NAME = 'Jones' LOCK IN SHARE MODE;

После LOCK IN SHARE MODE запрос возвращает 'Jones', который Вы можете безопасно добавить в дочернюю запись в таблице CHILD и передать транзакцию. Любая транзакция, которая пытается приобрести исключительную блокировку в применимой строке в таблице PARENT ждет, пока Вы не закончите, то есть, пока данные во всех таблицах не находятся в последовательном статусе.

Для другого примера, рассмотрите область счетчика целого числа в таблице таблице CHILD_CODES, используемую, чтобы назначить уникальный идентификатор каждому дочернему элементу в таблице CHILD. Не используйте последовательное чтение или совместно используемое чтение, чтобы считать текущее значение счетчика, потому что два пользователя базы данных могли видеть то же самое значение счетчика, и происходит ошибка дублирования ключа, если две транзакции пытаются добавить строки с тем же самым идентификатором к CHILD.

Здесь LOCK IN SHARE MODE плохое решение, потому что, если два пользователя читают счетчик в то же самое время, по крайней мере один из них заканчивает в тупике, когда пытается обновить счетчик.

Чтобы осуществить чтение и постепенное увеличение счетчика, сначала выполните блокировку чтения счетчика через FOR UPDATE, а затем увеличьте счетчик. Например:

SELECT counter_field FROM child_codes FOR UPDATE;
UPDATE child_codes SET counter_field = counter_field + 1;

SELECT ... FOR UPDATE читает последние доступные данные, устанавливая исключительные блокировки на каждой строке, которую читает. Таким образом, это устанавливает те же самые блокировки, какие ищущий UPDATE установил бы на строках.

Предыдущее описание просто пример того, как работает SELECT ... FOR UPDATE. В MySQL определенная задача производства уникального идентификатора фактически может быть выполнена, используя только единственный доступ к таблице:

UPDATE child_codes SET counter_field = LAST_INSERT_ID(counter_field + 1);
SELECT LAST_INSERT_ID();

SELECT просто получает информацию об идентификаторе (определенном для текущего соединения). Это не получает доступ ни к какой таблице.

16.5.3. Установка блокировок различными запросами SQL в InnoDB

Блокировка чтения, UPDATE или DELETE вообще устанавливают блокировки записи на каждой записи индекса, которая просмотрена в обработке запроса SQL. Не имеет значения, есть ли условие WHERE в запросе, которое исключило бы строку. InnoDB не помнит точное выражение WHERE, а только знает, которые индексные диапазоны, были просмотрены. Блокировки обычно следующего ключа, которые также блокируют промежуток сразу перед записью. Однако, блокировка промежутка может быть отключена явно, что заставляет блокировку следующего ключа не использоваться. Подробности в разделе 16.5.1. Операционный уровень изоляции также может затронуть, какие блокировки установлены, см. раздел 14.3.6.

Если вторичный индекс используется в поиске, и блокировки индексной записи, которые будут установлены, исключительны, InnoDB также получает соответствующие записи кластеризируемого индекса и ставит на них блокировки.

Различия между совместно используемыми и исключительными блокировками описаны в разделе 16.5.1.

Если Вы не имеете индекса, подходящего для Вашего запроса, и MySQL должен просмотреть всю таблицу, чтобы обработать запрос, каждая строка таблицы становится заблокированной, что в свою очередь блокирует все вставки другими пользователями в таблицу. Важно создать хороший индекс так, чтобы Ваши запросы не просматривали слишком много строк.

Для SELECT ... FOR UPDATE или SELECT ... LOCK IN SHARE MODE блокировки приобретены для просмотренные строки и, как ожидают, будут выпущены для строк, которые не имеют право на включение в набор результатов (например, если они не соответствуют критериям, поданным в WHERE). Однако, в некоторых случаях, строки нельзя было бы немедленно разблокировать, потому что отношения между строкой результата и ее первоисточником потеряны во время выполнения запроса. Например, в UNION просмотренные (и заблокированные) строки могли бы быть вставлены во временную таблицу перед оценкой, имеют ли они право на набор результатов. При этом потеряны отношения строк во временной таблице к строкам в оригинальной таблице, и последние строки не разблокируют до конца выполнения запроса.

InnoDB устанавливает типы блокировок следующим образом.

16.5.4. Строки-призраки

Так называемая призрачная проблема происходит в пределах транзакции, когда тот же самый запрос производит различные наборы строк в разное время. Например, если SELECT выполнен дважды, но возвращает строку во второй раз, которая не была возвращена в первый раз, строка призрачная.

Предположите, что есть индекс на столбце id таблицы child и что Вы хотите считать и заблокировать все строки из таблицы, имеющей значение идентификатора, больше 100, с намерением обновить некоторый столбец в выбранных строках позже:

SELECT * FROM child WHERE id > 100 FOR UPDATE;

Запрос просматривает индекс с первой записи, где id больше 100. Пусть в таблице строки с id 90 и 102. Если блокировки на записях индекса в просмотренном диапазоне не запрещают вставки в промежутки (в этом случае, промежуток между 90 и 102), другой сеанс может вставить новую строку в таблицу с id 101. Если Вы должны были выполнить тот же самый SELECT в пределах той же самой транзакции Вы видели бы новую строку с id 101 (призрак) в наборе результатов, возвращенном запросом. Если мы расцениваем ряд строк как элемент данных, новый призрачный дочерний элемент нарушил бы принцип изоляции транзакций, что транзакция должна быть в состоянии работать так, чтобы данные, которые она прочитала, не изменились во время транзакции.

Чтобы избегать таких ситуаций InnoDB использует алгоритм, названный блокировка следующего ключа, который комбинирует блокировку индекса строки с блокировкой промежутка. InnoDB выполняет блокировку на уровне строки таким способом, что когда это ищет или просматривает индекс таблицы, это устанавливает совместно использованные или исключительные блокировки на индексных записях, с которыми сталкивается. Таким образом, блокировки на уровне строки фактически блокировки индексных записей. Кроме того, блокировка следующего ключа на записи индекса также затрагивает промежуток перед этой записью. Таким образом, блокировка следующего ключа это блокировка индексной записи и промежутка, предшествующего ей. Если у одного сеанса есть совместно используемая или исключительная блокировка на записи R в индексе, другой сеанс не может вставить новую запись в промежутке немедленно перед R в порядке индекса.

Когда InnoDB просматривает индекс, это может также заблокировать промежуток после последней записи в индексе. Это происходит в предыдущем примере: чтобы предотвратить любую вставку в таблицу, где id больше 100, блокировки, установленные InnoDB, включают блокировку на промежутке после id 102.

Вы можете использовать блокировку следующего ключа, чтобы осуществить проверку уникальности в Вашем приложении: если Вы читаете свои данные в режиме совместного доступа и не видите дубликат строки, которую собираетесь вставить, то можете безопасно вставить свою строку и знать, что блокировка следующего ключа, установленная на преемнике Вашей строки во время чтения, предотвращает вставку дубликата для Вашей строки. Таким образом, блокировка следующего ключа позволяет Вам блокировать небытие чего-то в Вашей таблице.

Блокировка промежутка может быть отключена как обсуждено в разделе 16.5.1. Это может вызвать призрачные проблемы, потому что другие сеансы могут вставить новые строки в промежутки, когда блокировка промежутка отключена.

16.5.5. Тупики в InnoDB

Тупик это ситуация, где различные транзакции не способны продолжить работу потому, что каждый держит блокировку, нужную другой. Поскольку обе транзакции ждут ресурса, ни одна никогда не будет выпускать блокировки, которые держит.

Тупик может произойти, когда транзакции блокируют строки в многих таблицах (через такие запросы, как UPDATE или SELECT ... FOR UPDATE), но в противоположном порядке. Тупик может также произойти, когда такие запросы блокируют диапазоны, индексных записей и промежутки с каждой транзакцией, приобретающей некоторые блокировки, но не другие из-за проблемы синхронизацией. Для примера тупика см. раздел 16.5.5.1.

Чтобы уменьшить возможность тупиков, используйте транзакции, а не LOCK TABLES, сохраните транзакции, которые вставляют или обновляют данные, достаточно маленькими, чтобы они не оставались открытыми в течение долгих промежутков времени, когда различные транзакции обновляют многие таблицы или большие спектры строк, используйте тот же самый порядок операций (таких, как SELECT ... FOR UPDATE) в каждой транзакции, создайте индексы на столбцах, используемых в SELECT ... FOR UPDATE и UPDATE ... WHERE. Возможность тупиков не затронута уровнем изоляции, потому что уровень изоляции изменяет поведение операций чтения, в то время как тупики происходят из-за записи. Для получения дополнительной информации об уходе от условий тупика см. раздел 16.5.5.3 .

Когда обнаружение тупика включено (значение по умолчанию), и тупик действительно происходит, InnoDB обнаруживает условие и откатывает одну из транзакций до прежнего уровня. Если обнаружение тупика отключено, используя опцию innodb_deadlock_detect, InnoDB полагается на настройку innodb_lock_wait_timeout, чтобы откатить транзакции до прежнего уровня в случае тупика. Таким образом, даже если Ваша логика приложения правильна, Вы должны все еще обработать случай, где транзакция должна быть повторена. Чтобы увидеть последний тупик в пользовательской транзакции InnoDB, используйте SHOW ENGINE INNODB STATUS. Если частые тупики выделяют проблему с операционной структурой или обработкой ошибки приложения, работайте с опцией innodb_print_all_deadlocks, чтобы напечатать информацию обо всех тупиках в журнал ошибок mysqld . Для получения дополнительной информации о том, как тупики автоматически обнаружены и обработаны см. раздел 16.5.5.2.

16.5.5.1. Пример тупика в InnoDB

Следующий пример иллюстрирует, как ошибка может произойти, когда запрос блокировки вызвал бы тупик. Пример вовлекает двух клиентов A и B.

Клиент А составляет таблицу, содержащую одну строку, а затем начинает транзакцию. В пределах транзакции A получает блокировку S на строке, выбирая это в режиме общего доступа:

mysql> CREATE TABLE t (i INT) ENGINE = InnoDB;
Query OK, 0 rows affected (1.07 sec)

mysql> INSERT INTO t (i) VALUES(1);
Query OK, 1 row affected (0.09 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM t WHERE i = 1 LOCK IN SHARE MODE;
+---+
| i |
+---+
| 1 |
+---+

Затем клиент Б начинает транзакцию и пытается удалить строку из таблицы:

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> DELETE FROM t WHERE i = 1;

Удаление требует блокировки X. Блокировку нельзя предоставить, потому что это является несовместимым с S, которую держит клиент А, таким образом, запрос идет в очередь запросов блокировки для строки, что блокирует клиента B.

Наконец, клиент также пытается удалить строку из таблицы:

mysql> DELETE FROM t WHERE i = 1;
ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction

Тупик происходит здесь потому, что клиент A требует блокировку X, чтобы удалить строку. Однако, тот запрос блокировки нельзя предоставить, потому что у клиента B уже есть запрос на X, и он ждет, пока клиент A выпустит блокировку S. Так они будут ждать друг друга вечно. В результате InnoDB производит ошибку для одного из клиентов и выпускает все его блокировки. Клиент возвращает эту ошибку:

ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction

Здесь можно предоставить запрос блокировки для другого клиента, и это удаляет строку из таблицы.

16.5.5.2. Обнаружение тупика и отмена

Когда обнаружение тупика включено (по умолчанию), InnoDB автоматически обнаруживает транзакционные тупики и откатывает до прежнего уровня транзакцию или транзакции, чтобы найти выход из тупика. InnoDB старается выбрать маленькие транзакции, чтобы откатить, где размер транзакции определен числом затронутых ей строк.

InnoDB знает о табличных блокировках, если innodb_table_locks = 1 (по умолчанию) и autocommit = 0, и уровень MySQL выше этого знает о блокировках на уровне строки. Иначе InnoDB не может обнаружить тупики, где табличная блокировка, установленная MySQL LOCK TABLES или блокировка, установленная механизмом хранения кроме InnoDB, вовлечена. Решите эти ситуации, устанавливая значение innodb_lock_wait_timeout.

Когда InnoDB выполняет полную отмену транзакции, все блокировки, установленные транзакцией, выпущены. Однако, если только единственный запрос SQL откатывается до прежнего уровня в результате ошибки, некоторые из блокировок, установленных запросом, могут быть сохранены. Это происходит потому, что InnoDB хранит блокировки строк таким образом, что не может знать, какая блокировка была установлена которым запросом.

Если SELECT вызывает сохраненную функцию в транзакции, и запрос в пределах функции терпит неудачу, то запрос откатывается. Кроме того, если ROLLBACK выполнен после этого, откатывается вся транзакция.

Если раздел LATEST DETECTED DEADLOCK в InnoDB Monitor включает сообщение TOO DEEP OR LONG SEARCH IN THE LOCK TABLE WAITS-FOR GRAPH, WE WILL ROLL BACK FOLLOWING TRANSACTION, это указывает, что число транзакций в ожидании достигло предела 200. Это обработано как тупик и транзакция, пытающаяся встать в очередь откатывается до прежнего уровня. Та же самая ошибка может также произойти, если поток блокировки должен смотреть больше, чем на 1000000 блокировок, принадлежавших транзакциям в списке ожидания.

Для методов, чтобы организовать операции базы данных, чтобы избежать тупиков, см. раздел 16.5.5.

Отключение обнаружения тупика

На высоконагруженных системах обнаружение тупика может вызвать замедление, когда многочисленные потоки ждут той же самой блокировки. Время от времени может быть более эффективно отключить обнаружение тупика и положиться на опцию innodb_lock_wait_timeout для операционной отмены, когда тупик происходит. Обнаружение тупика может быть отключено, используя опцию innodb_deadlock_detect.

16.5.5.3. Как минимизировать и обработать тупики

Этот раздел основывается на концептуальной информации о тупиках в разделе 16.5.5.2. Это объясняет, как организовать операции базы данных, чтобы минимизировать тупики и последующую обработку ошибок, требуемую в приложениях.

Тупики это классическая проблема в транзакционных базах данных, но они не опасны, если не являются настолько частыми, что Вы не можете выполнить определенные транзакции вообще. Обычно Вы должны написать свои приложения так, чтобы они были всегда подготовлены перезапустить транзакцию, если она отменена из-за тупика.

InnoDB использует автоматическую блокировку на уровне строки. Вы можете получить тупики даже в случае транзакций, которые только вставляют или удаляют единственную строку. Это так, потому что эти операции не действительно атомарные, они автоматически устанавливают блокировки (возможно, несколько) индексных записей строки, вставленной или удаленной.

Вы можете справиться с тупиками и уменьшить вероятность их возникновения следующими методами:

16.6. Конфигурация InnoDB

Этот раздел предоставляет информацию о конфигурации и процедуры для инициализации и запуска InnoDB, а также различные компоненты и особенности механизма хранения InnoDB. Для информации об оптимизации операций базы данных для таблиц InnoDB см. раздел 9.5 .

16.6.1. Конфигурация запуска InnoDB

Первые решения о настройке InnoDB вовлекают конфигурацию файлов с данными, файлов системного журнала, размера страницы и буферов памяти. Рекомендуется, чтобы Вы определили файл с данными, файл системного журнала и конфигурацию размера страницы прежде, чем создать экземпляр InnoDB. Изменение файла с данными или конфигурации файла системного журнала после запуска InnoDB может вовлечь нетривиальную процедуру, и размер страницы может быть определен только когда InnoDB начально инициализирован.

В дополнение к этим темам этот раздел предоставляет информацию об опциях в конфигурационном файле, рассматривая информацию об инициализации и важные соображения о хранении.

Определение опций в конфигурационном файле MySQL

Поскольку MySQL использует файл с данными, файл системного журнала и настройки конфигурации размера страницы, чтобы инициализировать InnoDB, рекомендуется, чтобы Вы определили эти настройки в конфигурационном файле, который MySQL читает при запуске, до инициализации InnoDB впервые. InnoDB инициализирован, когда сервер MySQL запущен, и первая инициализация InnoDB обычно происходит в первый раз, когда Вы запускаете сервер MySQL.

Вы можете поместить опции InnoDB в группу [mysqld] любого файла опции, который читает Ваш сервер, когда запускается. Местоположения файлов опции MySQL описаны в разделе 5.2.6.

Чтобы удостовериться, что mysqld читает опции только из определенного файла (и mysqld-auto.cnf), используйте --defaults-file как первую опцию в командной строке, запуская сервер:

mysqld --defaults-file=path_to_configuration_file

Просмотр информации об инициализации InnoDB

Чтобы видеть сведения об инициализации InnoDB во время запуска, запустите mysqld из командной строки. Когда mysqld запущен из командной строки, информация об инициализации выведена на консоль.

Например, в Windows, если mysqld расположен в C:\Program Files\MySQL\MySQL Server 8.0\bin, запустите MySQL так:

C:\> "C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqld" --console

В Unix-системах mysqld расположен в подкаталоге bin установки MySQL:

sell> bin/mysqld --user=mysql &

Если Вы не посылаете вывод сервера на консоль, проверьте журнал ошибок после запуска, чтобы видеть информацию об инициализации InnoDB, напечатанную во время процесса запуска.

Для информации о запуске MySQL, используя другие методы, см. раздел 2.9.5.

Важные соображения о хранении

Рассмотрите следующие связанные с хранением соображения перед продолжением Вашей конфигурации.

Системная конфигурация файла с данными табличного пространства

Системные файлы с данными табличного пространства сконфигурированы, используя опции innodb_data_file_path и innodb_data_home_dir .

innodb_data_file_path используется, чтобы сконфигурировать системные файлы с данными табличного пространства. Значение innodb_data_file_path должно быть списком из одной или более спецификаций файла с данными. Если Вы называете больше чем один файл с данными, отделяете их точкой с запятой (;):

innodb_data_file_path=datafile_spec1[;datafile_spec2]...

Например, следующая установка явно создает минимальное системное табличное пространство:

[mysqld]
innodb_data_file_path=ibdata1:12M:autoextend

Эта установка конфигурирует единственный файл с данными 12 МБ ibdata1. Никакое местоположение для файла не задано, так что по умолчанию, InnoDB создает это в каталоге данных MySQL.

Размеры определены, используя буквы суффикса K, M или G, чтобы указать на KB, MB или GB.

Табличное пространство, содержащее файл с данными 50 МБ фиксированного размера с именем ibdata1 и 50MB автомасштабируемый файл с именем ibdata2 в каталоге данных может быть сконфигурирован как это:

[mysqld]
innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend

Полный синтаксис для спецификации файла с данными включает имя файла, его размер и несколько дополнительных признаков:

file_name:file_size[:autoextend[:max:max_file_size]]

autoextend и max могут использоваться только для последнего файла с данными в строке innodb_data_file_path .

Если Вы определяете autoextend для последнего файла с данными, InnoDB расширяет файл с данными, если он исчерпывает свободное пространство в табличном пространстве. Инкремент составляет 64 МБ за один раз по умолчанию. Чтобы изменить инкремент, измените значение innodb_autoextend_increment.

Если диск становится полным, Вы могли бы добавить другой файл с данными на другом диске. Для инструкций реконфигурирования табличного пространства см. раздел 16.7.1.

InnoDB не знает о максимальном размере файла в файловой системе, так что следует быть осторожным на файловых системах, где максимальный размер файла маленькое значение, такое как 2GB. Чтобы определить максимальный размер для файла с данными, используйте параметр max после autoextend. Используйте max только в случаях, где ограничение дискового использования имеет жизненную важность, потому что превышение максимального размера вызывает фатальную ошибку, возможно, включая катастрофический отказ. Следующяя конфигурация позволяет ibdata1 расти до 500MB:

[mysqld]
innodb_data_file_path=ibdata1:12M:autoextend:max:500M

InnoDB создает файлы табличного пространства в каталоге данных MySQL по умолчанию (datadir ). Чтобы определить местоположение явно, используйте опцию innodb_data_home_dir . Например, чтобы создать два файла ibdata1 и ibdata2 в /myibdata:

[mysqld]
innodb_data_home_dir = /myibdata
innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend

InnoDB не создает каталоги, так что удостоверьтесь, что каталог /myibdata существует прежде, чем Вы запустите сервер. Используйте Unix или DOS mkdir, чтобы создать любые необходимые каталоги.

Удостоверьтесь, что у сервера MySQL есть надлежащие права доступа, чтобы создать файлы в каталоге данных. Более широко, у сервера должны быть права доступа в любом каталоге, где это должно создать файлы с данными.

InnoDB формирует путь к каталогу для каждого файла с данными, дословно добавляя значение innodb_data_home_dir к имени файла с данными, добавляя разделитель пути (наклонная черта или наклонная черта влево) между значениями в случае необходимости. Если опция innodb_data_home_dir не определена в my.cnf вообще, значение по умолчанию ./, что означает каталог данных MySQL. Сервер MySQL изменяет свой текущий рабочий каталог на свой каталог данных, когда он начинает выполняться.

Если Вы определяете innodb_data_home_dir как пустую строку, Вы можете определить абсолютные пути для файлов с данными, перечисленных в innodb_data_file_path . Следующий пример эквивалентен предыдущему:

[mysqld]
innodb_data_home_dir =
innodb_data_file_path=/ibdata/ibdata1:50M;/ibdata/ibdata2:50M:autoextend

Конфигурация файла системного журнала InnoDB

По умолчанию InnoDB создает два файла системного журнала по 48 МБ в каталоге данных MySQL (datadir) с именами ib_logfile0 и ib_logfile1.

Следующие опции могут использоваться, чтобы изменить конфигурацию по умолчанию:

Конфигурация табличного пространства отмены InnoDB

По умолчанию журналы отмены это часть системного табличного пространства. Однако, Вы можете хотеть хранить их в одном или более отдельных табличных пространств отмены, как правило, на ином устройстве хранения данных.

Опция innodb_undo_directory определяет путь, где InnoDB создает отдельные табличные пространства для журналов отмены. Эта опция как правило используется в соединении с innodb_undo_logs и innodb_undo_tablespaces, которые определяют дисковое расположение журналов отмены вне системного табличного пространства.

Подробности в разделе 16.7.7 .

Конфигурация временного табличного пространства InnoDB

По умолчанию InnoDB создает единственный автомасштабируемый временный файл с данными табличного пространства ibtmp1 в каталоге данных MySQL (datadir ) это немного больше, чем 12 МБ. Конфигурация по умолчанию может быть изменена при запуске, используя innodb_temp_data_file_path.

innodb_temp_data_file_path определяет путь, имя файла и размер файла для временных файлов с данными табличного пространства. Полный путь к каталогу для файла сформирован, связывая innodb_data_home_dir с путем, определенным innodb_temp_data_file_path. Размер файла определен в KB, MB или GB (1024MB), добавляя K, M или G к значению размера. Сумма размеров файлов должна быть немного больше, чем 12 МБ.

Конфигурация размера страницы InnoDB

innodb_page_size определяет размер страницы для всех табличных пространств InnoDB. Это значение установлено, когда экземпляр создается и остается постоянным позже. Допустимые значения составляют 64k, 32k, 16k (по умолчанию), 8k и 4k. Альтернативно, Вы можете определить размер страницы в байтах (65536, 32768, 16384, 8192, 4096).

Размер страницы по умолчанию 16k является подходящим для широкого диапазона рабочих нагрузок, особенно для запросов, вовлекающих сканирование таблицы и операции DML, вовлекающие оптовые обновления. Меньшие размеры страницы могли бы быть более эффективными для рабочих нагрузок OLTP, вовлекающих, многие маленькие записи, где может быть проблемой, когда единственная страница содержит много строк. Меньшие страницы могли бы также быть эффективными с устройствами хранения данных SSD, которые, как правило, используют маленькие размеры блока. Задание размера страницы близким к размеру блока устройства хранения данных минимизирует количество неизменных данных, которые переписаны на диск.

Конфигурация памяти InnoDB

MySQL выделяет память различным кэшам и буферам, чтобы улучшить исполнение операций базы данных. Выделяя память для InnoDB, всегда считайте память требуемую операционной системой, память, выделенную другим приложениям, и память для других буферов MySQL и кэшей. Например, если Вы используете таблицы MyISAM, считайте объем памяти, выделенный для ключевого буфера (key_buffer_size ). Для краткого обзора буферов MySQL и кэшей см. раздел 9.12.3.1.

Буферы для InnoDB сконфигурированы, используя следующие параметры:

В 32-bit GNU/Linux x86 не стоит устанавливать использование памяти слишком большим. glibc может разрешить куче процесса расти по стекам потока, который разрушает Ваш сервер. Это рискованно, если память, выделенная процессу mysqld для глобальных и поточных буферов и кэшей, близка к или превышает 2GB.

Формула, подобная следующей, которая вычисляет глобальное и поточное распределение памяти для MySQL, может использоваться, чтобы оценить использование памяти MySQL. Вы, возможно, должны изменить формулу, чтобы составлять буферы и кэши в Вашей версии MySQL и конфигурации. Для краткого обзора буферов MySQL и кэшей см. раздел 9.12.3.1.

innodb_buffer_pool_size + key_buffer_size +
   max_connections*(sort_buffer_size+read_buffer_size+binlog_cache_size) +
   max_connections*2MB

Каждый поток использует стек (часто 2 МБ, но только 256 КБ в двоичных модулях MySQL от Oracle Corporation) и в худшем случае также использует еще sort_buffer_size + read_buffer_size памяти.

В Linux, если ядро настроено для поддержки большой страницы, InnoDB может использовать большие страницы, чтобы выделить память для буферного пула. См. раздел 9.12.3.2.

16.6.2. Конфигурирование InnoDB для работы только для чтения

Вы можете теперь запросить таблицы, где каталог данных MySQL находится на носителе только для чтения, включая опцию --innodb-read-only при запуске сервера.

Как это включить

Чтобы подготовить систему к работе только для чтения, удостоверьтесь, что вся необходимая информация сброшена в файлы с данными прежде, чем сохранить ее на носителе только для чтения. Выполните сервер с отключенной буферизацией изменения ( innodb_change_buffering=0) и сделайте медленную парковку.

Чтобы включить режим только для чтения для всего MySQL, определите следующие параметры конфигурации при запуске сервера:

С MySQL 8.0 включение innodb_read_only блокирует табличные операции создания и удаления для всех механизмов хранения. Эти операции изменяют таблицы словаря данных в системной базе данных mysql, но те таблицы использует механизм хранения InnoDB и не может изменить, когда включена innodb_read_only . То же самое ограничение относится к любой работе, которая изменяет таблицы словаря данных, такой как ANALYZE TABLE и ALTER TABLE tbl_name ENGINE=engine_name .

Кроме того, другие таблицы в базе данных mysql используют механизм хранения InnoDB в MySQL 8.0. Например, CREATE USER, GRANT, REVOKE и INSTALL PLUGIN не работают в режиме только для чтения.

Сценарии использования

Этот режим работы является подходящим в таких ситуациях:

Эта особенность, главным образом, предназначена для гибкости в распределении и развертывании, а не сырой работе, основанной на аспекте только для чтения. См. раздел 9.5.3 для способов настроить исполнение запросов только для чтения, которые не требуют создания всего сервера только для чтения.

Как это работает

Когда сервер выполнен в режиме только для чтения через --innodb-read-only , многие особенности и компоненты InnoDB уменьшены или выключены полностью:

16.6.3. Конфигурация буферного пула InnoDB

Этот раздел обеспечивает конфигурацию буферного пула InnoDB.

16.6.3.1. Буферный пул InnoDB

InnoDB поддерживает область хранения, названную буферным пулом для того, чтобы кэшировать данные и индексы в памяти. Знание, как буфер работает и использование в своих интересах его, чтобы сохранить данные, к которым часто получают доступ, в памяти, важный аспект настройки MySQL.

Вы можете сконфигурировать различные аспекты буферного пула InnoDB, чтобы улучшить работу.

Алгоритм InnoDB LRU

InnoDB управляет буферным пулом как списком, используя вариант последнего использованного алгоритма (LRU). Когда нужно место, чтобы добавить новую страницу к пулу, InnoDB вычеркивает последнюю использованную страницу и добавляет новую страницу к середине списка. Эта вставка в середину обрабатывает список как два подсписка:

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

Алгоритм LRU работает следующим образом по умолчанию:

По умолчанию, страницы, считанные запросами немедленно, перемещаются в новый подсписок, означая, что они будут оставаться в буферном пуле в течение долгого времени. Сканирование таблицы (такое, как выполнено для mysqldump или SELECT без WHERE) может принести большой объем данных в буферный пул и выдавить эквивалентное количество более старых данных, даже если новые данные никогда не используются снова. Точно так же страницы, которые загружены фоновым потоком предвыборки, к которым затем получен доступ только однажды, перемещены в начало нового списка. Эти ситуации могут продвинуть часто используемые страницы к старому подсписку, где они становятся кандидатами на вычеркивание. Для информации об оптимизации этого поведения см. разделы 16.6.3.4 и 16.6.3.5.

InnoDB Standard Monitor выводит содержимое нескольких полей в разделе BUFFER POOL AND MEMORY, которые принадлежат работе алгоритма LRU буферного пула. Для деталей см. раздел 16.6.3.9.

Параметры конфигурации буферов InnoDB

Несколько параметров конфигурации затрагивают различные аспекты буферного пула InnoDB.

16.6.3.2. Конфигурирование размера буферного пула InnoDB

Вы можете сконфигурировать размер буферного пула офлайн (при запуске) или онлайн в то время, как сервер работает. Поведение, описанное в этом разделе, относится к обоим методам.

Увеличивая или уменьшая innodb_buffer_pool_size работа выполняется кусками. Размер куска определен параметром конфигурации innodb_buffer_pool_chunk_size, у которого есть значение по умолчанию 128M.

Размер пула должен всегда быть равным или кратным числу innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances. Если Вы конфигурируете innodb_buffer_pool_size к значению, которое не равно или кратно числу innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances, размер пула автоматически скорректирован к значению, которое равно или кратно этому числу, но не меньше чем указанный буферный размер пула.

В следующем примере innodb_buffer_pool_size установлен в 8G, и innodb_buffer_pool_instances установлен в 16. innodb_buffer_pool_chunk_size 128M, что является значением по умолчанию.

8G допустимое значение innodb_buffer_pool_size, потому что 8G кратно innodb_buffer_pool_instances=16 * innodb_buffer_pool_chunk_size=128M, которое 2G.

shell> mysqld --innodb_buffer_pool_size=8G
                 --innodb_buffer_pool_instances=16
mysql> SELECT @@innodb_buffer_pool_size/1024/1024/1024;
+------------------------------------------+
| @@innodb_buffer_pool_size/1024/1024/1024 |
+------------------------------------------+
|   8.000000000000                         |
+------------------------------------------+

В этом примере innodb_buffer_pool_size установлен в 9G и innodb_buffer_pool_instances установлен в 16. innodb_buffer_pool_chunk_size 128M, что является значением по умолчанию. В этом случае 9G не кратно innodb_buffer_pool_instances=16 * innodb_buffer_pool_chunk_size=128M, так что innodb_buffer_pool_size скорректирован к 10G, что является следующим числом, кратным innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances, но не меньше чем указанный размер пула.

shell> mysqld --innodb_buffer_pool_size=9G
                 --innodb_buffer_pool_instances=16
mysql> SELECT @@innodb_buffer_pool_size/1024/1024/1024;
+------------------------------------------+
| @@innodb_buffer_pool_size/1024/1024/1024 |
+------------------------------------------+
|  10.000000000000                         |
+------------------------------------------+
Конфигурирование размера куска буфера InnoDB

innodb_buffer_pool_chunk_size может быть увеличен или уменьшен с шагом в 1MB (1048576 байт), но может быть изменен только при запуске в командной строки или в конфигурационном файле MySQL.

Командная строка:

shell> mysqld --innodb_buffer_pool_chunk_size=134217728

Конфигурационный файл:

[mysqld]
innodb_buffer_pool_chunk_size=134217728

Следующие условия применяются, изменяя innodb_buffer_pool_chunk_size:

Чтобы избежать потенциальных исполнительных проблем, число кусков ( innodb_buffer_pool_size / innodb_buffer_pool_chunk_size) не должно превышать 1000.

Конфигурирование буфера InnoDB Online

Опция innodb_buffer_pool_size может быть установлена динамически, используя командой SET, разрешая Вам изменить размеры буферного пула, не перезапуская сервер. Например:

mysql> SET GLOBAL innodb_buffer_pool_size=402653184;

Активные транзакции и операции через InnoDB API должны быть завершены прежде, чем изменить размеры буферного пула. Начиная изменение размера, работа не запускается, пока все активные транзакции не завершены. Как только работа по изменению размеров началась, новые транзакции и операции, которые требуют доступа к буферному пулу, ждут, пока работа не закончится. Исключение: параллельный доступ к буферному пулу разрешен в то время, когда буферный пул дефрагментируется. Недостаток разрешения параллельного доступа состоит в том, что это может привести к временной нехватке доступных страниц, в то время как страницы удаляются.

Вложенные транзакции могут отвалиться, если начаты после того, как началась работа по изменению размера буфера.

Контроль изменения размера пула

Innodb_buffer_pool_resize_status сообщает о ходе изменения размеров буферного пула:

mysql> SHOW STATUS WHERE Variable_name='InnoDB_buffer_pool_resize_status';
+----------------------------------+----------------------------------+
| Variable_name                    | Value                            |
+----------------------------------+----------------------------------+
| Innodb_buffer_pool_resize_status | Resizing also other hash tables. |
+----------------------------------+----------------------------------+

Это также зарегистрировано в файле журнала ошибок сервера. Этот пример показывает записи, которые зарегистрированы, увеличивая размер буферного пула:

[Note] InnoDB: Resizing buffer pool from 134217728 to 4294967296. (unit=134217728)
[Note] InnoDB: disabled adaptive hash index.
[Note] InnoDB: buffer pool 0 : 31 chunks (253952 blocks) was added.
[Note] InnoDB: buffer pool 0 : hash tables were resized.
[Note] InnoDB: Resized hash tables at lock_sys, dictionary.
[Note] InnoDB: completed to resize buffer pool from 134217728 to 4294967296.
[Note] InnoDB: re-enabled adaptive hash index.

Этот пример показывает записи, которые зарегистрированы, уменьшая размер буферного пула:

[Note] InnoDB: Resizing buffer pool from 4294967296 to 134217728. (unit=134217728)
[Note] InnoDB: disabled adaptive hash index.
[Note] InnoDB: buffer pool 0 : start to withdraw the last 253952 blocks.
[Note] InnoDB: buffer pool 0 : withdrew 253952 blocks from free list. tried to relocate 0 pages.
(253952/253952)
[Note] InnoDB: buffer pool 0 : withdrawn target 253952 blocks.
[Note] InnoDB: buffer pool 0 : 31 chunks (253952 blocks) was freed.
[Note] InnoDB: buffer pool 0 : hash tables were resized.
[Note] InnoDB: Resized hash tables at lock_sys, dictionary.
[Note] InnoDB: completed to resize buffer pool from 4294967296 to 134217728.
[Note] InnoDB: re-enabled adaptive hash index.
Как происходит изменение

Работа изменения размеров выполнена фоновым потоком. Увеличивая размер буферного пула:

В то время как эти операции происходят, другие потоки заблокированы на доступ к буферному пулу.

Уменьшение размера буферного пула:

Из этих операций только дефрагментация и удаление страниц позволяют другим потокам доступ к буферному пулу одновременно.

16.6.3.3. Конфигурирование многих буферных экземпляров

Для систем с буферными пулами в диапазоне нескольких гигабайт деление буферного пула на отдельные экземпляры может улучшить параллелизм, уменьшая столкновения потоков при доступе к кэшируемым страницам. Эта особенность как правило предназначается для систем с многогигабайтным буфером. Многократные буферные экземпляры сконфигурированы, используя опцию innodb_buffer_pool_instances, и Вы могли бы также корректировать innodb_buffer_pool_size.

Когда буферный пул является большим, много запросов данных могут быть удовлетворены, получая из памяти. Вы могли бы столкнуться с узкими местами от многократных потоков, пытающихся получить доступ к буферному пулу сразу. Вы можете позволить многим буферным пулам минимизировать это. Каждая страница, которая сохранена в (или считана из) буферного пула, назначена на один из буферных пулов беспорядочно, используя хеширующую функцию. Каждый буферный пул управляет своими собственными свободными списками, списками потока, LRU и всеми другими структурами данных, соединенными с буферным пулом. До MySQL 8.0 каждый буферный пул был защищен его собственным mutex. В MySQL 8.0 и позже mutex был заменен несколькими списками и хешем, чтобы уменьшить накладные расходы.

Чтобы включить многократные буферы, установите опцию innodb_buffer_pool_instances к значению больше 1 (значение по умолчанию), но до 64 (максимум). Эта опция вступает в силу только, когда Вы устанавливаете innodb_buffer_pool_size к размеру 1GB или больше. Полный размер, который Вы определяете, разделен среди всех буферных пулов. Для лучшей эффективности, определите комбинацию innodb_buffer_pool_instances и innodb_buffer_pool_size так, чтобы каждый экземпляр буфера был по крайней мере в 1GB.

Для информации об изменении размера буфера InnoDB см. раздел 16.6.3.2.

16.6.3.4. Создание стойкого к сканированию буферного пула

Вместо того, чтобы использовать строгий алгоритм LRU InnoDB использует метод, чтобы минимизировать объем данных, который принесен в буферный пул, но не используется никогда больше. Цель состоит в том, чтобы удостовериться, что часто используемые (горячие) страницы остаются в буферном пуле, как раз когда предвыборка и полное сканирование таблицы вводят новые блоки, которые не факт, что будут использованы позже.

Недавно считанные блоки вставлены в середину списка LRU. Все недавно прочитанные страницы вставлены в место, которое по умолчанию занимает место в 3/8 от хвоста списка LRU. Страницы перемещены в начало списка, когда к ним получают доступ в буферном пуле впервые. Таким образом, страницы, к которым никогда не получают доступ, никогда не добираются до передней части списка LRU и вычеркиваются скорее, чем со строгим подходом LRU. Это расположение делит список LRU на два сегмента, где страницы сдвигаются вниз от точки вставки.

Для объяснения внутренних работ буферного пула InnoDB и специфических особенностей алгоритма LRU см. раздел 16.6.3.1.

Вы можете управлять точкой вставки в списке LRU и выбрать применяет ли InnoDB ту же самую оптимизацию к блокам, принесенным в буферный пул просмотром таблицы или индекса. Параметр конфигурации innodb_old_blocks_pct управляет процентом старых блоков в списке LRU. Значение по умолчанию innodb_old_blocks_pct 37 соответствует оригинальному отношению 3/8. Диапазон значения от 5 (новые страницы в буфере стареют очень быстро) до 95 (только 5% буферного пула сохранены для горячих страниц, делая алгоритм близким к знакомой стратегии LRU).

Оптимизация, которая препятствует буферному пулу взбалтываться предвыборкой, может избежать подобных проблем из-за просмотров таблицы или индекса. В этих просмотрах к странице данных как правило получают доступ несколько раз в быстрой последовательности и никогда не затрагивают ее снова. Параметр конфигурации innodb_old_blocks_time определяет окно времени (в миллисекундах) после первого доступа к странице, во время которого к ней можно получить доступ, не перемещая ее в начало списка LRU. Значение по умолчанию innodb_old_blocks_time 1000. Увеличение этого значения делает все больше блоков стареющими быстро.

innodb_old_blocks_pct и innodb_old_blocks_time являются динамическими, глобальными и может быть определены в файле опции MySQL (my.cnf или my.ini) или изменены во время выполнения через SET GLOBAL. Изменение настроек требует привилегии SUPER.

Помочь Вам измерить эффект этих параметров может отчет команды SHOW ENGINE INNODB STATUS о буферной статистике пула. Для деталей см. раздел 16.6.3.9.

Поскольку эффекты этих параметров могут значительно различаться в зависимости от Вашей конфигурации аппаратных средств, Ваших данных и деталей Вашей рабочей нагрузки, всегда определяйте эффективность, чтобы проверить что получилось прежде, чем изменить эти настройки в любой критической по отношению к работе или производственной среде.

В смешанных рабочих нагрузках, где большая часть деятельности OLTP с с периодическими запросами сообщения пакета, которые приводят к большим просмотрам, установка значения innodb_old_blocks_time во время пакетных выполнений может помочь сохранить рабочий набор нормальной рабочей нагрузки в буферном пуле.

Просматривая большие таблицы, которые не могут поместиться полностью в буферном пуле, установите innodb_old_blocks_pct к маленькому значению, чтобы не дать данным, которые только считаны однажды, заполнить весь буфер. Например, установка innodb_old_blocks_pct=5 ограничивает эти данные 5% размера буферного пула.

Когда просматриваете маленькие таблицы, которые действительно вписываются в память, уменьшите накладные расходы на перемещение страниц в буфере, установив innodb_old_blocks_pct в его значение по умолчанию или еще выше, например, innodb_old_blocks_pct=50.

Эффект изменения innodb_old_blocks_time предсказать трудней, чем innodb_old_blocks_pct, так как он изменяется больше с рабочей нагрузкой. Чтобы достигнуть оптимального значения, проведите свои собственные точки отсчета, если изменение производительности от корректировки innodb_old_blocks_pct недостаточно.

16.6.3.5. Конфигурирование предвыборки InnoDB

Предвыборка это запрос ввода/вывода предварительно принести страницы в буферный пул асинхронно, в ожидании, что эти страницы скоро будут необходимы. Запросы получают все страницы в одном экстенте . InnoDB использует два алгоритма предвыборки, чтобы улучшить работу ввода/вывода:

Линейная предвыборка метод, который предсказывает, какие страницы могли бы скоро быть необходимы, основываясь на страницах в буферном пуле. Вы управляете, когда InnoDB выполняет работу предвыборки, корректируя число последовательных доступов к странице, требуемых, чтобы вызвать асинхронный запрос чтения, используя параметр конфигурации innodb_read_ahead_threshold.

Параметр конфигурации innodb_read_ahead_threshold контролирует, насколько чувствителен InnoDB в обнаружении образцов последовательного доступа страницы. Если число чтения страниц последовательно из экстента больше чем или равно innodb_read_ahead_threshold, InnoDB начинает асинхронную работу чтения следующего экстента целиком. innodb_read_ahead_threshold может быть установлен в любое значение от 0 до 64. По умолчанию 56. Чем выше значение, тем более строгая проверка образца доступа. Например, если Вы устанавливаете значение в 48, InnoDB вызывает линейный запрос предвыборки только когда к 48 страницам в текущем экстенте получили доступ последовательно. Если значение 8, InnoDB вызывает линейный запрос предвыборки даже если только к 8 страницам в экстенте получают доступ последовательно. Вы можете установить значение этого параметра в файле конфигурации MySQL или изменить это динамически с помощью SET GLOBAL, но для этого надо иметь привилегиюSUPER.

Случайная это метод, который предсказывает, когда страницы могли бы скоро быть необходимы, основываясь на страницах, которые уже в буферном пуле, независимо от порядка, в котором были считаны те страницы. Если 13 последовательных страниц из того же самого экстента найдены в буферном пуле, InnoDB делает запрос предварительно загрузить остающиеся страницы экстента. Чтобы активировать эту опцию, установите переменную конфигурации innodb_random_read_ahead в ON.

Команда SHOW ENGINE INNODB STATUS показывает статистику, чтобы помочь Вам оценить эффективность алгоритма чтения. Статистические данные включают счетчики для следующих глобальных переменных состояния:

Эта информация может быть полезной, точно настраивая innodb_random_read_ahead.

Для получения дополнительной информации о работе ввода/вывода см. разделы 9.5.8 и 9.12.1.

16.6.3.6. Конфигурирование сброса буфера InnoDB

InnoDB выполняет определенные задачи в фоне, включая сброс of грязных страниц (те страницы, которые были изменены, но еще не записаны в файлы базы данных) из буферного пула.

InnoDB начинает сбрасывать страницы пула, когда процент грязных страниц в буферном пуле достигает нижнего предела, определенного innodb_max_dirty_pages_pct_lwm. Эта опция предназначена, чтобы управлять отношением грязных страниц в буферном пуле и идеально препятствовать тому, чтобы процент грязных страниц достиг innodb_max_dirty_pages_pct. Если процент грязных страниц в буферном пуле превышает innodb_max_dirty_pages_pct, InnoDB начинает сброс буферных страниц немедленно.

InnoDB использует алгоритм, чтобы оценить необходимый уровень сброса, основанный на скорости генерации журнала redo и действующего коэффициента сброса. Намерение состоит в том, чтобы пригладить эффективность работы, гарантируя, что буферная деятельность потока не отстает от потребности сохранить буферный пул чистым. Автоматическая корректировка уровня сброса может помочь избежать внезапных падений пропускной способности, когда сброс буферного пула начинает мешать обычному вводу-выводу.

InnoDB использует файлы системного журнала круговым способом. Прежде, чем снова использовать часть файла системного журнала, InnoDB сбрасывает на диск все грязные буферные страницы, чьи записи содержатся в этой части файла системного журнала, это процесс острой контрольной точки. Если рабочая нагрузка записи интенсивная, она производит много информации в журнале redo. Если все свободное место в файлах системного журнала израсходовано, острая контрольная точка происходит, вызывая временное сокращение пропускной способности. Эта ситуация может произойти, даже если innodb_max_dirty_pages_pct не достигнут.

InnoDB использует эвристический алгоритм, чтобы избежать такого сценария, измеряя число грязных страниц в буферном пуле и уровень прироста журнала redo. Основываясь на этих числах, InnoDB решает, сколько грязных страниц сбросить из буферного пула каждую секунду. Этот адаптивный алгоритм в состоянии иметь дело с внезапными изменениями в рабочей нагрузке.

Внутренний сопоставительный анализ показал, что этот алгоритм не только поддерживает пропускную способность в течение долгого времени, но и может также значительно улучшить полную пропускную способность.

Поскольку адаптивный сброс может значительно затронуть образец ввода/вывода рабочей нагрузки, параметр innodb_adaptive_flushing позволяет Вам выключать эту особенность. Значение по умолчанию для innodb_adaptive_flushing TRUE, адаптивный алгоритм включен. Вы можете установить значение этого параметра в файле опции MySQL (my.cnf или my.ini) или изменить это динамически с помощью SET GLOBAL, имея привилегию SUPER.

Для информации о точной настройке сброса пула в InnoDB см. раздел 16.6.3.7. Для получения дополнительной информации о работе ввода/вывода InnoDB см. раздел 9.5.8.

16.6.3.7. Точная настройка сброса буферного пула InnoDB

Опции innodb_flush_neighbors и innodb_lru_scan_depth позволяют Вам точно настраивать определенные аспекты процесса сброса для буферного пула InnoDB. Эти опции прежде всего помогают рабочим нагрузкам с интенсивной записью. С большой активностью DML сброс может отстать, если это недостаточно агрессивно, приводя к чрезмерному использованию памяти в буферном пуле. С другой стороны сброс может перегрузить Вашу систему ввода/вывода, если этот механизм слишком агрессивен. Идеальные настройки зависят от Вашей рабочей нагрузки, образцов доступа к данным и конфигурации хранения (например, хранятся ли данные на HDD или SSD).

Для систем с постоянными тяжелыми рабочими нагрузками или рабочими нагрузками, которые широко колеблются, несколько параметров конфигурации позволяют Вам точно настраивать поведение сброса для таблиц:

Эти опции подпитывают формулу, используемую параметром innodb_adaptive_flushing.

Опции innodb_adaptive_flushing, innodb_io_capacity и innodb_max_dirty_pages_pct ограничены или расширены следующими опциями:

Механизм адаптивного сброса InnoDB не является подходящим во всех случаях. Это приносит большинство пользы, когда журнал redo рискует заполниться. Опция innodb_adaptive_flushing_lwm определяет процент нижнего предела заполнения журнала redo, когда этот порог пересечен, InnoDB включает адаптивный сброс даже если не определена опция innodb_adaptive_flushing.

Если активность сброса слишком мала, InnoDB может сбрасывать более настойчиво, чем указано в innodb_io_capacity . innodb_io_capacity_max представляет верхний предел нагрузки ввода/вывода, используемой в таких чрезвычайных ситуациях, чтобы пик ввода/вывода не потреблял всю пропускную способность сервера.

InnoDB старается сбросить данные из буферного пула так, чтобы процент грязных страниц не превысил значение innodb_max_dirty_pages_pct. Значение по умолчанию для innodb_max_dirty_pages_pct 75.

innodb_max_dirty_pages_pct устанавливает цель для активности сброса. Это не затрагивает уровень сброса. Для информации об управлении уровнем сброса см. раздел 16.6.3.6.

Опция innodb_max_dirty_pages_pct_lwm определяет значение, которое представляет процент грязных страниц, при котором предварительному сбросу позволяют управлять отношением грязных страниц и идеально препятствовать тому, чтобы процент грязных страниц достиг innodb_max_dirty_pages_pct. Значение innodb_max_dirty_pages_pct_lwm=0 отключает предсброс.

Большинство опций, на которые ссылаются выше, наиболее применимы к серверам, которые работают с большими рабочими нагрузками по записи в течение долгих промежутков времени.

innodb_flushing_avg_loops определяет число итераций для которого InnoDB сохраняет ранее расчитанный снимок состояния сброса, который управляет, как быстро адаптивный сброс отвечает на изменения загрузки. Указание большого значения для innodb_flushing_avg_loops предписывает хранить расчитанный снимок дольше, таким образом, адаптивный сброс отвечает более медленно. Высокое значение также уменьшает позитивные отклики между передним планом и фоновой работой, но задание большого значения очень важно, чтобы гарантировать, что использование InnoDB журнала redo не достигает 75% (предел, при котором запускается сброс), и что innodb_max_dirty_pages_pct сохраняет число грязных страниц на уровне, который является подходящим для рабочей нагрузки.

Системы с последовательными рабочими нагрузками, большим innodb_log_file_size и маленькими пиками, которые не достигают 75% использования места в журнале redo, должны использовать верхний уровень innodb_flushing_avg_loops, чтобы продолжить сбрасывать столь гладко, насколько возможно. Для систем с экстремальными пиками загрузки или файлами системного журнала, которые не обеспечивают много пространства, должны использовать меньшее значение innodb_flushing_avg_loops. Меньшее значение позволяет сбрасывать так, чтобы точно отследить загрузку и помогает избежать использования 75% пространства журнала redo.

16.6.3.8. Сохранение и восстановление состоояния буферного пула

Чтобы уменьшить период загрузки после перезапуска сервера, InnoDB сохраняет процент последний раз используемых страниц для каждого буферного пула при завершении работы сервера и восстанавливает эти страницы при запуске сервера. Процент недавно используемых страниц, который сохранен, определен параметром innodb_buffer_pool_dump_at_shutdown.

После перезапуска занятого сервера как правило есть период разминки с устойчиво увеличивающейся пропускной способностью, поскольку дисковые страницы, которые были в буферном пуле, возвращены в память (поскольку те же самые данные запрошены, обновлены и так далее). Способность восстановить буферный пул при запуске сокращает период разминки, перезагружая дисковые страницы, которые были в буферном пуле перед перезапуском вместо того, чтобы ждать операций DML, чтобы получить доступ к соответствующим строкам. Кроме того, запросы ввода/вывода могут быть выполнены в больших пакетах, делая полный ввод/вывод быстрее. Загрузка страниц происходит в фоне и не задерживает запуск базы данных.

В дополнение к сохранению состояния буферного пула при завершении работы и восстановлении его при запуске, Вы можете сохранить и восстановить состояние буферного пула в любое время, в то время как сервер работает. Например, Вы можете сохранить состояние после достижения устойчивой пропускной способности при устойчивой рабочей нагрузке. Вы можете также восстановить предыдущее состояние буферного пула после выполнения отчетов или заданий обслуживания, которые приносят страницы данных в буферный пул, которые нужны только для тех операций, или после выполнения некоторой другой нетипичной рабочей нагрузки.

Даже при том, что буферный пул может быть много гигабайт в размере, данные пула, которые InnoDB сохраняет на диск являются крошечными. Только ID табличного пространства и ID страницы, необходимые, чтобы определить местонахождение соответствующих страниц, сохранены на диск. Эта информация получена из таблицы INNODB_BUFFER_PAGE_LRU INFORMATION_SCHEMA. По умолчанию ID табличного пространства и страницы сохранены в файле ib_buffer_pool, в кталоге данных InnoDB. Имя файла и местоположение могут быть изменены, используя параметр innodb_buffer_pool_filename.

Поскольку данные кэшируются и устаревают в пуле, нет никакой проблемы, если дисковые страницы были недавно обновлены, или если работа DML вовлекает данные, которые еще не были загружены. Механизм загрузки пропускает требуемые страницы, которые больше не существуют.

Основной механизм вовлекает фоновый поток, чтобы выполнить операции загрузки и дамп.

Дисковые страницы от сжатых таблиц загружены в буферный пул в их сжатой форме. Страницы разсжаты, когда к содержанию страницы получают доступ во время операций DML. Поскольку разсжатие страниц является процессом, серьезно нагружающим центральный процессор, более эффективно для параллелизма выполнить работу в потоке соединения, а не в единственном потоке, который выполняет работу восстановления пула.

Конфигурирование процента дампа для страниц буферного пула

Прежде, чем вывести страницы из буферного пула, Вы можете сконфигурировать процент используемых буферных страниц, которые Вы хотите вывести, устанавливая опцию innodb_buffer_pool_dump_pct. Если Вы планируете вывести буферные страницы в то время, как сервер работает, Вы можете сконфигурировать опцию динамически:

SET GLOBAL innodb_buffer_pool_dump_pct=40;

Если Вы планируете вывести буферные страницы при завершении работы сервера, надо установить innodb_buffer_pool_dump_pct в Вашем конфигурационном файле.

[mysqld]
innodb_buffer_pool_dump_pct=40

Значение innodb_buffer_pool_dump_pct по умолчанию 25 (дамп 25% используемых последний раз страниц).

Сохранение статуса буферного пула при завершении работы и восстановление при запуске

Чтобы сохранить статус буферного пула при завершении работы сервера, сделайте следующее запрос до закрытия сервера:

SET GLOBAL innodb_buffer_pool_dump_at_shutdown=ON;

innodb_buffer_pool_dump_at_shutdown включена по умолчанию.

Чтобы восстановить статус пула при запуске сервера, определите опцию --innodb_buffer_pool_load_at_startup, запуская сервер:

mysqld --innodb_buffer_pool_load_at_startup=ON;

innodb_buffer_pool_load_at_startup включен по умолчанию.

Сохранение и восстановление статуса буферного пула онлайн

Чтобы сохранить состояние буферного пула в то время, как сервер MySQL работает, сделайте следующее:

SET GLOBAL innodb_buffer_pool_dump_now=ON;

Чтобы восстановить состояние буферного пула в то время, как сервер MySQL работает, сделайте следующее:

SET GLOBAL innodb_buffer_pool_load_now=ON;
Отображение процесса дампа буферного пула

Чтобы вывести на экран процесс сохранения пула на диск, сделайте следующее:

SHOW STATUS LIKE 'Innodb_buffer_pool_dump_status';

Если работа еще не запустилась, вернется not started . Если работа завершена, время завершения напечатано (например, Finished at 110505 12:18:02). Если работа происходит, информация о статусе обеспечена (например, Dumping buffer pool 5/7, page 237/2873).

Отображение процесса загрузки буферного пула

Чтобы вывести на экран процесс загрузки пула, сделайте следующее:

SHOW STATUS LIKE 'Innodb_buffer_pool_load_status';

Если работа еще не запустилась, вернется not started . Если работа завершена, время завершения напечатано (например, Finished at 110505 12:18:02). Если работа происходит, информация о статусе обеспечена (например, Loaded 123/22300 pages).

Прерывание загрузки пула

Чтобы прервать работу загрузки пула, сделайте следующее:

SET GLOBAL innodb_buffer_pool_load_abort=ON;
Контроль загрузки пула, используя Performance Schema

Вы можете контролировать ход загрузки пула, используя Performance Schema.

Следующий пример демонстрирует, как включить инструмент этапа событий stage/innodb/buffer pool load и связанные потребительские таблицы, чтобы контролировать продвижение загрузки.

Для информации о дампе пула и процедурах загрузки, используемых в этом примере, см. раздел 16.6.3.8 . Для информации об инструментах этапа Performance Schema и связанных потребителях, см. раздел 23.9.5.

  1. Включите инструмент stage/innodb/buffer pool load :

    mysql> UPDATE performance_schema.setup_instruments SET ENABLED = 'YES'
                     WHERE NAME LIKE 'stage/innodb/buffer%';
    
  2. Включите потребительские таблицы этапа событий, которые включают events_stages_current , events_stages_history и events_stages_history_long.
    mysql> UPDATE performance_schema.setup_consumers SET ENABLED = 'YES'
                     WHERE NAME LIKE '%stages%';
    
  3. Выведите текущее буферное состояние с помощью innodb_buffer_pool_dump_now.
    mysql> SET GLOBAL innodb_buffer_pool_dump_now=ON;
    
  4. Проверьте состояние дампа пула, чтобы гарантировать, что работа завершилась.
    mysql> SHOW STATUS LIKE 'Innodb_buffer_pool_dump_status'\G
    *************************** 1. row ***************************
    Variable_name: Innodb_buffer_pool_dump_status
    Value: Buffer pool(s) dump completed at 150202 16:38:58
    
  5. Загрузите буферный пул с помощью innodb_buffer_pool_load_now:
    mysql> SET GLOBAL innodb_buffer_pool_load_now=ON;
    
  6. Проверьте текущий статус загрузки пула, запрашивая таблицу Performance Schema events_stages_current. Столбец WORK_COMPLETED показывает число загруженных страниц пула. WORK_ESTIMATED обеспечивает оценку остающейся работы в страницах.
    mysql> SELECT EVENT_NAME, WORK_COMPLETED, WORK_ESTIMATED
                     FROM performance_schema.events_stages_current;
    +-------------------------------+----------------+----------------+
    | EVENT_NAME                    | WORK_COMPLETED | WORK_ESTIMATED |
    +-------------------------------+----------------+----------------+
    | stage/innodb/buffer pool load | 5353           | 7167           |
    +-------------------------------+----------------+----------------+
    

    Таблица events_stages_current возвращает пустой набор, если работа загрузки пула завершилась. В этом случае Вы можете проверить таблицу events_stages_history , чтобы рассмотреть данные для завершенного случая. Например:

    mysql> SELECT EVENT_NAME, WORK_COMPLETED, WORK_ESTIMATED
                     FROM performance_schema.events_stages_history;
    +-------------------------------+----------------+----------------+
    | EVENT_NAME                    | WORK_COMPLETED | WORK_ESTIMATED |
    +-------------------------------+----------------+----------------+
    | stage/innodb/buffer pool load | 7167           | 7167           |
    +-------------------------------+----------------+----------------+
    

Вы можете также контролировать ход загрузки пула, используя Performance Schema, загружая буферный пул при запуске с использованием innodb_buffer_pool_load_at_startup. В этом случае инструмент stage/innodb/buffer pool load и связанные потребители должны быть включены при запуске. Для получения дополнительной информации см. раздел 23.2.2 .

16.6.3.9. Контроль буферного пула, используя стандартный монитор InnoDB

Вывод InnoDB Standard Monitor, к которому можно получить доступ, используя SHOW ENGINE INNODB STATUS , обеспечивает метрики, которые принадлежат работе с пулом InnoDB. Буферные метрики пула расположены в разделе BUFFER POOL AND MEMORY вывода InnoDB Standard Monitor и подобны следующему:

----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 2198863872
Dictionary memory allocated 776332
Buffer pool size   131072
Free buffers   124908
Database pages 5720
Old database pages 2071
Modified db pages  910
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 4, not young 0
0.10 youngs/s, 0.00 non-youngs/s
Pages read 197, created 5523, written 5060
0.00 reads/s, 190.89 creates/s, 244.94 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not
0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read
ahead 0.00/s
LRU len: 5720, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]

Следующая таблица описывает метрики пула, о которых сообщает InnoDB Standard Monitor.

Средние числа в секунду в выводе InnoDB Standard Monitor основаны на прошедшем времени с последнего вывода InnoDB Standard Monitor.

Таблица 16.2. Метрики пула

ИмяОписание
Total memory allocatedПолная память, которая выделена для буферного пула в байтах.
Dictionary memory allocatedПолная память, выделенная для словаря данных InnoDB в байтах.
Buffer pool sizeПолный размер в страницах буферного пула.
Free buffersПолный размер в страницах свободного списка.
Database pagesПолный размер в страницах списка LRU.
Old database pagesПолный размер в страницах старого подсписка LRU.
Modified db pagesТекущее число страниц, измененных в буферном пуле.
Pending readsЧисло страниц, ждущих считывания в пул.
Pending writes LRUЧисло старых грязных страниц в буферном пуле, которые будут записаны от конца списка LRU.
Pending writes flush listЧисло страниц пула, которые будут сброшены во время установки контрольных точек.
Pending writes single pageЧисло независимых страниц в ожидании записи в буферном пуле.
Pages made youngОбщее количество молодых страниц в списке LRU (перемещенных к началу подсписка новых страниц).
Pages made not youngОбщее количество страниц, не сделанных молодыми в списке LRU (страницы, которые остались в подсписке старых, не будучи сделанным молодыми).
youngs/sСреднее число доступов в секунду к старым страницам в списке LRU, которые привели к созданию молодых страниц. См. примечания, которые следуют за этой таблицей для получения дополнительной информации.
non-youngs/sСреднее число доступов в секунду к старым страницам в списке LRU, которые не привели к созданию молодых страниц.
Pages readОбщее количество страниц, прочитанных из буферного пула.
Pages createdОбщее количество страниц, созданных в буферном пуле.
Pages writtenОбщее количество страниц, записанных из буферного пула.
reads/sСреднее число в секунду прочитанных страниц.
creates/sСреднее число в секунду создаваемых буферных страниц.
writes/sСреднее число записываемых буферных страниц в секунду.
Buffer pool hit rateЧастота успешных обращений к странице для страниц из буферной памяти, а не с диска.
young-making rateСредняя частота успешных обращений, в которых доступ к странице привел к созданию молодых страниц.
not (young-making rate)Средняя частота успешных обращений, в которых доступ к странице не привел к созданию молодых страниц.
Pages read ahead Среднее число операций предвыборки в секунду.
Pages evicted without accessСреднее число вычеркнутых страниц в секунду, к которым не получен доступ из буферного пула.
Random read aheadСреднее число операций случайного чтения в секунду.
LRU lenПолный размер в страницах списка LRU.
unzip_LRU lenПолный размер в страницах списка unzip_LRU.
I/O sumОбщее количество страниц списка LRU, к которым был доступ в течение прошлых 50 секунд.
I/O curОбщее количество страниц списка LRU, к которым получают доступ сейчас.
I/O unzip sumОбщее количество страниц списка unzip_LRU, к которым получали доступ.
I/O unzip curОбщее количество страниц списка unzip_LRU, к которым получают доступ сейчас.

Примечания:

Переменные статуса сервера пула InnoDB и таблица INNODB_BUFFER_POOL_STATS обеспечивает многие из тех же самых метрик пула, найденных в таблице INNODB_BUFFER_POOL_STATS, см. пример 16.19.

16.6.4. Конфигурирование изменения буферизации InnoDB

Когда INSERT, UPDATE и DELETE выполнены на таблице, значения индексированных столбцов (особенно значения вторичных ключей) часто находятся в несортированном порядке, требуя существенного ввода/вывода, чтобы принести вторичный индекс. InnoDB имеет буфер изменений, который кэширует изменения вторичного индекса, когда соответствующая страница не находится в буферном пуле, таким образом избегая дорогих операций ввода/вывода, не читая немедленно страницу с диска. Буферизованные изменения слиты, когда страница загружена в буферный пул, и обновленная страница позже сбрасывается на диск. Основной поток InnoDB объединяет изменения, когда сервер почти неактивен, и во время медленной парковки.

Поскольку это может привести к меньшему количеству обращений к диску, эта особенность является самой ценной для рабочих нагрузок, которые имеют большой ввод-вывод, например приложения с большим объемом операций DML, таких как большой объем вставок.

Однако, буфер изменения занимает часть буферного пула, уменьшая память, доступную страницам данных о кэше. Если рабочий набор данных почти помещается в буферный пул, или если Ваши таблицы имеют, относительно немногие вторичные индексы, может быть полезно отключить буферизацию изменения. Если работа помещается в буфере полностью, буферизация изменения не налагает дополнительных издержек, потому что это только относится к страницам, которые не находятся в буферном пуле.

Вы можете управлять степенью, в которой InnoDB выполняет буферизацию изменения, используя параметр innodb_change_buffering. Вы можете включить или отключить буферизацию для вставок и удалений (когда индексные записи первоначально отмечены для удаления) и операций чистки (когда индексные записи физически удалены). Обновления это комбинация вставки и удаления. Значение по умолчанию для innodb_change_buffering all.

Разрешенные значения innodb_change_buffering:

Вы можете установить innodb_change_buffering в файле опций MySQL (my.cnf или my.ini) или измените это динамически с помощью SET GLOBAL (нужна привилегия SUPER). Изменение установки затрагивает буферизацию новых операций, слияние существующих буферизованных записей не затронуто.

Подробности в разделе 16.4.2 . Для информации о конфигурировании размера буфера изменения см. раздел 16.6.4.1.

16.6.4.1. Конфигурирование максимального размера буфера изменений

Опция innodb_change_buffer_max_size позволяет Вам конфигурировать максимальный размер буфера изменения как процент полного размера буферного пула. По умолчанию innodb_change_buffer_max_size установлена в 25. Максимум 50.

Вы могли бы рассмотреть увеличение innodb_change_buffer_max_size на сервере MySQL с тяжелой вставкой, обновлением и удалением, где буферное слияние изменения не идет в ногу с новыми буферными записями изменения, заставляя буфер изменения достичь его максимального предела размера.

Вы могли бы рассмотреть уменьшение innodb_change_buffer_max_size на сервере MySQL со статическими данными, используемыми для отчетов, или если буфер изменения потребляет слишком много места в памяти, которое совместно использовано с буферным пулом, заставляя страницы стареть скорее, чем надо.

Проверьте различные настройки с представительной рабочей нагрузкой, чтобы определить оптимальную конфигурацию. Настройка innodb_change_buffer_max_size является динамической, что позволяет Вам изменять ее, не перезапуская сервер.

16.6.5. Конфигурирование параллелизма потока для InnoDB

InnoDB использует потоки операционной системы, чтобы обработать запросы от пользовательских транзакций. Транзакции могут выпустить много запросов к InnoDB перед завершением. На современных операционных системах и серверах с мультиядерными процессорами, где переключение контекста эффективно, большинство рабочих нагрузок, выполнены хорошо без особого предела на число параллельных потоков.

В ситуациях, где полезно минимизировать контекст, переключающийся между потоками, InnoDB может использовать много методов, чтобы ограничить число параллельного выполнения потоков операционной системы (и таким образом число запросов, которые обработаны в любой момент). Когда InnoDB получает новый запрос от пользовательского сеанса, если число одновременно выполняющихся потоков дошло до предопределенного предела, запрос спит в течение короткого времени прежде, чем попробует еще раз. Запрос, который не может быть запланирован после сна, помещен в очередь first-in/first-out и в конечном счете обработан. Потоки, ждущие блокировок, не посчитаны в числе параллельного выполнения потоков.

Вы можете ограничить число параллельных потоков, устанавливая параметры конфигурации innodb_thread_concurrency. Как только число выполняемых потоков достигает этого предела, дополнительные потоки спят в течение числа микросекунд, установленного параметром конфигурации innodb_thread_sleep_delay, прежде, чем быть помещенными в очередь.

Вы можете установить параметр конфигурации innodb_adaptive_max_sleep_delay к самому высокому значению, которое Вы разрешаете для innodb_thread_sleep_delay, и InnoDB автоматически корректирует innodb_thread_sleep_delay в зависимости от текущей и планируемой активности потоков. Эта динамическая корректировка помогает механизму планирования потока работать гладко в течение времен, когда система слегка загружена и когда она занята максимально.

Значение по умолчанию для innodb_thread_concurrency и подразумеваемый предел значения по умолчанию числа параллельных потоков был изменен в различных выпусках MySQL и InnoDB. Значение по умолчанию для innodb_thread_concurrency 0, чтобы по умолчанию не было никакого предела числа параллельного выполнения потоков.

InnoDB отправляет потоки в спячку только, когда число параллельных потоков ограничено. Когда нет никакого предела числа потоков, все работают одинаково. Таким образом, если innodb_thread_concurrency 0, значение innodb_thread_sleep_delay проигнорировано.

Когда есть предел числа потоков (когда innodb_thread_concurrency > 0), InnoDB уменьшает издержки переключения контекста, разрешая многократные запросы во время выполнения одного запроса SQL, не проверяя предела, установленного innodb_thread_concurrency. Так как запрос SQL может включить многострочные операции в пределах InnoDB, InnoDB назначает конкретное количество тикетов, которые позволяют потоку неоднократно планироваться с минимальными издержками.

Когда новый запрос SQL запускается, у потока нет никаких тикетов, и это должно работать согласно innodb_thread_concurrency. Как только поток входит в InnoDB, этому назначают много тикетов, которые это может использовать для того, чтобы впоследствии выполнить операции со строками. Если тикеты заканчиваются, поток вычеркивается, и innodb_thread_concurrency снова отслеживается, чтобы поместить поток назад в очередь first-in/first-out потоков ожидания. Когда поток еще раз попадает туда, тикеты назначены снова. Число назначенных тикетов определено глобальной опцией innodb_concurrency_tickets, 5000 по умолчанию. Потоку, который ждет блокировки, дают один тикет, как только блокировка становится доступной.

Правильные значения этих переменных зависят от Вашей среды и рабочей нагрузки. Попробуйте диапазон различных значений, чтобы определить, какое значение работает на Ваших приложениях. Прежде, чем ограничить число параллельного выполнения потоков, рассмотрите параметры конфигурации, которые могут улучшить исполнение InnoDB, например, innodb_adaptive_hash_index.

Для общей информации об обработке потока MySQL см. раздел 9.12.4.1.

16.6.6. Конфигурирование числа фоновых потоков ввода/вывода InnoDB

InnoDB применяет фоновые потоки , чтобы обслужить различные типы запросов ввода/вывода. Вы можете сконфигурировать число фоновых потоков, используя параметры конфигурации innodb_read_io_threads и innodb_write_io_threads. Эти параметры показывают число фоновых потоков, используемых для чтения и записи, соответственно. Они эффективны на всех поддержанных платформах. Вы можете установить значение этих параметров в файле опции MySQL (my.cnf или my.ini), Вы не можете изменить их динамически. Значение по умолчанию для этих параметров 4 допустимые значения 1-64.

Цель этого изменения состоит в том, чтобы сделать InnoDB более масштабируемым на системах высокого класса. Каждый фоновый поток может обработать до 256 запросов ввода/вывода. Основной источник фонового ввода/вывода это запросы предвыборки. InnoDB пытается сбалансировать загрузку входящих запросов таким способом, которым большая часть фоновой доли потоков работает одинаково. InnoDB также пытается выделить запросы чтения от того же самого экстента к тому же самому потоку, чтобы увеличить возможности соединения запросов вместе. Если у Вас есть подсистема ввода/вывода высокого класса, и Вы видите больше, чем 64 ждущих чтения запросов в SHOW ENGINE INNODB STATUS, Вы могли бы извлечь пользу, увеличивая значение innodb_read_io_threads.

Для получения дополнительной информации о работе ввода/вывода InnoDB см. раздел 9.5.8.

16.6.7. Конфигурирование ведущего уровня ввода/вывода потока InnoDB

Мастер-поток в InnoDB это поток, который выполняет различные задачи в фоне. Большинство этих задач связаны с вводом/выводом, такие, как сброс грязных страниц из буферного пула или запись изменений из буфера вставки в соответствующий вторичный индекс. Основной поток пытается выполнить эти задачи способом, который не оказывает негативное влияние на нормальную работу сервера. Это пытается оценить свободную доступную пропускную способность ввода/вывода и настроить свои действия, чтобы использовать в своих интересах эту свободную способность. Исторически InnoDB использовал твердое кодированное значение 100 IOPs (операций ввода/вывода в секунду) как полная способность ввода/вывода сервера.

Параметр innodb_io_capacity указывает на полную способность ввода/вывода, доступную InnoDB. Эти параметры должны быть установлены к приблизительному числу операций ввода/вывода, которые система может выполнить в секунду. Значение зависит от Вашей системной конфигурации. Когда innodb_io_capacity задано, основной поток оценивает пропускную способность ввода/вывода, доступную для фоновых задач, исходя из этого значения. Установка значения в 100 возвращает к старому поведению.

Вы можете установить значение innodb_io_capacity к числу 100 или больше. Значение по умолчанию 200, отражает, что производительность типичных современных устройств ввода/вывода выше, чем в первые годы MySQL. Как правило, значения около предыдущего значения по умолчанию 100 являются подходящими для устройств хранения данных потребительского уровня, таких как жесткие диски до 7200 RPM. Более быстрые жесткие диски, конфигурации RAID и SSD извлекают выгоду из более высоких значений.

innodb_io_capacity задает полный предел для всех экземпляров буферного пула. Когда грязные страницы сбрасываются, предел innodb_io_capacity разделен одинаково среди экземпляров буферного пула. Для получения дополнительной информации см. описание переменной innodb_io_capacity .

Вы можете установить значение этого параметра в файле опций MySQL или изменить динамически с помощью SET GLOBAL, при наличии привилегии SUPER.

Опция innodb_flush_sync предписывает игнорировать innodb_io_capacity во время взрывов деятельности ввода/вывода, которые происходят в контрольных точках. innodb_flush_sync включена по умолчанию.

В более ранних выпусках MySQL основной поток InnoDB также выполнял любые необходимые операции чистки . Те операции ввода/вывода теперь выполнены другими фоновыми потоками, числом которых управляет опция innodb_purge_threads .

Для получения дополнительной информации о работе ввода/вывода InnoDB см. раздел 9.5.8.

16.6.8. Конфигурирование опроса спин-блокировки

Много InnoDB mutex и rw-блокировок сохранены в течение короткого времени. На мультиядерной системе может быть более эффективно для потока непрерывно проверять, может ли это приобрести mutex или rw-блокировку некоторое время перед сном. Если mutex или rw-блокировка становятся доступными во время этого периода, поток может немедленно продолжиться в том же самом интервале времени. Однако, также частый опрос многократными потоками совместно используемого объекта может вызвать перегрузку кэша. InnoDB минимизирует эту проблему при ожидании случайное время между последующими опросами. Задержка осуществлена как цикл.

Вы можете управлять максимальной задержкой между тестированием mutex или rw-блокировки, используя параметр innodb_spin_wait_delay. Продолжительность цикла задержки зависит от компилятора C и целевого процессора. В эру Pentium на 100 МГц задержка была одной микросекундой. На системе, где все ядра процессора совместно используют быструю кэш-память, Вы могли бы уменьшить максимальную задержку или отключить цикл, устанавливая innodb_spin_wait_delay=0. На многопроцессорной системе эффект аннулирования кэша может быть более существенным, и Вы могли бы увеличить максимальную задержку.

Значение по умолчанию innodb_spin_wait_delay 6. Задержка это динамический глобальный параметр, который Вы можете определить в файле опции MySQL или командой SET GLOBAL innodb_spin_wait_delay=delay, где delay желаемая максимальная задержка. Изменение настроек требует привилегии SUPER.

Для исполнительных соображений операций блокировки в InnoDB см. раздел 9.11.

16.6.9. Конфигурирование планирования чистки InnoDB

Чистка (тип сбора мусора), которую InnoDB выполняет автоматически, теперь сделана в одном или более отдельных потоках, а не как часть мастер-потока. Это изменение улучшает масштабируемость, потому что основные операции базы данных работают независимо от работы обслуживания, происходящей в фоне.

Чтобы управлять этой особенностью, увеличьте значение параметра конфигурации innodb_purge_threads. Если действие DML сконцентрировано на единственной таблице или нескольких таблицах, сохраните установку низкой так, чтобы потоки не боролись друг с другом за доступ к занятым таблицам. Если операции DML распространены на многие таблицы, увеличивайте установку. Ее максимум 32.

Есть другой связанный параметр конфигурации innodb_purge_batch_size со значением по умолчанию 300 и максимальным значением 5000. Эта опция, главным образом, предназначена для экспериментирования и настройки операций чистки и не должна быть интересной типичным пользователям.

Для получения дополнительной информации о работе ввода/вывода InnoDB см. раздел 9.5.8.

16.6.10. Настройка оптимизатора статистики для InnoDB

Этот раздел описывает, как сконфигурировать постоянную статистику для таблиц InnoDB.

Статистические данные сохранены через перезапуски сервера, учитывая большую стабильность плана и и более последовательную работу запроса. Постоянные статистические данные также обеспечивают управление и гибкость с этими дополнительными выгодами:

Постоянная опция статистики активирована по умолчанию ( innodb_stats_persistent=ON).

Нестойкие статистические данные очищены на каждом перезапуске сервера и после некоторых других операций, и повторно вычислены при следующем доступе к таблице. В результате различные оценки могли быть произведены при перевычислении статистики, приводя к различному выбору в планах выполнения и изменениям в работе запроса.

Этот раздел также предоставляет информацию об оценке сложности ANALYZE TABLE, которая может быть полезной, пытаясь достигнуть баланса между точной статистикой и временем выполнения ANALYZE TABLE .

16.6.10.1. Конфигурирование постоянных параметров статистики

Постоянная статистика улучшает стабильность плана, храня статистику на диске и делая ее постоянной через перезапуски сервера так, чтобы оптимизатор, более вероятно, сделал последовательный выбор каждый раз для данного запроса.

Статистические данные сохранены на диск, когда innodb_stats_persistent=ON или когда отдельные таблицы составлены или изменены с STATS_PERSISTENT=1 . innodb_stats_persistent включен по умолчанию.

Прежде статистика была очищена при каждом перезапуске сервера и после некоторых других операций и повторно вычислена при следующем доступе к таблице. Следовательно, различные оценки могли быть произведены, повторно вычисляя статистику, приводя к различному выбору в планах выполнения запроса и таким образом изменениям в работе запроса.

Постоянные статистические данные сохранены в таблицах mysql.innodb_table_stats и mysql.innodb_index_stats, как описано в разделе 16.6.10.1.5.

Чтобы вернуться к использованию нестойкой статистики, Вы можете изменить таблицы, используя ALTER TABLE tbl_name STATS_PERSISTENT=0. Для соответствующей информации см. раздел 16.6.10.2.

16.6.10.1.1. Конфигурирование автоматического вычисления для постоянной статистики

Опция innodb_stats_auto_recalc, которая включена по умолчанию, определяет, вычислены ли статистические данные автоматически всякий раз, когда таблица подвергается существенным изменениям (больше, чем 10% строк). Вы можете также сконфигурировать автоматический перерасчет статистики для отдельных таблиц, используя параметр STATS_AUTO_RECALC в CREATE TABLE или ALTER TABLE. innodb_stats_auto_recalc включен по умолчанию.

Из-за асинхронной природы автоматического перерасчета статистики (который происходит в фоне), статистика не может быть повторно вычислена немедленно после выполнения работы DML, которая затрагивает больше, чем 10% таблицы, даже когда включен innodb_stats_auto_recalc. В некоторых случаях перерасчет статистики может быть отсрочен на несколько секунд. Если современные статистические данные требуются немедленно после изменения существенных частей таблицы, выполните ANALYZE TABLE, чтобы начать синхронный перерасчет статистики.

Если innodb_stats_auto_recalc отключен, гарантируйте точность статистики через ANALYZE TABLE для каждой применимой таблицы после существенных изменений индексированных столбцов. Вы могли бы выполнить этот запрос в своих скриптах после того, как представительные данные были загружены в таблицу, и периодически после того, как операции DML значительно изменяют содержание индексированных столбцов, или по графику во время низкой активности. Когда новый индекс добавлен к существующей таблице, статистика вычисленыа и добавлена к таблице innodb_index_stats независимо от значения innodb_stats_auto_recalc.

Чтобы гарантировать сбор статистики, когда новый индекс создается, включите innodb_stats_auto_recalc или выполните ANALYZE TABLE после создания каждого нового индекса, когда постоянный режим статистики включен.

16.6.10.1.2. Параметры статистики для отдельных таблиц

innodb_stats_persistent, innodb_stats_auto_recalc и innodb_stats_persistent_sample_pages глобальные параметры конфигурации. Чтобы переопределить эти настройки в масштабе всей системы и сконфигурировать параметры статистики для отдельных таблиц, Вы можете определить параметры STATS_PERSISTENT, STATS_AUTO_RECALC и STATS_SAMPLE_PAGES в CREATE TABLE или ALTER TABLE.

Все три пункта определены в следующем примере CREATE TABLE:

CREATE TABLE `t1` (`id` int(8) NOT NULL auto_increment,
                   `data` varchar(255), `date` datetime, PRIMARY KEY (`id`),
                   INDEX `DATE_IX` (`date`)) ENGINE=InnoDB,
                   STATS_PERSISTENT=1, STATS_AUTO_RECALC=1,
                   STATS_SAMPLE_PAGES=25;
16.6.10.1.3. Конфигурирование числа выбранных страниц для статистики InnoDB

MySQL запрашивают оцененную статистику использования ключевых распределений, чтобы выбрать индексирование для плана выполнения, основанное на относительной селективности индексирования. Такие операции, как ANALYZE TABLE просят InnoDB пробовать случайные страницы каждого индекса таблицы, чтобы оценить количество элементов индексирования. Этот метод известен как случайные погружения.

Чтобы дать Вам контроль над качеством оценки статистики (и таким образом лучшую информацию для запроса), Вы можете изменить число выбранных страниц, используя параметр innodb_stats_persistent_sample_pages, который может быть установлен во время выполнения.

innodb_stats_persistent_sample_pages имеет значение по умолчанию 20. Как общее руководство, рассмотрите изменение этого параметра, сталкиваясь со следующими проблемами:

  1. Statistics are not accurate enough and the optimizer chooses suboptimal plans в выводе EXPLAIN. Точность статистики может быть проверена, сравнивая фактическое количество элементов индексирования (как возвращено SELECT DISTINCT на столбцах индекса с оценками, обеспеченными таблице mysql.innodb_index_stats.

    Если решено, что статистические данные недостаточно точны, значение innodb_stats_persistent_sample_pages должно быть увеличено, пока оценки статистики не станут достаточно точными. Увеличение innodb_stats_persistent_sample_pages, однако, может вызвать замедление ANALYZE TABLE.

  2. ANALYZE TABLE работает медленно. В этом случае innodb_stats_persistent_sample_pages надо уменьшить до приемлемой скорости ANALYZE TABLE. Уменьшение значения, однако, могло привести к первой проблеме неточной статистики и подоптимальных планов выполнения запроса.

    Если баланс не может быть достигнут между точной статистикой и скоростью statistics and ANALYZE TABLE помните, что сокращение числа индексированных столбцов в таблице или ограничение числа разделов уменьшает сложность ANALYZE TABLE. Число столбцов в первичном ключе таблицы также важно, поскольку столбцы первичного ключа добавлены к каждому групповому индексу.

    Для соответствующей информации см. раздел 16.6.10.3.

16.6.10.1.4. Включение помеченных для удаления записей в вычисления статистики

По умолчанию InnoDB читает нейтральные данные, вычисляя статистику. В случае нейтральной транзакции, которая удаляет строки из таблицы, InnoDB исключает записи, которые отмечены как удаленные, вычисляя оценки строки и индексную статистику, которая может привести к неоптимальным планам выполнения относительно других транзакций, которые воздействуют на таблицу, одновременно используя операционный уровень изоляции, кроме READ UNCOMMITTED. Чтобы обойти эту ситуацию, опция innodb_stats_include_delete_marked может быть включена, чтобы гарантировать, что InnoDB добавляет записи, которые отмечены как удаленные, вычисляя постоянную статистику.

При включении innodb_stats_include_delete_marked ANALYZE TABLE рассматривает помеченные как удаленные записи, повторно вычисляя статистику.

innodb_stats_include_delete_marked глобальная установка, которая затрагивает все таблицы. Это применимо только к постоянной статистике. innodb_stats_include_delete_marked была введена в MySQL 8.0.1.

16.6.10.1.5. Постоянные таблицы статистики InnoDB

Постоянная статистика полагается на таблицы innodb_table_stats и innodb_index_stats в базе данных mysql. Эти таблицы настроены автоматически в ходе установки и обновления.

Таблица 16.3. Столбцы innodb_table_stats

Имя столбцаОписание
database_nameИмя базы данных
table_nameИмя таблицы, имя раздела или подраздела
last_updatetimestamp, указывающий последнее время обновления этой строки
n_rowsЧисло строк в таблице
clustered_index_size Размер первичного индекса в страницах
sum_of_other_index_sizes Полный размер других (не первичных) индексов в страницах

Таблица 16.4. Столбцы innodb_index_stats

СтолбецОписание
database_nameИмя базы данных
table_nameИмя таблицы, имя раздела или подраздела
index_nameИмя индекса
last_updatetimestamp, указывающий последнее время обновления этой строки
stat_nameНазвание статистической величины, о значении которой сообщают в столбце stat_value
stat_valueЗначение статистической величины, которая названа в столбце stat_name
sample_sizeЧисло страниц, выбранных для оценки величины в столбце stat_value
stat_description Описание статистической величины, которую называют в столбце stat_name

Таблицы innodb_table_stats и innodb_index_stats включают столбец last_update, показывающий, когда InnoDB в последний раз обновлени индексную статистику, как показано в следующем примере:

mysql> select * from innodb_table_stats \G
*************************** 1. row ***************************
 database_name: sakila
table_name: actor
   last_update: 2014-05-28 16:16:44
n_rows: 200
clustered_index_size: 1
sum_of_other_index_sizes: 1
...

mysql> select * from innodb_index_stats \G
*************************** 1. row ***************************
   database_name: sakila
  table_name: actor
  index_name: PRIMARY
 last_update: 2014-05-28 16:16:44
   stat_name: n_diff_pfx01
  stat_value: 200
 sample_size: 1
 ...

Таблицы innodb_table_stats и innodb_index_stats это обычные таблицы и могут быть обновлены вручную. Способность обновить статистику вручную позволяет вызвать определенный план оптимизации запроса или проверить альтернативные планы, не изменяя базу данных. Если Вы вручную обновляете статистику, скомандуйте FLUSH TABLE tbl_name, чтобы заставить MySQL перезагрузить обновленную статистику.

16.6.10.1.6. Пример постоянной табличной статистики InnoDB

Таблица innodb_table_stats содержит одну строку на таблицу. Собранные данные продемонстрированы в следующем примере.

Таблица t1 содержит первичный индекс (столбцы a, b), вторичный индекс (столбцы c, d) и уникальный индекс (столбцы e, f):

CREATE TABLE t1 (a INT, b INT, c INT, d INT, e INT, f INT,
       PRIMARY KEY (a, b), KEY i1 (c, d),
       UNIQUE KEY i2uniq (e, f)) ENGINE=INNODB;

После вставки пяти строк типовых данных таблица выглядит так:

mysql> SELECT * FROM t1;
+---+---+----+----+-----+-----+
| a | b | c  | d  | e   | f   |
+---+---+----+----+-----+-----+
| 1 | 1 | 10 | 11 | 100 | 101 |
| 1 | 2 | 10 | 11 | 200 | 102 |
| 1 | 3 | 10 | 11 | 100 | 103 |
| 1 | 4 | 10 | 12 | 200 | 104 |
| 1 | 5 | 10 | 12 | 100 | 105 |
+---+---+----+----+-----+-----+

Чтобы немедленно обновить статистику, скомандуйте ANALYZE TABLE (если включена innodb_stats_auto_recalc, статистические данные обновлены автоматически в течение нескольких секунд, предполагая, что порог 10% для измененных строк таблицы достигнут):

mysql> ANALYZE TABLE t1;
+---------+---------+----------+----------+
| Table   | Op      | Msg_type | Msg_text |
+---------+---------+----------+----------+
| test.t1 | analyze | status   | OK       |
+---------+---------+----------+----------+

Табличная статистика для таблицы показывает: обновлена в последний раз 2014-03-14 14:36:34, число строк в таблице (5), размер кластеризируемого индекса (1 страница) и объединенный размер других индексов (2 страницы).

mysql> SELECT * FROM mysql.innodb_table_stats WHERE table_name like 't1'\G
*************************** 1. row ***************************
 database_name: test
table_name: t1
   last_update: 2014-03-14 14:36:34
n_rows: 5
clustered_index_size: 1
sum_of_other_index_sizes: 2

Таблица innodb_index_stats содержит многократные строки для каждого индекса. Каждая строка в таблице innodb_index_stats обеспечивает, данные, связанные с индексируемой статистической величиной, которую называют в столбце stat_name и описывают в stat_description, например:

mysql> SELECT index_name, stat_name, stat_value, stat_description
    ->        FROM mysql.innodb_index_stats WHERE table_name like 't1';
+------------+--------------+------------+-----------------------------------+
| index_name | stat_name    | stat_value | stat_description                  |
+------------+--------------+------------+-----------------------------------+
| PRIMARY    | n_diff_pfx01 | 1          | a                                 |
| PRIMARY    | n_diff_pfx02 | 5          | a,b                               |
| PRIMARY    | n_leaf_pages | 1          | Number of leaf pages in the index |
| PRIMARY    | size         | 1          | Number of pages in the index      |
| i1         | n_diff_pfx01 | 1          | c                                 |
| i1         | n_diff_pfx02 | 2          | c,d                               |
| i1         | n_diff_pfx03 | 2          | c,d,a                             |
| i1         | n_diff_pfx04 | 5          | c,d,a,b                           |
| i1         | n_leaf_pages | 1          | Number of leaf pages in the index |
| i1         | size         | 1          | Number of pages in the index      |
| i2uniq     | n_diff_pfx01 | 2          | e                                 |
| i2uniq     | n_diff_pfx02 | 5          | e,f                               |
| i2uniq     | n_leaf_pages | 1          | Number of leaf pages in the index |
| i2uniq     | size         | 1          | Number of pages in the index      |
+------------+--------------+------------+-----------------------------------+

Столбец stat_name показывает следующие типы статистики:

Далее n_diff_pfxNN это статистическая величина, которая обеспечивает данные о количестве элементов, рассматриваемых в примере таблицы t1. Как показано ниже, таблица t1 составлена с первичным индексом (столбцы a, b), вторичным индексом (столбцы c, d) и уникальным индексом (столбцы e, f):

CREATE TABLE t1 (a INT, b INT, c INT, d INT, e INT, f INT,
       PRIMARY KEY (a, b), KEY i1 (c, d),
       UNIQUE KEY i2uniq (e, f)) ENGINE=INNODB;

После вставки пяти строк типовых данных таблица выглядит так:

mysql> SELECT * FROM t1;
+---+---+----+----+-----+-----+
| a | b | c  | d  | e   | f   |
+---+---+----+----+-----+-----+
| 1 | 1 | 10 | 11 | 100 | 101 |
| 1 | 2 | 10 | 11 | 200 | 102 |
| 1 | 3 | 10 | 11 | 100 | 103 |
| 1 | 4 | 10 | 12 | 200 | 104 |
| 1 | 5 | 10 | 12 | 100 | 105 |
+---+---+----+----+-----+-----+

Когда Вы запрашиваете index_name, stat_name, stat_value и stat_description, где stat_name LIKE 'n_diff%', следующий набор результатов возвращен:

mysql> SELECT index_name, stat_name, stat_value, stat_description
    ->        FROM mysql.innodb_index_stats
    ->        WHERE table_name like 't1' AND stat_name LIKE 'n_diff%';
+------------+--------------+------------+------------------+
| index_name | stat_name    | stat_value | stat_description |
+------------+--------------+------------+------------------+
| PRIMARY    | n_diff_pfx01 | 1          | a                |
| PRIMARY    | n_diff_pfx02 | 5          | a,b              |
| i1         | n_diff_pfx01 | 1          | c                |
| i1         | n_diff_pfx02 | 2          | c,d              |
| i1         | n_diff_pfx03 | 2          | c,d,a            |
| i1         | n_diff_pfx04 | 5          | c,d,a,b          |
| i2uniq     | n_diff_pfx01 | 2          | e                |
| i2uniq     | n_diff_pfx02 | 5          | e,f              |
+------------+--------------+------------+------------------+

Для индекса PRIMARY есть две строки n_diff%. Число строк равно числу столбцов в индексировании.

Для группового индекса InnoDB добавляет столбцы первичного ключа.

Для вторичного индекса (i1) есть четыре строки n_diff%. Только два столбца определены для вторичного индекса (c,d), но есть четыре строки n_diff% для него, потому что InnoDB соединяет все групповые индексы с первичным ключом. В результате есть четыре строки n_diff% вместо двух, чтобы сосчитать оба столбца вторичного индекса (c,d) и столбцы первичного ключа (a,b).

Для уникального индекса (i2uniq) есть две строки n_diff%.

16.6.10.1.7. Получение размера индекса, используя таблицу innodb_index_stats

Размер индекса для таблицы, раздела или подраздела может быть получен, используя таблицу innodb_index_stats. В следующем примере размеры индексов получены для таблицы t1. Для определения таблицы t1 и соответствующей статистики см. раздел 16.6.10.1.6.

mysql> SELECT SUM(stat_value) pages, index_name,
    ->        SUM(stat_value)*@@innodb_page_size size
    ->        FROM mysql.innodb_index_stats WHERE table_name='t1' AND
    ->        stat_name = 'size' GROUP BY index_name;
+-------+------------+-------+
| pages | index_name | size  |
+-------+------------+-------+
| 1     | PRIMARY    | 16384 |
| 1     | i1         | 16384 |
| 1     | i2uniq     | 16384 |
+-------+------------+-------+

Для раздела или подраздела подойдет тот же запрос, но с измененным WHERE. Например, следующий запрос получает размеры индексов для раздела таблицы t1:

mysql> SELECT SUM(stat_value) pages, index_name,
    ->        SUM(stat_value)*@@innodb_page_size size
    ->        FROM mysql.innodb_index_stats
                 WHERE table_name like 't1#P%' AND
    ->        stat_name = 'size' GROUP BY index_name;

16.6.10.2. Конфигурирование нестойких параметров статистики

Этот раздел описывает, как сконфигурировать нестойкую статистику. Статистические данные не сохранены на диске, когда innodb_stats_persistent=OFF или когда отдельные таблицы составлены или изменены с STATS_PERSISTENT=0 . Вместо этого статистические данные сохранены в памяти и потеряны, когда сервер закрыт. Статистические данные также периодически обновляются определенными операциями и при определенных условиях.

Статистические данные сохранены на диск по умолчанию при включении опции innodb_stats_persistent. Для информации о постоянной статистике см. раздел 16.6.10.1 .

Обновления статистики

Статистические данные обновлены когда:

Конфигурирование числа выбранных страниц

Оптимизатор MySQL запрашивают оцененную статистику о ключевых распределениях, чтобы выбрать индексирование для плана выполнения, основанного на относительной селективности индекса. Когда InnoDB обновляет статистику, это пробует случайные страницы от каждого индекса в таблицы, чтобы оценить количество элементов индекса. Этот метод известен как случайные погружения.

Чтобы дать Вам контроль над качеством оценки статистики (и таким образом лучшую информацию для запроса), Вы можете изменить число выбранных страниц, используя параметр innodb_stats_transient_sample_pages. Число значения по умолчанию выбранных страниц 8 может быть недостаточным, чтобы произвести точную оценку. Этот метод особенно важен для больших таблиц и таблиц, используемых в joins. Ненужное полное сканирование таблицы для таких таблиц может быть существенной исполнительной проблемой. См. раздел 9.2.1.21 для подсказок относительно настройки таких запросов. innodb_stats_transient_sample_pages глобальный параметр, который может быть установлен во время выполнения.

Значение innodb_stats_transient_sample_pages влияет на осуществление выборки для всех таблиц и нидексов InnoDB, когда innodb_stats_persistent=0. Знайте о следующем потенциально существенном влиянии, когда Вы изменяете объем выборки:

Выберите значение, которое приводит к разумно точным оценкам для всех таблиц в Вашей базе данных, не требуя чрезмерного ввода/вывода. Поскольку статистические данные автоматически повторно вычислены неоднократно кроме выполнения ANALYZE TABLE, не имеет смысла увеличивать объем выборки, запуская ANALYZE TABLE, уменьшите объем выборки.

Меньшие таблицы вообще требуют меньшие образцы индекса, чем большие таблицы. Если у Вашей базы данных есть много больших таблиц, рассмотрите использование более высокого значения для innodb_stats_transient_sample_pages, чем если бы у Вас есть главным образом маленькие таблицы.

16.6.10.3. Оценка сложности ANALYZE TABLE для таблиц InnoDB

Сложность ANALYZE TABLE для таблицы InnoDB зависит от:

Используя эти параметры, приблизительная формула для того, чтобы оценить сложность ANALYZE TABLE:

Значение innodb_stats_persistent_sample_pages * число индексированных столбцов в таблице * число разделов.

Как правило, чем больше получающееся значение, тем больше время выполнения для ANALYZE TABLE.

innodb_stats_persistent_sample_pages определяет число страниц, выбранных на глобальном уровне. Чтобы определить число страниц, выбранных для отдельной таблицы, используйте опцию STATS_SAMPLE_PAGES в CREATE TABLE или ALTER TABLE. Подробности в разделе 16.6.10.1.

Если innodb_stats_persistent=OFF, число выбранных страниц определено innodb_stats_transient_sample_pages. См. раздел 16.6.10.2.

Для более всестороннего подхода к оценке сложности ANALYZE TABLE рассмотрите следующий пример.

В записи Big O сложность ANALYZE TABLE описана как:

O(n_sample * (n_cols_in_uniq_i + n_cols_in_non_uniq_i + n_cols_in_pk *
 (1 + n_non_uniq_i)) * n_part)

Здесь:

Теперь, рассмотрите следующую таблицу (таблица t), у которой есть первичный ключ (2 столбца), уникальный индекс (2 столбца) и два групповых индекса (по два столбца каждый):

CREATE TABLE t (a INT, b INT, c INT, d INT, e INT, f INT, g INT, h INT,
                PRIMARY KEY (a, b), UNIQUE KEY i1uniq (c, d),
                KEY i2nonuniq (e, f), KEY i3nonuniq (g, h));

Для данных столбца и индекса, требуемых алгоритмом, описанным выше, запрашивают постоянный индекс статистики из mysql.innodb_index_stats для таблицы t. Статистические данные n_diff_pfx% показывают столбцы, которые посчитаны для каждого индекса. Например, столбцы a и b посчитаны для индекса первичного ключа. Для неуникальных индексов столбцы первичного ключа (a,b) посчитаны в дополнение к определяемым пользователем столбцам.

Для дополнительной информации о постоянных таблицах статистики InnoDB см. раздел 16.6.10.1.

SELECT index_name, stat_name, stat_description FROM mysql.innodb_index_stats
       WHERE database_name='test' AND table_name='t' AND
       stat_name like 'n_diff_pfx%';
+------------+--------------+------------------+
| index_name | stat_name    | stat_description |
+------------+--------------+------------------+
| PRIMARY    | n_diff_pfx01 | a                |
| PRIMARY    | n_diff_pfx02 | a,b              |
| i1uniq     | n_diff_pfx01 | c                |
| i1uniq     | n_diff_pfx02 | c,d              |
| i2nonuniq  | n_diff_pfx01 | e                |
| i2nonuniq  | n_diff_pfx02 | e,f              |
| i2nonuniq  | n_diff_pfx03 | e,f,a            |
| i2nonuniq  | n_diff_pfx04 | e,f,a,b          |
| i3nonuniq  | n_diff_pfx01 | g                |
| i3nonuniq  | n_diff_pfx02 | g,h              |
| i3nonuniq  | n_diff_pfx03 | g,h,a            |
| i3nonuniq  | n_diff_pfx04 | g,h,a,b          |
+------------+--------------+------------------+

Основываясь на индексных данных о статистике, показанных выше, и табличном определении, следующие значения могут быть определены:

Вы можете теперь вычислить innodb_stats_persistent_sample_pages * (2 + 4 + 2 * (1 + 2)) * 1, чтобы определить число страниц, которые отсканированы. С установкой innodb_stats_persistent_sample_pages в значение по умолчанию 20 и с размером страницы по умолчанию 16 KiB ( innodb_page_size=16384) Вы можете тогда оценить, что 20 * 12 * 16384 байт считаны из таблицы t или приблизительно 4 MiB.

Все 4 MiB возможно, не будут считаны с диска, поскольку некоторые страницы могут уже кэшироваться в буферном пуле.

16.6.11. Конфигурирование порога слияния для индексных страниц

Вы можете сконфигурировать значение MERGE_THRESHOLD для индексных страниц. Если процент полных страниц для индексной страницы падает ниже MERGE_THRESHOLD, когда строка удалена или сокращена через UPDATE, InnoDB пробует слить индексную страницу с соседней индексной страницей. Значение по умолчанию MERGE_THRESHOLD 50, что является ранее неизменным значением. Минимум MERGE_THRESHOLD 1 и максимальное значение 50.

Когда процент полных страниц для индексной страницы падает ниже 50%, что является значением по умолчанию для MERGE_THRESHOLD, InnoDB пробует слить индексную страницу с соседней страницей. Если обе страницы близки к полным 50%, разделение страницы может произойти вскоре после того, как страницы слиты. Если это происходит часто, у него может быть неблагоприятное влияние на производительность. Чтобы избежать частых разделений слияния, Вы можете понизить MERGE_THRESHOLD так, чтобы InnoDB сливал страницы при более низком проценте полных страниц. Слияние страниц в более низком проценте полной страницы освобождает больше места в индексных страницах и помогает уменьшить разделение после слияния.

MERGE_THRESHOLD для индексных страниц может быть определен для таблицы или индекса. MERGE_THRESHOLD для отдельного индекса берет приоритет над MERGE_THRESHOLD для таблицы. Если не определен, значение MERGE_THRESHOLD по умолчанию 50.

Установка MERGE_THRESHOLD для таблицы

Вы можете установить значение MERGE_THRESHOLD для таблицы, используя предложение параметр COMMENT в CREATE TABLE:

CREATE TABLE t1 (id INT, KEY id_index (id)) COMMENT='MERGE_THRESHOLD=45';

Вы можете также установить значение MERGE_THRESHOLD для существующей таблицы, используя параметр COMMENT в ALTER TABLE:

CREATE TABLE t1 (id INT, KEY id_index (id));
ALTER TABLE t1 COMMENT='MERGE_THRESHOLD=40';

Задание MERGE_THRESHOLD для индекса

Установить значение MERGE_THRESHOLD для индекса можно через параметр COMMENT в запросах CREATE TABLE, ALTER TABLE или CREATE INDEX:

CREATE TABLE t1 (id INT, KEY id_index (id) COMMENT 'MERGE_THRESHOLD=40');

Или:

CREATE TABLE t1 (id INT, KEY id_index (id));
ALTER TABLE t1 DROP KEY id_index;
ALTER TABLE t1 ADD KEY id_index (id) COMMENT 'MERGE_THRESHOLD=40';

Или:

CREATE TABLE t1 (id INT);
CREATE INDEX id_index ON t1 (id) COMMENT 'MERGE_THRESHOLD=40';

Вы не можете изменить MERGE_THRESHOLD на уровне индекса для GEN_CLUST_INDEX, который является кластеризируемым индексом, создаваемым InnoDB, когда таблица составлена без первичного ключа или индекса уникального ключа. Вы можете только изменить MERGE_THRESHOLD для GEN_CLUST_INDEX установкой MERGE_THRESHOLD для таблицы.

Запрос значения MERGE_THRESHOLD для индекса

Текущее значение MERGE_THRESHOLD для индекса может быть получено, запрашивая таблицу INNODB_SYS_INDEXES:

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES
                   WHERE NAME='id_index' \G
*************************** 1. row ***************************
   INDEX_ID: 91
 NAME: id_index
   TABLE_ID: 68
 TYPE: 0
   N_FIELDS: 1
PAGE_NO: 4
SPACE: 57
MERGE_THRESHOLD: 40

Вы можете использовать SHOW CREATE TABLE, чтобы посмотреть значение MERGE_THRESHOLD для таблицы, если явно определено, используя предложение table_option COMMENT:

mysql> SHOW CREATE TABLE t2 \G
*************************** 1. row ***************************
   Table: t2
Create Table: CREATE TABLE `t2` (
  `id` int(11) DEFAULT NULL,
  KEY `id_index` (`id`) COMMENT 'MERGE_THRESHOLD=40'
) ENGINE=InnoDB DEFAULT CHARSET=latin1

MERGE_THRESHOLD для индексного уровня берет приоритет над MERGE_THRESHOLD уровня таблицы. Если не определено, то 50% (MERGE_THRESHOLD=50).

Аналогично, Вы можете использовать SHOW INDEX для просмотра MERGE_THRESHOLD для индексирования, если явно определено, используя COMMENT:

mysql> SHOW INDEX FROM t2 \G
*************************** 1. row ***************************
Table: t2
   Non_unique: 1
 Key_name: id_index
 Seq_in_index: 1
  Column_name: id
Collation: A
  Cardinality: 0
 Sub_part: NULL
   Packed: NULL
 Null: YES
   Index_type: BTREE
  Comment:
Index_comment: MERGE_THRESHOLD=40

Измерение эффекта MERGE_THRESHOLD

Таблица INNODB_METRICS обеспечивает два счетчика, которые могут использоваться, чтобы измерить эффект MERGE_THRESHOLD на слияниях индексной страницы.

mysql> SELECT NAME, COMMENT FROM INFORMATION_SCHEMA.INNODB_METRICS
                 WHERE NAME like '%index_page_merge%';
+-----------------------------+----------------------------------------+
| NAME                        | COMMENT                                |
+-----------------------------+----------------------------------------+
| index_page_merge_attempts   | Number of index page merge attempts    |
| index_page_merge_successful | Number of successful index page merges |
+-----------------------------+----------------------------------------+

Понижение значения MERGE_THRESHOLD дает:

Установка MERGE_THRESHOLD, которая является слишком маленькой, могла привести к большим файлам с данными из-за чрезмерного количества пустого пространства страницы.

Для информации об использовании счетчиков INNODB_METRICS см. раздел 16.14.6 .

16.7. Табличные пространства InnoDB

16.7.1. Изменение размеров системного табличного пространства InnoDB

Этот раздел описывает, как увеличить или уменьшить системное табличное пространство InnoDB.

Увеличение размера системного табличного пространства InnoDB

Самый легкий способ увеличить размер системного табличного пространства это сконфигурировать его сначала на авторасширение. Определите атрибут autoextend для последнего файла с данными в определении табличного пространства. Тогда InnoDB увеличивает размер этого файла автоматически порциями по 64MB, когда это исчерпывает пространство. Размер порции может быть изменен, устанавливая значение innodb_autoextend_increment, которая измерена в мегабайтах.

Вы можете расширить системное табличное пространство определенным количеством, добавляя другой файл с данными:

  1. Закройте сервер MySQL.

  2. Если предыдущий последний файл с данными определен с ключевым словом autoextend, измените его определение, чтобы использовать фиксированный размер, основанный на том, как это фактически выросло. Проверьте размер файла с данными, округлите это в меньшую сторону к самому близкому числу, кратному 1024*1024 байт (=1MB), и определите этот округленный размер явно в innodb_data_file_path .
  3. Добавьте новый файл с данными в конец innodb_data_file_path, произвольно делая автомасштабирование файла. Только последний файл с данными в innodb_data_file_path может быть определен как автомасштабируемый.
  4. Запустите сервер MySQL снова.

Например, у этого табличного пространства есть только один автомасштабируемый файл с данными ibdata1:

innodb_data_home_dir =
innodb_data_file_path = /ibdata/ibdata1:10M:autoextend

Предположите, что этот файл с данными в течение долгого времени вырос до 988MB. Вот строка конфигурации после изменения оригинального файла с данными, чтобы использовать фиксированный размер и добавления нового файла:

innodb_data_home_dir =
innodb_data_file_path = /ibdata/ibdata1:988M;/disk2/ibdata2:50M:autoextend

Когда Вы добавляете новый файл с данными к системной конфигурации табличного пространства, удостоверьтесь, что имя файла не обращается к существующему файлу. InnoDB создает и инициализирует файл, когда Вы перезапускаете сервер.

Уменьшение размера системного табличного пространства InnoDB

Вы не можете удалить файл с данными из системного табличного пространства. Чтобы уменьшить размер табличного пространства, используйте эту процедуру:

  1. Используйте mysqldump, чтобы вывести в дамп все Ваши таблицы InnoDB, включая таблицы InnoDB, расположенные в базе данных MySQL.

    mysql> select table_name from information_schema.tables
                     where table_schema='mysql' and engine='InnoDB';
    +---------------------------+
    | table_name                |
    +---------------------------+
    | columns_priv              |
    | db                        |
    | engine_cost               |
    | gtid_executed             |
    | help_category             |
    | help_keyword              |
    | help_relation             |
    | help_topic                |
    | innodb_index_stats        |
    | innodb_table_stats        |
    | plugin                    |
    | procs_priv                |
    | proxies_priv              |
    | server_cost               |
    | servers                   |
    | slave_master_info         |
    | slave_relay_log_info      |
    | slave_worker_info         |
    | tables_priv               |
    | time_zone                 |
    | time_zone_leap_second     |
    | time_zone_name            |
    | time_zone_transition      |
    | time_zone_transition_type |
    | user                      |
    +---------------------------+
    
  2. Остановите сервер.
  3. Удалите все существующие файлы табличного пространства (*.ibd), включая ibdata и ib_log. Не забывайте удалять *.ibd для таблиц, расположенных в базе данных MySQL.
  4. Сконфигурируйте новое табличное пространство.
  5. Перезапустите сервер.
  6. Импортируйте файлы дампа.

Если Ваши базы данных используют только механизм InnoDB, может быть более просто вывести в дамп все базы данных, остановить сервер, удалить все базы данных и файлы системного журнала InnoDB, перезапустить сервер и импортировать файлы дампа.

16.7.2. Изменение числа или размера файлов системного журнала Redo

Изменить число или размер файлов журнала redo можно так:

  1. Остановите сервер MySQL и удостоверьтесь, что он закрывается без ошибок.

  2. Отредактируйте my.cnf, чтобы изменить конфигурацию файла системного журнала. Чтобы изменить размер файла системного журнала, надо сконфигурировать innodb_log_file_size. Чтобы увеличить число файлов системного журнала, надо сконфигурировать innodb_log_files_in_group.
  3. Запустите сервер MySQL снова.

Если InnoDB обнаруживает, что innodb_log_file_size отличается от размера файла системного журнала, это напишет контрольную точку журнала, закроет и удалит старые файлы, создаст новые файлы в требуемом размере и откроет их.

16.7.3. Использование сырого дискового раздела для системного табличного пространства

Вы можете использовать сырой раздел в качестве файлов с данными в системном табличном пространстве InnoDB. Этот метод включает небуферизованный вводу/выводу в Windows и некоторых системах Linux и Unix без издержек файловой системы. Выполните тесты с и без сырого разделения, чтобы проверить, улучшает ли это изменение фактически работу относительно Вашей системы.

Когда Вы используете сырой дисковый раздел, гарантируете, что пользовательский ID, который выполняет сервер MySQL, имеет привилегии чтения и записи для того раздела. Например, если Вы выполняете сервер как mysql, раздел должен быть читаем и записываем для mysql. Если Вы выполняете сервер с опцией --memlock, сервер должен быть выполнен как root, таким образом, раздел должен быть доступен для root.

Процедуры, описанные ниже, вовлекают модификацию файла опции. Для дополнительной информации см. раздел 5.2.6.

Выделение сырого дискового раздела на системах Linux и Unix

  1. Когда Вы создаете новый файл с данными, определите ключевое слово newraw сразу после размера файла с данными для опции innodb_data_file_path. Раздел должен быть, по крайней мере, столь же большим как размер, который Вы определяете.

    [mysqld]
    innodb_data_home_dir=
    innodb_data_file_path=/dev/hdd1:3Gnewraw;/dev/hdd2:2Gnewraw
    
  2. Перезапустите сервер. InnoDB найдет ключевое слово newraw и инициализирует новый раздел. Однако, не создавайте или изменяйте таблицы. Иначе, когда Вы затем перезапускаете сервер, InnoDB повторно инициализирует раздел, и Ваши изменения потеряны. Как мера по безопасности InnoDB препятствует тому, чтобы пользователи изменили данные, когда любой раздел определен с newraw.
  3. После того, как InnoDB инициализировал новый раздел, остановите сервер и измените newraw на raw:
    [mysqld]
    innodb_data_home_dir=
    innodb_data_file_path=/dev/hdd1:3Graw;/dev/hdd2:2Graw
    
  4. Перезапустите сервер. InnoDB теперь разрешает вносить любые изменения.

Выделение сырого дискового раздела в Windows

В Windows те же самые шаги , описанные для систем Linux и Unix, применяются за исключением того, что innodb_data_file_path расходится немного в Windows.

  1. Когда Вы создаете новый файл с данными, определите ключевое слово newraw сразу после размера файла с данными для опции innodb_data_file_path:

    [mysqld]
    innodb_data_home_dir=
    innodb_data_file_path=//./D::10Gnewraw
    

    //./ соответствует синтаксису Windows \\.\ для того, чтобы получить доступ к физическим дискам. В примере выше D: имя диска раздела.

  2. Перезапустите сервер. InnoDB найдет ключевое слово newraw и инициализирует новый раздел.
  3. После этого остановите сервер и измените newraw на raw:
    [mysqld]
    innodb_data_home_dir=
    innodb_data_file_path=//./D::10Graw
    
  4. Перезапустите сервер. InnoDB теперь может работать.

16.7.4. Табличные пространства InnoDB File-Per-Table

Исторически все таблицы и индексы InnoDB были сохранены в системном табличном пространстве. Этот монолитный подход был хорош в машинах, посвященных полностью обработке базы данных, с тщательно запланированным ростом данных, где любое дисковое хранение, выделенное MySQL, никогда не будет необходимо в других целях. Табличное пространство InnoDB's file-per-table обеспечивает более гибкую альтернативу, где каждая таблица и индекс InnoDB сохранены в отдельном файле .ibd. Каждый такой файл .ibd представляет отдельное табличное пространство. Этой особенностью управляет опция innodb_file_per_table, которая включена по умолчанию.

Преимущества табличных пространств File-Per-Table

Потенциальные недостатки табличных пространств File-Per-Table

16.7.4.1. Включение и отключение табличных пространств File-Per-Table

Опция innodb_file_per_table включена по умолчанию.

Установить innodb_file_per_table можно как параметр командной строки --innodb_file_per_table или добавив строку в раздел [mysqld] файла my.cnf:

[mysqld]
innodb_file_per_table=1

Вы можете также установить innodb_file_per_table динамически, в то время как сервер работает:

SET GLOBAL innodb_file_per_table=1;

При включении innodb_file_per_table Вы можете сохранить таблицы InnoDB в файл tbl_name.ibd. В отличие от механизма хранения MyISAM с его отдельными файлами tbl_name.MYD и tbl_name.MYI, InnoDB хранит данные и индексы вместе в файле .ibd.

При выключении innodb_file_per_table в Ваших опциях запуска и перезапуске сервера или отключении этого через SET GLOBAL, InnoDB составляет новые таблицы в системном табличном пространстве, если Вы явно не поместили таблицу в табличное пространство file-per-table или общее табличное пространство, используя опцию CREATE TABLE ... TABLESPACE.

Вы можете всегда читать и писать любую таблицу InnoDB, независимо от установки file-per-table.

Чтобы переместить таблицу из системного табличного пространства в свое, измените innodb_file_per_table и пересоздайте таблицу:

SET GLOBAL innodb_file_per_table=1;
ALTER TABLE table_name ENGINE=InnoDB;

Таблицы, добавленные к системному табличному пространству через CREATE TABLE ... TABLESPACE или ALTER TABLE ... TABLESPACE не затронуты innodb_file_per_table. Чтобы переместить эти таблицы из системного табличного пространства в свое табличное пространство, они должны быть перемещены явно, используя ALTER TABLE ... TABLESPACE.

InnoDB всегда нуждается в системном табличном пространстве, потому что помещает свой внутренний словарь данных и журналы отмены там. Файлы .ibd недостаточны для работы InnoDB.

Когда таблица перемещена из системного табличного пространства в свое, файлы с данными, которые составляют системное табличное пространство, остаются того же самого размера. Место, прежде занятое таблицей, может быть снова использовано для новых данных, но не для использования операционной системой. Перемещая большие таблицы из системного табличного пространства, где дисковое пространство ограничено, Вы можете предпочесть включить innodb_file_per_table и обновите весь экземпляр, применяя mysqldump. Как упомянуто выше, таблицы, добавленные к системному табличному пространству через CREATE TABLE ... TABLESPACE или ALTER TABLE ... TABLESPACE не затронуты настройкой innodb_file_per_table . Эти таблицы должны быть перемещены индивидуально.

16.7.5. Создание табличного пространства File-Per-Table вне каталога данных

Чтобы создать новое табличное пространство file-per-table в определенном местоположении вне каталога данных MySQL, используйте параметр DATA DIRECTORY = absolute_path_to_directory в CREATE TABLE.

Запланируйте местоположение заранее, потому что Вы не можете использовать DATA DIRECTORY с ALTER TABLE . Каталог, который Вы определяете, мог быть на другом устройстве хранения данных с особыми характеристиками, таком как быстрый SSD или особо большой HDD.

В пределах целевого каталога MySQL создает подкаталог, соответствующий имени базы данных, и в его пределах файл .ibd для новой таблицы.

Следующий пример демонстрирует создание табличного пространства file-per-table вне каталога данных MySQL. Это показывает .ibd, создаваемый в указанном каталоге.

mysql> USE test;
Database changed

mysql> SHOW VARIABLES LIKE 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+
1 row in set (0.00 sec)

mysql> CREATE TABLE t1 (c1 INT PRIMARY KEY)
                 DATA DIRECTORY = '/alternative/directory';
Query OK, 0 rows affected (0.03 sec)

# MySQL creates a .ibd file for the new table in a
# subdirectory that corresponding
# to the database name

db_user@ubuntu:~/alternative/directory/test$ ls
t1.ibd

Вы можете также использовать CREATE TABLE ... TABLESPACE в комбинации с DATA DIRECTORY, чтобы создать табличное пространство вне каталога данных MySQL. Чтобы сделать так, Вы должны определить innodb_file_per_table как имя табличного пространства.

CREATE TABLE t2 (c1 INT PRIMARY KEY) TABLESPACE = innodb_file_per_table
       DATA DIRECTORY = '/alternative/directory';

Вы не должны включать innodb_file_per_table, используя этот метод.

Примечания использования

16.7.6. Копирование табличных пространств к другому серверу

Этот раздел описывает, как скопировать табличные пространства file-per-table от одного сервера базы данных на другой. Свойство известно как мобильность. Эта особенность также поддерживает разделенные таблицы InnoDB.

Для информации о других методах копирования таблиц InnoDB см. раздел 16.8.3.

Есть много причин, почему Вы могли бы скопировать табличное пространство InnoDB file-per-table на другой сервер базы данных:

Ограничения и примечания использования

16.7.6.1. Мобильные примеры табличного пространства

Если Вы транспортируете таблицы, которые зашифрованы, используя шифрование табличного пространства см. здесь прежде, чем Вы начнете для дополнительной процедурной информации.

Пример 1: Копирование Таблицы InnoDB с одного сервера на другой

Эта процедура демонстрирует, как скопировать таблицу с одного экземпляра MySQL на другой. Та же самая процедура с незначительными корректировками может использоваться, чтобы выполнить полное табличное восстановление на том же самом сервере.

  1. На исходном сервере составьте таблицу, если ее нет:

    mysql> use test;
    mysql> CREATE TABLE t(c1 INT) engine=InnoDB;
    
  2. На целевом сервере составьте таблицу, если ее нет:
    mysql> use test;
    mysql> CREATE TABLE t(c1 INT) engine=InnoDB;
    
  3. На целевом сервере откажитесь от существующего табличного пространства. Прежде, чем табличное пространство сможет быть импортировано, InnoDB должен отказаться от табличного пространства, которое присоединено к таблице получения.
    mysql> ALTER TABLE t DISCARD TABLESPACE;
    
  4. На исходном сервере выполните FLUSH TABLES ... FOR EXPORT, чтобы создать метафайл .cfg с данными:
    mysql> use test;
    mysql> FLUSH TABLES t FOR EXPORT;
    

    Метафайл (.cfg) создается в каталоге данных InnoDB.

    FLUSH TABLES ... FOR EXPORT гарантирует, что изменения названной таблицы сброшены на диск так, чтобы двоичная табличная копия могла быть сделана в то время, как сервер работает. Когда выполняется FLUSH TABLES ... FOR EXPORT, InnoDB делает файл .cfg в том же самом каталоге базы данных, где таблица. Файл .cfg содержит метаданные, используемые для проверки схемы, импортируя файл табличного пространства.

  5. Скопируйте файлы .ibd и .cfg с исходного сервера на целевой:

    shell> scp /path/to/datadir/test/t.{ibd,cfg} destination-server:/path/to/datadir/test
    

    Файлы .ibd и .cfg должны быть скопированы прежде, чем выпустить совместно используемые блокировки, как описано в следующем шаге.

  6. На исходном сервере скомандуйте UNLOCK TABLES, чтобы выпустить блокировки, приобретенные FLUSH TABLES ... FOR EXPORT:

    mysql> use test;
    mysql> UNLOCK TABLES;
    
  7. На целевом сервере импортируйте табличное пространство:
    mysql> use test;
    mysql> ALTER TABLE t IMPORT TABLESPACE;
    

    ALTER TABLE ... IMPORT TABLESPACE не проводит в жизнь ограничения внешнего ключа на импортированные данные. Если есть ограничения внешнего ключа между таблицами, все таблицы должны быть экспортированы в том же самом (логическом) моменте времени. В этом случае Вы прекратите обновлять таблицы, закроете все транзакции, приобрете совместно используемые блокировки на таблицах и затем выполните экспортную работу.

Пример 2: Копирование разделенной таблицы InnoDB с одного сервера на другой

Эта процедура демонстрирует, как скопировать разделенную таблицу InnoDB с одного сервера на другой. Та же самая процедура с незначительными корректировками может использоваться, чтобы выполнить полное восстановление разделенной таблицы на том же самом сервере.

  1. На исходном сервере составьте разделенную таблицу, если ее нет. В следующем примере составлена таблица с тремя разделами (p0, p1, p2):

    mysql> use test;
    mysql> CREATE TABLE t1 (i int) ENGINE = InnoDB
                     PARTITION BY KEY (i) PARTITIONS 3;
    

    В каталоге /datadir/test Вы будете видеть отдельное табличное пространство (.ibd) для каждого из этих трех разделов.

    mysql> \! ls /path/to/datadir/test/
    t1#P#p0.ibd  t1#P#p1.ibd  t1#P#p2.ibd
    
  2. На целевом сервере составьте ту же самую разделенную таблицу:
    mysql> use test;
    mysql> CREATE TABLE t1 (i int) ENGINE = InnoDB
                     PARTITION BY KEY (i) PARTITIONS 3;
    

    В каталоге /datadir/test Вы будете видеть отдельное табличное пространство (.ibd) для каждого из этих трех разделов.

    mysql> \! ls /path/to/datadir/test/
    t1#P#p0.ibd  t1#P#p1.ibd  t1#P#p2.ibd
    
  3. На целевом сервере откажитесь от табличного пространства для разделенной таблицы. Прежде, чем табличное пространство сможет быть импортировано на целевом сервере, от табличного пространства, которое присоединено к таблице получения, нужно отказаться.
    mysql> ALTER TABLE t1 DISCARD TABLESPACE;
    

    Три файла .ibd, которые составляют табличное пространство для разделенной таблицы, исчезают из каталога /datadir/test.

  4. На исходном сервере выполните FLUSH TABLES ... FOR EXPORT, что создаст файл .cfg:
    mysql> use test;
    mysql> FLUSH TABLES t1 FOR EXPORT;
    

    Файлы данных, один для каждого табличного пространства (.ibd ), и метафайл (.cfg) создаются в каталоге /datadir/test на исходном сервере:

    mysql> \! ls /path/to/datadir/test/
    t1#P#p0.ibd  t1#P#p1.ibd  t1#P#p2.ibd
    t1#P#p0.cfg  t1#P#p1.cfg  t1#P#p2.cfg
    

    FLUSH TABLES ... FOR EXPORT гарантирует, что изменения названной таблицы сброшены на диск так, чтобы двоичная табличная копия могла быть сделана в то время, как сервер работает. Когда выполняется FLUSH TABLES ... FOR EXPORT, InnoDB создает файл .cfg с данными для файлов табличного пространства таблицы в том же самом каталоге базы данных, где таблица. .cfg содержат метаданные, используемые для проверки схемы, импортируя файлы табличного пространства. FLUSH TABLES ... FOR EXPORT может быть выполнен только на таблице, не на отдельном табличном разделе.

  5. Скопируйте файлы .ibd и .cfg на сервер назначения:

    shell> scp /path/to/datadir/test/t1*.{ibd,cfg}
                  destination-server:/path/to/datadir/test
    

    Файлы .ibd и .cfg должны быть скопированы прежде, чем выпустить совместно используемые блокировки, как описано в следующем шаге.

  6. На исходном сервере скомандуйте UNLOCK TABLES, чтобы снять блокировки, приобретенные FLUSH TABLES ... FOR EXPORT:

    mysql> use test;
    mysql> UNLOCK TABLES;
    
  7. На целевом сервере импортируйте табличное пространство для разделенной таблицы:
    mysql> use test;
    mysql> ALTER TABLE t1 IMPORT TABLESPACE;
    
Пример 3: Копирование табличного раздела с сервера на сервер

Эта процедура демонстрирует, как скопировать табличный раздел. Та же самая процедура с незначительными корректировками может использоваться, чтобы выполнить восстановление раздела. В следующем примере разделенная таблица с четырьмя разделами (p0, p1, p2, p3) составлена на исходном сервере. Два раздела (p2 и p3) скопированы целевому серверу.

  1. На исходном сервере составьте разделенную таблицу, если ее нет. В следующем примере составлена таблица с четырьмя разделами (p0, p1, p2, p3):

    mysql> use test;
    mysql> CREATE TABLE t1 (i int) ENGINE = InnoDB
                     PARTITION BY KEY (i) PARTITIONS 4;
    

    В каталоге /datadir/test Вы будете видеть отдельное табличное пространство (.ibd) для каждого из этих четырех разделов.

    mysql> \! ls /path/to/datadir/test/
    t1#P#p0.ibd  t1#P#p1.ibd  t1#P#p2.ibd t1#P#p3.ibd
    
  2. На целевом сервере составьте ту же самую разделенную таблицу:
    mysql> use test;
    mysql> CREATE TABLE t1 (i int) ENGINE = InnoDB
                     PARTITION BY KEY (i) PARTITIONS 4;
    

    В каталоге /datadir/test Вы будете видеть отдельное табличное пространство (.ibd) для каждого из этих четырех разделов.

    mysql> \! ls /path/to/datadir/test/
    t1#P#p0.ibd  t1#P#p1.ibd  t1#P#p2.ibd t1#P#p3.ibd
    
  3. На целевом сервере откажитесь от раздела табличного пространства, который Вы планируете импортировать с исходного сервера. Прежде, чем раздел табличного пространства сможет быть импортирован на целевом сервере, от соответствующего раздела, который присоединен к таблице получения, нужно отказаться.
    mysql> ALTER TABLE t1 DISCARD PARTITION p2, p3 TABLESPACE;
    

    Файлы .ibd для двух разделов, от которых отказываются, удалены из каталога /datadir/test на целевом сервере, оставляя следующие файлы:

    mysql> \! ls /path/to/datadir/test/
    t1#P#p0.ibd  t1#P#p1.ibd
    

    Когда ALTER TABLE ... DISCARD PARTITION ... TABLESPACE работает на разделенных таблицах имена таблиц и подразделов позволены. Когда имя раздела определено, подраздел того раздела включен в работу.

  4. На исходном сервере выполните FLUSH TABLES ... FOR EXPORT, чтобы получить файл .cfg.

    mysql> use test;
    mysql> FLUSH TABLES t1 FOR EXPORT;
    

    Файл (.cfg) для каждого раздела создается в каталоге /datadir/test на исходном сервере. Есть .cfg для каждого табличного пространства (.ibd).

    mysql> \! ls /path/to/datadir/test/
    t1#P#p0.ibd  t1#P#p1.ibd  t1#P#p2.ibd t1#P#p3.ibd
    t1#P#p0.cfg  t1#P#p1.cfg  t1#P#p2.cfg t1#P#p3.cfg
    

    FLUSH TABLES ... FOR EXPORT гарантирует, что изменения в названной таблице сброшены на диск так, чтобы двоичная табличная копия могла быть сделана в то время, как сервер работает. Когда FLUSH TABLES ... FOR EXPORT работает, InnoDB производит файл .cfg с данными для файлов табличного пространства таблицы в том же самом каталоге базы данных, где таблица. .cfg содержат метаданные, используемые для проверки схемы, импортируя файлы табличного пространства. FLUSH TABLES ... FOR EXPORT может быть выполнен только на таблице, не на отдельном табличном разделе.

  5. Скопируйте файлы .ibd и .cfg на сервер назначения. В этом примере только файлы .ibd and .cfg для разделов 2 (p2) и 3 (p3) скопированы в каталог data на сервере назначения. Другие разделы остаются на исходном сервере.

    shell> scp t1#P#p2.ibd  t1#P#p2.cfg t1#P#p3.ibd t1#P#p3.cfg \
                  destination-server:/path/to/datadir/test
    

    Файлы .ibd и .cfg должны быть скопированы прежде, чем выпустить совместно используемые блокировки, как описано в следующем шаге.

  6. На исходном сервере скомандуйте UNLOCK TABLES, чтобы выпустить блокировки, приобретенные FLUSH TABLES ... FOR EXPORT:

    mysql> use test;
    mysql> UNLOCK TABLES;
    
  7. На целевом сервере импортируйте разделы табличного пространства (p2 и p3):
    mysql> use test;
    mysql> ALTER TABLE t1 IMPORT PARTITION p2, p3 TABLESPACE;
    

    Когда ALTER TABLE ... DISCARD PARTITION ... TABLESPACE работает на разделенных таблицах имена таблиц и подразделов позволены. Когда имя раздела определено, подраздел того раздела включен в работу.

16.7.6.2. Мобильные внутренности табличного пространства

Следующая информация описывает внутренности и сообщения в журнале ошибок для процедуры копирования мобильных табличных пространств.

Когда ALTER TABLE ... DISCARD TABLESPACE выполнена на целевом сервере:

Когда FLUSH TABLES ... FOR EXPORT выполнен на исходном сервере:

Ожидаемые сообщения журнала ошибок для этой работы:

2013-09-24T13:10:19.903526Z 2 [Note] InnoDB: Sync to disk of '"test"."t"' started.
2013-09-24T13:10:19.903586Z 2 [Note] InnoDB: Stopping purge
2013-09-24T13:10:19.903725Z 2 [Note] InnoDB: Writing table metadata to './test/t.cfg'
2013-09-24T13:10:19.904014Z 2 [Note] InnoDB: Table '"test"."t"' flushed to disk

Когда UNLOCK TABLES выполнен на исходном сервере:

Ожидаемые сообщения журнала ошибок для этой работы:

2013-09-24T13:10:21.181104Z 2 [Note] InnoDB: Deleting the meta-data file
                              './test/t.cfg'
2013-09-24T13:10:21.181180Z 2 [Note] InnoDB: Resuming purge

Когда ALTER TABLE ... IMPORT TABLESPACE выполнен на целевом сервере, алгоритм импорта выполняет следующие операции для каждого импортируемого табличного пространства:

Ожидаемые сообщения журнала ошибок для этой работы:

2013-07-18 15:15:01 34960 [Note] InnoDB: Importing tablespace for table
                    'test/t' that was exported from host 'ubuntu'
2013-07-18 15:15:01 34960 [Note] InnoDB: Phase I - Update all pages
2013-07-18 15:15:01 34960 [Note] InnoDB: Sync to disk
2013-07-18 15:15:01 34960 [Note] InnoDB: Sync to disk - done!
2013-07-18 15:15:01 34960 [Note] InnoDB: Phase III - Flush changes to disk
2013-07-18 15:15:01 34960 [Note] InnoDB: Phase IV - Flush complete

Вы можете также получить предупреждение, что от табличного пространства отказываются (если Вы отказались от табличного пространства для целевой таблицы) и сообщение, что статистика не может быть вычислена из-за отсутствия файла .ibd:

2013-07-18 15:14:38 34960 [Warning] InnoDB: Table "test"."t" tablespace is
                    set as discarded.
2013-07-18 15:14:38 7f34d9a37700 InnoDB: cannot calculate statistics for
                    table "test"."t" because the .ibd file is missing.
                    For help, please refer to
http://dev.mysql.com/doc/refman/5.8/en/innodb-troubleshooting.html

16.7.7. Хранение журналов отмены в отдельных табличных пространствах

Вы можете сохранить журналы отмены в одном или более отдельных табличных пространствах отмены за пределами системного табличного пространства. Это расположение отличается от конфигурации значения по умолчанию, где журнал отмены это часть системного табличного пространства. Образцы ввода/вывода для журнала отмены делают эти табличные пространства хорошими кандидатами, чтобы переместить на SSD, сохраняя системное табличное пространство на жестком диске. Пользователи не могут удалить отдельные табличные пространства, создаваемые, чтобы хранить журналы или отдельные сегменты в тех табличных пространствах. Однако, журналы отмены, сохраненные в табличных пространствах отмены, могут быть усеченными. Для получения дополнительной информации см. раздел 16.7.8.

Поскольку эти файлы обрабатывают операции ввода/вывода, прежде сделанные в системном табличном пространстве, мы расширяем определение системного табличного пространства, чтобы включать эти новые файлы.

Журналы отмены также упоминаются как сегменты отмены.

Эта особенность вовлекает следующие новые или переименованные параметры конфигурации:

Поскольку особенность журнала отмены вовлекает установку двух нединамических переменных запуска ( innodb_undo_tablespaces и innodb_undo_directory), эта опция может быть активирована только инициализируя экземпляр MySQL.

Примечания

Чтобы использовать эту функцию:

  1. Выберите путь, где хранить журналы отмены. Вы определите путь как параметр innodb_undo_directory в Вашем конфигурационном файле MySQL или скрипте запуска. Если никакой путь не определен, табличные пространства отмены создаются в каталоге данных MySQL, как определено datadir.

  2. Выберите начальное значение для innodb_undo_logs . Вы можете запустить с относительно низким значением и увеличить его в течение долгого времени, чтобы исследовать эффект.

    Один журнал отмены всегда назначается на системное табличное пространство, и 32 журнала отмены сохранены для использования временными таблицами и размещены во временном табличном пространстве (ibtmp1). Поэтому, чтобы выделить журналы отмены для табличных пространств отмены, innodb_undo_logs должен быть установлен в значение, больше 33. Например, если у Вас есть два табличных пространства отмены ( innodb_undo_tablespaces=2), innodb_undo_logs должен быть установлен в 35, чтобы назначить один журнал отмены на каждое из двух табличных пространств отмены.

    Когда Вы конфигурируете отдельные табличные пространства отмены, журнал отмены в системном табличном пространстве бездействует.

  3. Выберите ненулевое значение для innodb_undo_tablespaces. Множественные журналы отмены, определенные innodb_undo_logs, разделены между этим числом отдельных табличных пространств (файлы .ibd ). Это значение установлено для жизни сервера MySQL, так что, если Вы не уверены в оптимальном значении, повысьте его.

  4. Создайте новый экземпляр MySQL, используя значения, которые Вы выбрали в конфигурационном файле или в Вашем скрипте запуска MySQL. Используйте реалистическую рабочую нагрузку с объемом данных, подобным Вашим производственным серверам. Альтернативно, используйте мобильную функцию табличных пространств, чтобы скопировать существующие таблицы базы данных к Вашему недавно сконфигурированному экземпляру MySQL. См. раздел 16.7.6.
  5. Определите эффективность исполнения ввода/вывода интенсивных рабочих нагрузок.
  6. Периодически увеличивайте значение innodb_undo_logs и повторно делайте тесты производительности. Найдите значение, где Вы прекращаете получать улучшение в работе ввода/вывода.
  7. Разверните новый производственный сервер, используя идеальные настройки для этих опций. Настройте это как ведомый сервер в репликации или возьмите данные с предыдущего сервера.

Соображения масштабируемости

Хранение журналов отмены позволяют MySQL осуществлять ввод/вывод и оптимизацию памяти, связанную с этими транзакционными данными. Например, потому что данные об отмене написаны на диск и затем редко используются (только в случае восстановления катастрофического отказа), это не должно быть сохранено в кэш-памяти файловой системы, в свою очередь позволяя более высокий процент системной памяти выделить буферному пулу.

Типичная передовая практика SSD: хранить системное табличное пространство на жестком диске и переместить табличные пространства per-table на SSD.

Внутренности

Физические файлы табличного пространства называют undoN, где N ID пространства, включая начальные нули.

Вы можете усечь журналы отмены, которые находятся в табличных пространствах отмены. Для получения дополнительной информации см. раздел 16.7.8.

16.7.8. Усечение журналов отмены, которые находятся в табличных пространствах отмены

Вы можете усечь журналы отмены, которые находятся в табличных пространствах отмены, при условии, что следующие условия верны:

Включение усечения табличных пространств отмены

Чтобы усечь журналы отмены, которые находятся в табличных пространствах отмены, Вы должны сначала включить innodb_undo_log_truncate.

mysql> SET GLOBAL innodb_undo_log_truncate=ON;

Когда Вы включаете innodb_undo_log_truncate, файлы табличного пространства отмены, которые превышают предел размера, определенный innodb_max_undo_log_size, отмечены для усечения. innodb_max_undo_log_size динамическая глобальная переменная со значением по умолчанию 1024 MiB (1073741824 байт).

mysql> SELECT @@innodb_max_undo_log_size;
+----------------------------+
| @@innodb_max_undo_log_size |
+----------------------------+
|   1073741824               |
+----------------------------+
1 row in set (0.00 sec)

Вы можете сконфигурировать innodb_max_undo_log_size с использованием SET GLOBAL:

mysql> SET GLOBAL innodb_max_undo_log_size=2147483648;
Query OK, 0 rows affected (0.00 sec)

Когда innodb_undo_log_truncate включена:

  1. Табличные пространства отмены, которые превышают innodb_max_undo_log_size, отмечены для усечения. Выбор табличного пространства отмены для усечения выполнен круговым способом, чтобы не усекать то же самое табличное пространство отмены каждый раз.

  2. Сегменты отмены, находящиеся в выбранном табличном пространстве отмены, сделаны бездействующими так, чтобы они не были выделены новым транзакциям. Существующим транзакциям, которые в настоящее время используют сегменты отмены, позволяют завершиться.
  3. Система чистки освобождает сегменты отмены, которые больше не необходимы.
  4. После того, как все сегменты отмены в табличном пространстве отмены освобождены, табличное пространство отмены усечено к его начальному размеру. Начальный размер файла табличного пространства отмены составляет 10 МБ.

    Если Вы проверяете размер табличного пространства отмены после того усечения, размер файла может быть больше 10 МБ из-за непосредственного использования после завершения работы усечения. Опция innodb_undo_directory определяет местоположение файлов табличного пространства отмены. Значение по умолчанию . представляет каталог, где InnoDB создает другие файлы системного журнала по умолчанию.

    mysql> select @@innodb_undo_directory;
    +-------------------------+
    | @@innodb_undo_directory |
    +-------------------------+
    | .                       |
    +-------------------------+
    1 row in set (0.00 sec)
    
  5. Сегменты отмены включены так, чтобы они могли быть выделены новым транзакциям.

Ускорение усечения файлов табличного пространства отмены

Табличное пространство отмены не может быть усечено, пока его сегменты отмены не освобождены. Обычно система чистки освобождает сегменты отмены каждый 128-й раз. Чтобы ускорить усечение табличных пространств отмены, Вы можете использовать опцию innodb_purge_rseg_truncate_frequency, чтобы временно увеличить частоту, с которой система чистки освобождает сегменты отмены. По умолчанию innodb_purge_rseg_truncate_frequency 128, что является также максимальным значением.

mysql> select @@innodb_purge_rseg_truncate_frequency;
+----------------------------------------+
| @@innodb_purge_rseg_truncate_frequency |
+----------------------------------------+
|  128                                   |
+----------------------------------------+
1 row in set (0.00 sec)

Чтобы увеличить частоту, с которой поток чистки освобождает сегменты отмены, уменьшите значение innodb_purge_rseg_truncate_frequency:

mysql> SET GLOBAL innodb_purge_rseg_truncate_frequency=32;
Query OK, 0 rows affected (0.00 sec)

Исполнительное воздействие усечения файлов табличного пространства отмены

В то время как работа усечения табличного пространства отмены происходит, сегменты отмены в одном табличном пространстве отмены временно дезактивированы. Например, если у Вас есть 2 табличных пространства отмены ( innodb_undo_tablespaces=2) и 128 выделенных журналов отмены (innodb_undo_logs=128 ), 95 из журналов отмены находятся в двух табличных пространствах отмены (48 сегментов отмены в одном табличном пространстве отмены и 47 в другом). Если первое табличное пространство отмены взято офлайн, 48 журналов отмены сделаны бездействующими, уменьшая ресурс журнала отмены немного больше, чем наполовину. В то время, как работа усечения происходит, остающиеся журналы отмены принимают на себя всю системную нагрузку, что может привести к небольшой исполнительной деградации. Степень исполнительной деградации зависит в ряде факторов, включая:

16.7.9. Общие табличные пространства InnoDB

Общее табличное пространство это особенность табличного пространства, которая обеспечивает следующие способности:

Создание общего табличного пространства

Общие табличные пространства создаются, используя CREATE TABLESPACE.

CREATE TABLESPACE tablespace_name ADD DATAFILE 'file_name'
       [FILE_BLOCK_SIZE = value]
       [ENGINE [=] engine_name]

Общее табличное пространство может быть создано в каталоге данных MySQL или в каталоге за пределами каталога данных MySQL. Чтобы избегать конфликтов с неявно создаваемыми табличными пространствами file-per-table, создание общего табличного пространства в подкаталоге в соответствии с каталогом данных MySQL не поддержано. Кроме того, создавая общее табличное пространство за пределами каталога данных MySQL, каталог должен существовать до создания табличного пространства.

Например:

Создание общего табличного пространства в каталоге данных MySQL:

mysql> CREATE TABLESPACE `ts1` ADD DATAFILE 'ts1.ibd' Engine=InnoDB;

Создание общего табличного пространства в каталоге за пределами каталога данных MySQL:

mysql> CREATE TABLESPACE `ts1` ADD DATAFILE
                 '/my/tablespace/directory/ts1.ibd' Engine=InnoDB;

Вы можете определить путь относительно каталога данных MySQL, пока каталог табличного пространства не является подкаталогом каталога данных MySQL. В этом примере my_tablespace каталог на том же самом уровне, как каталог данных MySQL:

mysql> CREATE TABLESPACE `ts1` ADD DATAFILE '../my_tablespace/ts1.ibd'
                 Engine=InnoDB;

ENGINE = InnoDB должен быть определен как часть CREATE TABLESPACE или InnoDB должен быть определен как механизм хранения по умолчанию ( default_storage_engine=InnoDB).

Добавление таблиц к общему табличному пространству

После создания общего табличного пространства, Вы можете использовать CREATE TABLE tbl_name ... TABLESPACE [=] tablespace_name или ALTER TABLE tbl_name TABLESPACE [=] tablespace_name, чтобы добавить таблицы к табличному пространству, как показано в следующих примерах:

CREATE TABLE:

mysql> CREATE TABLE t1 (c1 INT PRIMARY KEY) TABLESPACE ts1
                 ROW_FORMAT=COMPACT;

ALTER TABLE:

mysql> ALTER TABLE t2 TABLESPACE ts1;

Для подробной информации о синтаксисе см. CREATE TABLE и ALTER TABLE.

Поддержка формата строки табличным пространством

Общие табличные пространства поддерживают все форматы строки таблицы (REDUNDANT, COMPACT, DYNAMIC, COMPRESSED), но сжатые и несжатые таблицы не могут сосуществовать в том же самом общем табличном пространстве из-за различных физических размеров страницы.

Для общего табличного пространства, чтобы содержать сжатые таблицы (ROW_FORMAT=COMPRESSED), FILE_BLOCK_SIZE должен быть определен, и FILE_BLOCK_SIZE должно быть допустимым сжатым размером страницы относительно innodb_page_size . Кроме того, физический размер страницы сжатой таблицы (KEY_BLOCK_SIZE) должен быть равным FILE_BLOCK_SIZE/1024. Например, если innodb_page_size=16K и FILE_BLOCK_SIZE=8K, KEY_BLOCK_SIZE из таблицы должен быть 8.

Следующая таблица показывает допустимые FILE_BLOCK_SIZE и KEY_BLOCK_SIZE для каждого innodb_page_size . FILE_BLOCK_SIZE могут также быть определены в байтах. Определить допустимое KEY_BLOCK_SIZE для данного FILE_BLOCK_SIZE можно, поделив FILE_BLOCK_SIZE на 1024. Табличное сжатие не поддерживает размеры страницы 32K и 64K. Для получения дополнительной информации о KEY_BLOCK_SIZE см. CREATE TABLE и раздел 16.9.1.2.

Таблица 16.5. FILE_BLOCK_SIZE и KEY_BLOCK_SIZE для CREATE TABLESPACE

Размер страницы InnoDB (innodb_page_size) Permitted FILE_BLOCK_SIZE Permitted KEY_BLOCK_SIZE
64K64K (65536)Сжатие не поддерживается
32K32K (32768)Сжатие не поддерживается
16K16K (16384)N/A: Если innodb_page_size равно FILE_BLOCK_SIZE, табличное пространство не может содержать сжатую таблицу.
8K (8192)8
4K (4096)4
2K (2048)2
1K (1024)1
8K8K (8192)N/A: Если innodb_page_size равно FILE_BLOCK_SIZE, табличное пространство не может содержать сжатую таблицу.
4K (4096)4
2K (2048)2
1K (1024)1
4K4K (4096)N/A: Если innodb_page_size равно FILE_BLOCK_SIZE, табличное пространство не может содержать сжатую таблицу.
2K (2048)2
1K (1024)1

Этот пример демонстрирует создание общего табличного пространства и добавление сжатой таблицы. Пример принимает значение по умолчанию innodb_page_size 16K. FILE_BLOCK_SIZE 8192 требует, чтобы у сжатой таблицы был KEY_BLOCK_SIZE 8.

mysql> CREATE TABLESPACE `ts2` ADD DATAFILE 'ts2.ibd'
                 FILE_BLOCK_SIZE = 8192 Engine=InnoDB;
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE t4 (c1 INT PRIMARY KEY) TABLESPACE ts2
                 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
Query OK, 0 rows affected (0.00 sec)

Если Вы не определяете FILE_BLOCK_SIZE, создавая общее табличное пространство, FILE_BLOCK_SIZE по умолчанию innodb_page_size. Когда FILE_BLOCK_SIZE = innodb_page_size, табличное пространство может содержать только таблицы с несжатым форматом строки (COMPACT, REDUNDANT и DYNAMIC).

Перемещение неразделенной таблицы между табличными пространствами, используя ALTER TABLE

Вы можете использовать ALTER TABLE с опцией TABLESPACE, чтобы переместить неразделенную таблица к существующему общему табличному пространству, к новому табличному пространству file-per-table или к системному табличному пространству.

Выполнение ALTER TABLE tbl_name TABLESPACE [=] tablespace_name на разделенной таблице только изменяет табличное пространство по умолчанию таблицы. Это не перемещает разделы таблицы.

Чтобы переместить неразделенную таблицу от табличного пространства file-per-table или системного табличного пространства в общее, определите название общего табличного пространства. Общее табличное пространство должно уже существовать. См. CREATE TABLESPACE.

ALTER TABLE tbl_name TABLESPACE [=] tablespace_name

Чтобы переместить неразделенную таблицу от общего табличного пространства или табличного пространства file-per-table в системное, надо определить innodb_system как имя табличного пространства.

ALTER TABLE tbl_name ... TABLESPACE [=] innodb_system

Чтобы переместить неразделенную таблицу от системного табличного пространства или общего табличного пространства в file-per-table, укажите innodb_file_per_table как имя табличного пространства.

ALTER TABLE tbl_name ... TABLESPACE [=] innodb_file_per_table

ALTER TABLE ... TABLESPACE всегда вызывает полное пересоздание таблицы, даже если атрибут TABLESPACE не изменился от его предыдущего значения.

ALTER TABLE ... TABLESPACE не поддерживает перемещение таблицы из временного табличного пространства в постоянное.

DATA DIRECTORY разрешен с CREATE TABLE ... TABLESPACE=innodb_file_per_table, но иное не поддержано для использования в комбинации с опцией TABLESPACE.

Поддержка разделов таблиц в общем пространстве

Опция TABLESPACE может использоваться, чтобы назначить отдельный табличный раздел или подраздел к общему табличному пространству, отдельному табличному пространству file-per-table или системному табличному пространству. Все разделы должны принадлежать тому же самому механизму хранения. Использование продемонстрировано в следующих примерах.

mysql> CREATE TABLESPACE `ts1` ADD DATAFILE 'ts1.ibd' Engine=InnoDB;
mysql> CREATE TABLESPACE `ts2` ADD DATAFILE 'ts2.ibd' Engine=InnoDB;
mysql> CREATE TABLE t1 (a INT, b INT) ENGINE = InnoDB
    ->        PARTITION BY RANGE(a) SUBPARTITION BY KEY(b) (
    ->        PARTITION p1 VALUES LESS THAN (100) TABLESPACE=`ts1`,
    ->        PARTITION p2 VALUES LESS THAN (1000) TABLESPACE=`ts2`,
    ->        PARTITION p3 VALUES LESS THAN (10000) TABLESPACE `innodb_file_per_table`,
    ->        PARTITION p4 VALUES LESS THAN (100000) TABLESPACE `innodb_system`);

mysql> CREATE TABLE t2 (a INT, b INT) ENGINE = InnoDB
    ->        PARTITION BY RANGE(a) SUBPARTITION BY KEY(b) (
    ->           PARTITION p1 VALUES LESS THAN (100) TABLESPACE=`ts1`
    ->              (SUBPARTITION sp1, SUBPARTITION sp2),
    ->           PARTITION p2 VALUES LESS THAN (1000)
    ->              (SUBPARTITION sp3,
    ->               SUBPARTITION sp4 TABLESPACE=`ts2`),
    ->           PARTITION p3 VALUES LESS THAN (10000)
    ->              (SUBPARTITION sp5 TABLESPACE `innodb_system`,
    ->               SUBPARTITION sp6 TABLESPACE `innodb_file_per_table`));

Опция TABLESPACE также допустима с ALTER TABLE.

mysql> ALTER TABLE t1 ADD PARTITION (PARTITION p5 VALUES LESS
                THAN (1000000) TABLESPACE = `ts1`);

Если опция TABLESPACE = tablespace_name не определена, ALTER TABLE ... ADD PARTITION добавляет раздел к табличному пространству по умолчанию таблицы, которое может быть определено на табличном уровне во время CREATE TABLE или ALTER TABLE.

Чтобы проверить, что раздел был помещен в указанные табличные пространства, Вы можете запросить INFORMATION_SCHEMA.INNODB_SYS_TABLES:

mysql> SELECT NAME, SPACE, SPACE_TYPE
                 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
    ->        WHERE NAME LIKE '%t1%';
+-----------------------+-------+------------+
| NAME                  | SPACE | SPACE_TYPE |
+-----------------------+-------+------------+
| test/t1#P#p1#SP#p1sp0 | 57    | General    |
| test/t1#P#p2#SP#p2sp0 | 58    | General    |
| test/t1#P#p3#SP#p3sp0 | 59    | Single     |
| test/t1#P#p4#SP#p4sp0 |  0    | System     |
| test/t1#P#p5#SP#p5sp0 | 57    | General    |
+-----------------------+-------+------------+

mysql> SELECT NAME, SPACE, SPACE_TYPE FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
    ->        WHERE NAME LIKE '%t2%';
+---------------------+-------+------------+
| NAME                | SPACE | SPACE_TYPE |
+---------------------+-------+------------+
| test/t2#P#p1#SP#sp1 |    57 | General    |
| test/t2#P#p1#SP#sp2 |    57 | General    |
| test/t2#P#p2#SP#sp3 |    60 | Single     |
| test/t2#P#p2#SP#sp4 |    58 | General    |
| test/t2#P#p3#SP#sp5 |     0 | System     |
| test/t2#P#p3#SP#sp6 |    61 | Single     |
+---------------------+-------+------------+

Перемещение табличного раздела между табличными пространствами, используя ALTER TABLE

Чтобы переместить табличное разделение в иное табличное пространство, Вы должны переместить каждый раздел, используя ALTER TABLE tbl_name REORGANIZE PARTITION.

Следующий пример демонстрирует, как переместить табличное разделение в иное табличное пространство. INFORMATION_SCHEMA.INNODB_SYS_TABLES и INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES запрошены, чтобы проверить, что разделение помещено в ожидаемое табличное пространство.

Если опция TABLESPACE = tablespace_name не определена в запросе REORGANIZE PARTITION, InnoDB перемещает разделение в табличное пространство по умолчанию таблицы. В этом примере табличное пространство ts1, которое определено на табличном уровне, является табличным пространством по умолчанию для таблицы t1. Раздел P3 перемещен от системного табличного пространства в ts1, поскольку нет опции TABLESPACE в ALTER TABLE t1 REORGANIZE PARTITION для раздела P3.

Чтобы изменить табличное пространство по умолчанию разделенной таблицы, Вы можете сделать ALTER TABLE tbl_name TABLESPACE [=] tablespace_name на разделенной таблице.

mysql> CREATE TABLESPACE ts1 ADD DATAFILE 'ts1.ibd';
mysql> CREATE TABLESPACE ts2 ADD DATAFILE 'ts2.ibd';
mysql> CREATE TABLE t1 ( a INT NOT NULL, PRIMARY KEY (a))
    ->        ENGINE=InnoDB TABLESPACE ts1
    ->        PARTITION BY RANGE (a) PARTITIONS 3 (
    ->        PARTITION P1 VALUES LESS THAN (2),
    ->        PARTITION P2 VALUES LESS THAN (4) TABLESPACE `innodb_file_per_table`,
    ->        PARTITION P3 VALUES LESS THAN (6) TABLESPACE `innodb_system`);

mysql> SELECT A.NAME as partition_name, A.SPACE_TYPE as space_type,
                 B.NAME as space_name
    ->        FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES A
    ->        LEFT JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES B
    ->        ON A.SPACE = B.SPACE WHERE A.NAME LIKE '%t1%'
                 ORDER BY A.NAME;
+----------------+------------+--------------+
| partition_name | space_type | space_name   |
+----------------+------------+--------------+
| test/t1#P#P1   | General    | ts1          |
| test/t1#P#P2   | Single     | test/t1#P#P2 |
| test/t1#P#P3   | System     | NULL         |
+----------------+------------+--------------+

mysql> ALTER TABLE t1 REORGANIZE PARTITION P1
    ->       INTO (PARTITION P1 VALUES LESS THAN (2) TABLESPACE = `ts2`);
mysql> ALTER TABLE t1 REORGANIZE PARTITION P2
    ->       INTO (PARTITION P2 VALUES LESS THAN (4) TABLESPACE = `ts2`);
mysql> ALTER TABLE t1 REORGANIZE PARTITION P3
    ->       INTO (PARTITION P3 VALUES LESS THAN (6));

mysql> SELECT A.NAME AS partition_name, A.SPACE_TYPE AS space_type,
                 B.NAME AS space_name
    ->        FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES A
    ->        LEFT JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES B
    ->        ON A.SPACE = B.SPACE WHERE A.NAME LIKE '%t1%'
                 ORDER BY A.NAME;
+----------------+------------+------------+
| partition_name | space_type | space_name |
+----------------+------------+------------+
| test/t1#P#P1   | General    | ts2        |
| test/t1#P#P2   | General    | ts2        |
| test/t1#P#P3   | General    | ts1        |
+----------------+------------+------------+

Удаление общего табличного пространства

DROP TABLESPACE используется, чтобы удалить общее табличное пространство.

Все таблицы должны быть исключены из табличного пространства до DROP TABLESPACE. Если табличное пространство не пусто, DROP TABLESPACE возвращает ошибку.

Табличное пространство не удалено автоматически, когда последняя таблица в табличном пространстве удалена. Табличное пространство должно быть удалено явно, используя DROP TABLESPACE tablespace_name.

Общее табличное пространство не принадлежит никакой особой базе данных. DROP DATABASE может удалить таблицы, которые принадлежат общему табличному пространству, но она не может удалить табличное пространство, даже если DROP DATABASE удаляет все таблицы, которые принадлежат табличному пространству. Общее табличное пространство должно быть явно, используя DROP TABLESPACE tablespace_name.

Подобно системному табличному пространству, удаление таблиц, сохраненных в общем табличном пространстве, создает свободное пространство внутренне в общем табличном пространстве файле данных .ibd, которое может использоваться только для новых данных InnoDB. Пространство не освобождено назад к операционной системе, как табличное пространство file-per-table удалено во время DROP TABLE.

Этот пример демонстрирует, как удалить общее табличное пространство. Общее табличное пространство ts1 создается с единственной таблицей. Таблица должна быть удалена прежде, чем все табличное пространство.

mysql> CREATE TABLESPACE `ts1` ADD DATAFILE 'ts1.ibd' Engine=InnoDB;
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE t1 (c1 INT PRIMARY KEY) TABLESPACE ts10 Engine=InnoDB;
Query OK, 0 rows affected (0.02 sec)

mysql> DROP TABLE t1;
Query OK, 0 rows affected (0.01 sec)

mysql> DROP TABLESPACE ts1;
Query OK, 0 rows affected (0.01 sec)

tablespace_name чувствительный к регистру идентификатор в MySQL.

Ограничения общего табличного пространства

Для получения дополнительной информации см. раздел 14.1.16.

16.7.10. Шифрование табличного пространства InnoDB

InnoDB допускает шифрование данных для таблиц, сохраненных в табличных пространствах file-per-table. Эта особенность обеспечивает шифрование для физических файлов с данными табличного пространства.

Шифрование табличного пространства использует две архитектуры ключа шифрования ряда, состоя из основного ключа шифрования и ключей табличного пространства. Когда таблица зашифрована, ключ табличного пространства зашифрован и сохранен в заголовке табличного пространства. Когда приложение или пользователь хотят получить доступ к зашифрованным данным табличного пространства, InnoDB использует основной ключ шифрования, чтобы дешифровать ключ табличного пространства. Основной ключ шифрования сохранен в файле keyring в местоположении, определенном опцией keyring_file_data . Дешифрованная версия ключа табличного пространства никогда не изменяется, но основной ключ шифрования может быть изменен как требуется. Это действие упоминается как ротация главного ключа.

Особенность шифрования табличного пространства полагается на плагин keyring для основного управления ключом шифрования.

Шифрование табличного пространства поддерживает алгоритм Advanced Encryption Standard (AES) block-based. Это использует режим блочного шифрования Electronic Codebook (ECB) для ключевого шифрования табличного пространства и режим блочного шифрования Cipher Block Chaining (CBC) для шифрования данных.

Особенность шифрования табличного пространства, предоставленная MySQL Community Edition, не предназначена как решение для соответствия установленным требованиям. Стандарты безопасности, такие как PCI, FIPS и другие требуют, чтобы использование систем ключевого менеджмента обеспечило, управляло и защитило ключи в ключевых хранилищах или модулях безопасности аппаратных средств (HSM).

Для часто задаваемых вопросов о особенности шифрования табличного пространства см. раздел A.15 .

Предпосылки шифрования табличного пространства InnoDB

Включение и отключение шифрования табличного пространства InnoDB

Чтобы включить шифрование для новой таблицы, укажите опцию ENCRYPTION в CREATE TABLE .

mysql> CREATE TABLE t1 (c1 INT) ENCRYPTION='Y';

Чтобы включить шифрование для существующей таблицы, укажите опцию ENCRYPTION в ALTER TABLE .

mysql> ALTER TABLE t1 ENCRYPTION='Y';

Чтобы выключить шифрование для таблицы, укажите опцию ENCRYPTION='N' в ALTER TABLE .

mysql> ALTER TABLE t1 ENCRYPTION='N';

Запланируйте все, изменяя существующую таблицу с опцией ENCRYPTION. ALTER TABLE ... ENCRYPTION пересоздает таблицу алгоритмом ALGORITHM=COPY. ALGORITM=INPLACE не поддержан.

Шифрование табличного пространства InnoDB и ротация главного ключа

Основной ключ шифрования должен периодически меняться и всякий раз, когда Вы подозреваете, что ключ, возможно, поставлен под угрозу.

Ротация главного ключа атомная работа на уровне сервера. Каждый раз, когда основной ключ шифрования меняется, все ключи табличных пространств повторно зашифрованы и сохранены назад к их соответствующим заголовкам табличного пространства. Как атомная работа, перешифрование должно пройти для всех ключей табличного пространства, как только работа начата. Если ротация главного ключа прервана отказом сервера, InnoDB продолжает процесс при перезапуске сервера.

Ротация основного ключа шифрования изменяет только основной ключ шифрования и повторно шифрует ключи табличного пространства. Это не дешифрует или повторно шифрует связанные данные о табличном пространстве.

Ротация основного ключа шифрования требует привилегии SUPER.

Чтобы сменить основной ключ шифрования:

mysql> ALTER INSTANCE ROTATE INNODB MASTER KEY;

ALTER INSTANCE ROTATE INNODB MASTER KEY поддерживает параллельный DML. Однако, это не может быть выполнено одновременно с CREATE TABLE ... ENCRYPTED или ALTER TABLE ... ENCRYPTED, блокировки взяты, чтобы предотвратить конфликты, которые могли явиться результатом параллельного выполнения этих запросов. Если один из противоречивых запросов работает, он должно завершиться прежде, чем другой сможет продолжить.

Шифрование табличного пространства InnoDB и восстановление

Если отказ сервера происходит во время ротации главного ключа, InnoDB продолжает работу при перезапуске сервера.

Плагин keyring должен быть загружен до инициализации механизма хранения, чтобы информация, необходимая, чтобы дешифровать страницы данных о табличном пространстве, могла быть получена от заголовков табличного пространства прежде инициализации InnoDB и востановления активности доступа к данным.

Когда инициализация и восстановление начинаются, ротация восстанавливается. Из-за отказа сервера, некоторые ключи табличных пространств могут уже быть зашифрованы, используя новый основной ключ шифрования. InnoDB читает данные о шифровании из каждого заголовка табличного пространства, и если данные указывают, что ключ табличного пространства зашифрован, используя старый ключ шифрования, получает старый ключ и использует это, чтобы дешифровать ключ пространства. InnoDB тогда повторно шифрует ключ табличного пространства с использованием нового основного ключа шифрования и сохраняет повторно зашифрованный ключ табличного пространства назад в заголовке.

Экспорт зашифрованных таблиц

Когда зашифрованная таблица экспортируется, InnoDB производит ключ передачи, который используется, чтобы зашифровать ключ табличного пространства. Зашифрованный ключ табличного пространства и ключ передачи сохранены в файле tablespace_name.cfp. Этот файл вместе с зашифрованным файлом табличного пространства обязан выполнять работу импорта. При импорте InnoDB использует ключ передачи, чтобы дешифровать ключ табличного пространства в tablespace_name.cfp. Подробности в разделе 16.7.6.

Шифрование табличного пространства InnoDB и репликация

Идентификация Таблиц, которые используют шифрование табличного пространства InnoDB

Когда опция ENCRYPTION определена в CREATE TABLE или ALTER TABLE, это зарегистрировано в поле CREATE_OPTIONS в INFORMATION_SCHEMA.TABLES. Это поле может быть запрошена, чтобы идентифицировать зашифрованные таблицы.

mysql> SELECT TABLE_SCHEMA, TABLE_NAME, CREATE_OPTIONS
                 FROM INFORMATION_SCHEMA.TABLES
    ->        WHERE CREATE_OPTIONS LIKE '%ENCRYPTION="Y"%';
+--------------+------------+----------------+
| TABLE_SCHEMA | TABLE_NAME | CREATE_OPTIONS |
+--------------+------------+----------------+
| test         | t1         | ENCRYPTION="Y" |
+--------------+------------+----------------+

Примечания использования шифрования табличного пространства

Ограничения шифрования табличного пространства InnoDB

16.8. Таблицы и индексы InnoDB

16.8.1. Составление таблиц InnoDB

Чтобы создать таблицу, используйте CREATE TABLE. Вы не должны определить ENGINE=InnoDB, если InnoDB определен как механизм хранения по умолчанию. Вы могли бы все еще использовать ENGINE=InnoDB, если Вы планируете использовать mysqldump или репликацию, чтобы повторить CREATE TABLE на сервере, где механизм хранения по умолчанию не InnoDB.

-- Default storage engine = InnoDB.
CREATE TABLE t1 (a INT, b CHAR (20), PRIMARY KEY (a));
-- Backward-compatible with older MySQL.
CREATE TABLE t2 (a INT, b CHAR (20), PRIMARY KEY (a)) ENGINE=InnoDB;

Когда включена опция innodb_file_per_table, что является значением по умолчанию, таблица неявно составлена в отдельном табличном пространстве file-per-table. Наоборот, когда innodb_file_per_table выключена, таблица неявно составлена в системном табличном пространстве. Вы можете использовать CREATE TABLE ... TABLESPACE, чтобы явно создать таблицу в любом из трех типов табличного пространства.

Когда Вы создаете таблицу, MySQL создает каталог базы данных в соответствии с каталогом данных MySQL. Для таблицы, составленной в табличном пространстве file-per-table, создается файл .ibd. Таблица, создаваемая в системном табличном пространстве, составлена в существующем системном табличном пространстве файлов ibdata. Таблица, создаваемая в общем табличном пространстве, составлена в существующем общем табличном пространстве файла .ibd.

Внутренне InnoDB добавляет запись для каждой таблицы к словарю данных. Запись включает имя базы данных. Например, если таблица t1 создается в базе данных test, запись будет 'test/t1'. Это означает, что Вы можете составить таблицу с тем же самым именем (t1) в иной базе данных, и имена таблиц не сталкиваются внутри InnoDB.

Просмотр свойств таблиц

Используйте SHOW TABLE STATUS :

mysql > SHOW TABLE STATUS FROM test LIKE 't%' \G;
*************************** 1. row ***************************
 Name: t1
 Engine: InnoDB
Version: 10
 Row_format: Compact
 Rows: 0
 Avg_row_length: 0
Data_length: 16384
Max_data_length: 0
   Index_length: 0
  Data_free: 0
 Auto_increment: NULL
Create_time: 2015-03-16 15:13:31
Update_time: NULL
 Check_time: NULL
  Collation: latin1_swedish_ci
   Checksum: NULL
 Create_options:
Comment:
1 row in set (0.00 sec)

В выводе состояния Вы видите, что свойство Row format таблицы t1 Compact. Формат строки Dynamic или Compressed используют особенности InnoDB, такие как табличное сжатие и хранение вне страницы для длинных значений столбцов. Чтобы использовать эти форматы строки, Вы можете включить innodb_file_per_table (по умолчанию):

SET GLOBAL innodb_file_per_table=1;
CREATE TABLE t3 (a INT, b CHAR (20), PRIMARY KEY (a)) ROW_FORMAT=DYNAMIC;
CREATE TABLE t4 (a INT, b CHAR (20), PRIMARY KEY (a)) ROW_FORMAT=COMPRESSED;

Или Вы можете использовать CREATE TABLE ... TABLESPACE, чтобы создать таблицу InnoDB в общем табличном пространстве. Общие табличные пространства поддерживают все форматы строки. Для получения дополнительной информации см. раздел 16.7.9.

CREATE TABLE t1 (c1 INT PRIMARY KEY) TABLESPACE ts1 ROW_FORMAT=DYNAMIC;

CREATE TABLE ... TABLESPACE может также использоваться, чтобы создать таблицу с форматом строки Dynamic в системном табличном пространстве, а также таблицы с форматом строк Compact или Redundant.

CREATE TABLE t1 (c1 INT PRIMARY KEY) TABLESPACE = innodb_system
       ROW_FORMAT=DYNAMIC;

Табличные свойства могут также быть запрошены, используя таблицы Information Schema:

SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME='test/t1' \G
*************************** 1. row ***************************
 TABLE_ID: 45
 NAME: test/t1
 FLAG: 1
   N_COLS: 5
SPACE: 35
   ROW_FORMAT: Compact
ZIP_PAGE_SIZE: 0
SPACE_TYPE: Single

Определение первичного ключа для таблиц InnoDB

Всегда настраивайте первичный ключ для каждой таблицы, определяя столбец или столбцы, которые:

Например, в таблице, содержащей информацию о людях, Вы не создали бы первичный ключ на (firstname, lastname) потому, что больше чем у одного человека может быть то же самое имя, у некоторых людей есть пустые фамилии, и иногда люди меняют свои имена. С очень многими ограничениями часто нет очевидного набора столбцов, чтобы использовать в качестве первичного ключа, таким образом, Вы создаете новый столбец с числовым ID, чтобы служить всем или частью первичного ключа. Вы можете объявить столбец auto-increment, чтобы значения были заполнены автоматически, когда строки вставлены:

-- The value of ID can act like a pointer between related items in different tables.
CREATE TABLE t5 (id INT AUTO_INCREMENT, b CHAR (20), PRIMARY KEY (id));
-- The primary key can consist of more than one column. Any autoinc column must come first.
CREATE TABLE t6 (id INT AUTO_INCREMENT, a INT, b CHAR (20), PRIMARY KEY (id,a));

Хотя таблица работает правильно, не определяя первичный ключ, первичный ключ связан со многими аспектами работы и является решающим аспектом проекта для любой большой или часто используемой таблицы. Рекомендуется, чтобы Вы всегда определили первичный ключ в CREATE TABLE. Если Вы составляете таблицу, вводите данные и затем выполняете ALTER TABLE, чтобы добавить первичный ключ позже, эта работа намного медленнее, чем определение первичного ключа, составляя таблицу.

16.8.2. Физическая структура строки таблиц InnoDB

Физическая структура строки таблицы зависит от формата строки, определенного, когда таблица составлена. Если формат строки не определен, формат строки по умолчанию используется. Формат строки по умолчанию определен опцией innodb_default_row_format, у которой есть значение по умолчанию DYNAMIC.

Формат REDUNDANT доступен, чтобы сохранить совместимость с более старыми версиями MySQL.

Чтобы проверить формат строки таблицы, Вы можете использовать SHOW TABLE STATUS:

mysql> SHOW TABLE STATUS IN test1\G
*************************** 1. row ***************************
 Name: t1
 Engine: InnoDB
Version: 10
 Row_format: Dynamic
 Rows: 0
 Avg_row_length: 0
Data_length: 16384
Max_data_length: 0
   Index_length: 16384
  Data_free: 0
 Auto_increment: 1
Create_time: 2016-09-14 16:29:38
Update_time: NULL
 Check_time: NULL
  Collation: latin1_swedish_ci
   Checksum: NULL
 Create_options:
Comment:

Вы можете также проверить формат строки, запрашивая INFORMATION_SCHEMA.INNODB_SYS_TABLES.

mysql> SELECT NAME, ROW_FORMAT FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
                 WHERE NAME='test1/t1';
+----------+------------+
| NAME     | ROW_FORMAT |
+----------+------------+
| test1/t1 | Dynamic    |
+----------+------------+

Характеристики формата строки Redundant

Строки в таблицах, использующие формат REDUNDANT, имеют следующие характеристики:

Характеристики формата строки COMPACT

Формат строки COMPACT уменьшает место для хранения строки приблизительно на 20% по сравнению с REDUNDANT за счет увеличения использования центрального процессора для некоторых операций. Если Ваша рабочая нагрузка типичная, которая ограничена частотами успешных обращений кэша и дисковой скоростью, COMPACT, вероятно, будет быстрее. Если рабочая нагрузка редкий случай, который ограничен скоростью центрального процессора, компактный формат мог бы быть медленнее.

Строки в таблице имеют следующие характеристики:

Форматы строк DYNAMIC и COMPRESSED

Форматы строк DYNAMIC и COMPRESSED это варианты формата COMPACT. Для информации об этих форматах строки см. раздел 16.10.3.

16.8.3. Перемещение или копирование таблиц InnoDB в другую машину

Этот раздел описывает методы для перемещения или копирования некоторых или всех таблиц InnoDB на другой сервер. Например, Вы могли бы переместить весь экземпляр MySQL на больший, более быстрый сервер, Вы могли бы клонировать весь экземпляр MySQL к новому ведомому серверу репликации, Вы могли бы скопировать отдельные таблицы на другой сервер, чтобы развить и проверить приложение, или к серверу хранилища данных, чтобы представить доклады.

Методы для перемещения или копирования таблиц включают:

Имена в нижнем регистре

В Windows InnoDB всегда хранит имена базы данных и таблиц внутренне в нижнем регистре. Чтобы переместить базы данных в двоичном формате из Unix в Windows или наоборот, создайте все базы данных и таблицы, используя строчные имена. Удобный способ достигнуть этого состоит в том, чтобы добавить следующую строку к группе [mysqld] файла my.cnf or my.ini прежде, чем создать любые базы данных или таблицы:

[mysqld]
lower_case_table_names=1

Мобильные табличные пространства

Мобильные табличные пространства используют FLUSH TABLES ... FOR EXPORT, чтобы скопировать таблицы. Чтобы использовать эту функцию, таблицы должны быть составлены с innodb_file_per_table в ON, чтобы каждая таблица имела свое собственное табличное пространство. Для информации об использовании см. раздел 16.7.6.

MySQL Enterprise Backup

MySQL Enterprise Backup позволяет Вам поддерживать рабочую базу данных MySQL, включая таблицы InnoDB и MyISAM, с минимальным разрушением к операциям, производя последовательный снимок базы данных. Когда MySQL Enterprise Backup копирует таблицы InnoDB, чтение и запись таблиц InnoDB и MyISAM могут продолжиться. Во время копирования MyISAM и других не-InnoDB таблиц, чтения (но не записи) к тем таблицам разрешены. Кроме того, MySQL Enterprise Backup может создать сжатые резервные файлы и поддержать подмножества таблиц InnoDB. В соединении с двоичным журналом Вы можете выполнить восстановление момента времени. MySQL Enterprise Backup включен как часть MySQL Enterprise.

Подробности в разделе 27.2 .

Копирование файлов с данными

Вы можете переместить база данных, просто копируя все соответствующие файлы, см. раздел 16.17.

Аналогично файлам MyISAM, InnoDB данные и файлы системного журнала совместимы на всех платформах, имеющих тот же самый числовой формат с плавающей запятой. Если форматы с плавающей запятой отличаются, но Вы не использовали DOUBLE в Ваших таблицах, процедура та же самая: просто скопируйте соответствующие файлы.

Соображения мобильности для файлов .ibd File-Per-Table

Когда Вы перемещаете или копируете файл .ibd, имя каталога базы данных должно быть тем же самым на целевых системах и источнике. Табличное определение, сохраненное в совместно используемом табличном пространстве включает имя базы данных. Операционные ID и порядковые номера журнала, сохраненные в файлах табличного пространства, также отличаются между базами данных.

Перемещать файл .ibd и связанную таблицу от одной базы данных к другой можно с помощью RENAME TABLE :

RENAME TABLE db1.tbl_name TO db2.tbl_name;

Если у Вас есть резервная копия файла .ibd, Вы можете восстановить ее к исходной установке MySQL следующим образом:

  1. Таблица, должно быть, не была удалена или усечена, так как Вы скопировали .ibd, табличный ID сохранен в табличном пространстве.

  2. С помощью ALTER TABLE удалите текущий файл .ibd:
    ALTER TABLE tbl_name DISCARD TABLESPACE;
    
  3. Скопируйте резервную копию файла .ibd к надлежащему каталогу базы данных.
  4. Используйте ALTER TABLE, чтобы сказать InnoDB использовать новый файл .ibd для таблицы:
    ALTER TABLE tbl_name IMPORT TABLESPACE;
    

    ALTER TABLE ... IMPORT TABLESPACE не проводит в жизнь ограничения внешнего ключа на импортированные данные.

В этом контексте копия файла .ibd удовлетворяет следующим требованиям:

Вы можете сделать чистое резервное копирование .ibd:

  1. Остановите всю деятельность mysqld и передайте все транзакции.

  2. Ждите, пока SHOW ENGINE INNODB STATUS покажет, что нет никаких активных транзакций в базе данных, и состояние основного потока InnoDB Waiting for server activity. Тогда Вы можете сделать копию файла .ibd.

Другой метод для того, чтобы сделать чистую копию .ibd:

  1. Используйте MySQL Enterprise Backup.

  2. Запустите второй сервер mysqld и позвольте ему очистить файлы .ibd в резервном копировании.

Экспорт и импорт (mysqldump)

Вы можете использовать mysqldump, чтобы вывести Ваши таблицы в дамп на одной машине и затем импортировать файлы дампа на другой машине. Используя этот метод, не имеет значения, отличаются ли форматы или содержат ли Ваши таблицы данные с плавающей запятой.

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

16.8.4. Преобразование таблиц из MyISAM в InnoDB

Если Вы имеете таблицы MyISAM, которые Вы хотите преобразовать в InnoDB, рассмотрите следующие подсказки прежде, чем сделать преобразование.

Разделенные таблицы MyISAM, составленные в предыдущих версиях MySQL, несовместимы с MySQL 8.0. Такие таблицы должны быть подготовлены до обновления, удаляя разделение, или преобразовывая их в InnoDB. См. раздел 20.6.2.

Уменьшите использование памяти для MyISAM

Поскольку Вы переходите от таблиц MyISAM, понизьте значение key_buffer_size, чтобы освободить память, больше не нужную для того, чтобы кэшировать результаты. Увеличьте значение innodb_buffer_pool_size, которое выполняет подобную роль выделения кэш-памяти для InnoDB. Буферный пул кэширует табличные данные и индексы, таким образом, это действительно удваивает ускорение поисков для запросов и хранения результатов запроса в памяти для повторного использования. Для руководства относительно буферной конфигурации размера пула см. раздел 9.12.3.1.

На занятом сервере выполните тесты с выключенным кэшем запроса. Буферный пул обеспечивает подобную выгоду, таким образом, кэш запроса мог бы излишне связывать память.

Не упустите слишком длинные или короткие транзакции

Поскольку таблицы MyISAM не поддерживают транзакции, Вы, возможно, не обратили много внимания на настройку autocommit и команды COMMIT и ROLLBACK. Эти ключевые слова важны, чтобы позволить многим сеансам читать и писать таблицы InnoDB одновременно, обеспечивая существенную выгоду масштабируемости.

В то время как транзакция открыта, система сохраняет снимок данных в начале транзакции, что может вызвать существенные накладные расходы, если система вставляет, обновляет и удаляет миллионы строк, в то время как беспризорная транзакция продолжает работать. Таким образом, заботьтесь о том, чтобы избежать транзакций, которые работают слишком долго:

Предыдущие подсказки сохраняют место в памяти и дисковое пространство, которое может быть потрачено впустую во время слишком длинных транзакций. Когда транзакции короче, чем они должны быть, проблемой будет чрезмерный ввод/вывод. С каждым COMMIT MySQL удостоверяется, что каждое изменение безопасно зарегистрировано на диске, что вовлекает некоторый ввод/вывод.

Не волнуйтесь слишком много о тупиках

Вы могли бы видеть предупреждающие сообщения о тупиках в журнале ошибок MySQL или выводе SHOW ENGINE INNODB STATUS. Несмотря на страшно звучащее имя, тупик не серьезная проблема для InnoDB и часто не требуют никакого корректирующего действия. Когда две транзакции начинают изменять многие таблицы, получая доступ к таблицам в различном порядке, они могут достигнуть состояния, где каждая транзакция ждет другую, и ни одна не может продолжить. Когда определение тупиков включено (значение по умолчанию), MySQL немедленно обнаруживает это условие, и отменяет меньшую, позволяя другой продолжиться. Если обнаружение тупика отключено, используя innodb_deadlock_detect, InnoDB полагается на innodb_lock_wait_timeout, чтобы откатить транзакции до прежнего уровня в случае тупика.

Так или иначе, Ваши приложения нуждаются в логике обработки ошибок, чтобы перезапустить транзакцию, которая насильственно отменена из-за тупика. Когда Вы переиздаете те же самые запросы SQL как прежде, оригинальная проблема синхронизации больше не применяется: или другая транзакция уже закончилась, и Ваша может продолжиться, или другая транзакция все еще происходит, и Ваша транзакция ждет, пока это не заканчивается.

Если предупреждения тупика постоянно происходят, Вы могли бы рассмотреть код программы, чтобы переупорядочить операции SQL последовательным способом, или сократить транзакции. Вы можете проверить с включенной опцией innodb_print_all_deadlocks, чтобы видеть все предупреждения тупика в журнале ошибок MySQL, а не только последнее предупреждение в SHOW ENGINE INNODB STATUS.

Подробности в разделе 16.5.5.

Запланируйте расположение хранения

Получить лучшую работу от InnoDB Вы можете, скорректировав много параметров, связанных с расположением хранения.

Когда Вы преобразовываете таблицы MyISAM, которые являются большими, часто используемыми и содержащими жизненные данные, исследуйте и рассмотрите опции innodb_file_per_table и innodb_page_size , а также параметры ROW_FORMAT и KEY_BLOCK_SIZE в CREATE TABLE.

Во время Ваших начальных экспериментов самая важная установка innodb_file_per_table. Когда эта установка включена, что является значением по умолчанию, новые таблицы неявно составлены в табличных пространствах file-per-table. В отличие от системного табличного пространства, табличные пространства file-per-table позволяют дисковому пространству использоваться операционной системой, когда таблица является усеченной или удаленной. Табличные пространства File-per-table также поддерживают строки форматов DYNAMIC и COMPRESSED и связанные особенности, такие как табличное сжатие, хранение вне страницы для длинных столбцов переменной длины и большой префикс индекса. Для получения дополнительной информации см. раздел 16.7.4.

Вы можете также сохранить таблицы в совместно используемом общем табличном пространстве, которое поддерживает многие таблицы и все форматы строки. Для получения дополнительной информации см. раздел 16.7.9.

Преобразование существующей таблицы

Преобразовать не-InnoDB таблицу, чтобы использовать InnoDB можно через ALTER TABLE:

ALTER TABLE table_name ENGINE=InnoDB;

Клонирование структуры таблицы

Вы могли бы сделать таблицу InnoDB, которая является клоном таблицы MyISAM, вместо того, чтобы делать ALTER TABLE, чтобы проверить старую и новую таблицу бок о бок перед переключением.

Создайте пустую таблицу с идентичными определениями столбца и индексов. Примените show create table table_name\G, чтобы посмотреть полный запрос CREATE TABLE. Смените ENGINE на ENGINE=INNODB.

Передача существующих данных

Передать большой объем данных в пустую таблицу, составленную как показано в предыдущем разделе, можно, вставив строки с помощью INSERT INTO innodb_table SELECT * FROM myisam_table ORDER BY primary_key_columns.

Вы можете также создать индексирование для таблицы после вставки данных. Исторически, создание новых вторичных индексов было медленной работой для InnoDB, но теперь Вы можете создать индексирование после того, как данные загружены, относительно легко и быстро.

Если Вы имеете ограничения UNIQUE на вторичные ключи, Вы можете ускорить табличный импорт, выключая проверки уникальности временно во время работы импорта:

SET unique_checks=0;
... import operation ...
SET unique_checks=1;

Для больших таблиц это сохраняет дисковый ввод/вывод потому, что InnoDB может использовать буфер изменения, чтобы записать вторичный индекс как пакет. Будьте уверены, что данные не содержат дубликаты ключа. unique_checks разрешает, но не требует, чтобы механизмы хранения проигнорировали дубликаты ключа.

Чтобы получить лучший контроль над процессом вставки, Вы могли бы вставить большие таблицы по частям:

INSERT INTO newtable SELECT * FROM oldtable
       WHERE yourkey > something AND
             yourkey <= somethingelse;

После того, как все записи были вставлены, Вы можете переименовать таблицы.

Во время преобразования больших таблиц, увеличьте размер буферного пула, чтобы уменьшить дисковый ввод/вывод, максимум до 80% физической памяти. Вы можете также увеличить размер файлов системного журнала.

Требования хранения

Если Вы намереваетесь сделать несколько временных копий своих данных в таблицах во время конверсионного процесса, рекомендуется, чтобы Вы составили таблицы в табличных пространствах file-per-table, чтобы Вы могли восстановить дисковое пространство, когда Вы удаляете таблицы. Как упомянуто ранее, когда innodb_file_per_table включена (значение по умолчанию), созданные таблицы неявно составлены в табличных пространствах file-per-table.

Преобразовываете ли Вы MyISAM непосредственно или создаете клонированную таблицу InnoDB, удостоверьтесь, что у Вас есть достаточное дисковое пространство, чтобы хранить старые и новые таблицы во время процесса. Таблицы InnoDB требуют большего количества дискового пространства, чем MyISAM. Если ALTER TABLE исчерпывает пространство, она запускает откат, а это может занять часы. Для вставок InnoDB использует буфер вставки, чтобы слить вторичные индексные записи в пакетах. Это сохраняет много дискового ввода/вывода. Для отмены не используется такой механизм, и отмена может занять в 30 раз дольше, чем вставка.

В случае безудержной отмены, если у Вас нет ценных данных в Вашей базе данных, может быть желательно уничтожить процесс базы данных, а не ждать миллионов дисковых операций ввода/вывода. Для полной процедуры см. раздел 16.20.2.

Тщательно выберите PRIMARY KEY для каждой таблицы

PRIMARY KEY это критический фактор, затрагивающий исполнение запросов MySQL и использование пространства для таблиц и индексов. У каждой строки в таблице должно быть значение первичного ключа, но ни у каких двух строк не может быть того же самого значения первичного ключа.

Вот направляющие идеи для первичного ключа, сопровождаемые более подробными объяснениями.

Рассмотрите добавление primary key к любой таблице, у которой его еще нет. Используйте самый маленький практический числовой тип, основанный на максимальном спроектированном размере таблицы. Это может сделать каждую строку немного более компактной, что может привести к существенной экономии места для больших таблиц. Сбережения пространства умножены, если таблица имеет вторичный индекс, потому что значение первичного ключа повторено в каждом вторичном индексе. В дополнение к сокращению размера данных на диске маленький первичный ключ также позволяет большее количество совпадения данных в буферном пуле, ускоряя все виды операций и улучшая параллелизм.

Если у таблицы уже есть первичный ключ на некотором более длинном столбце, таком как VARCHAR, рассмотрите добавление нового столбца unsigned AUTO_INCREMENT и переключение первичного ключа на него, даже если на этот столбец не ссылаются в запросах. Это изменение проекта может произвести существенную экономию места во вторичном индексе. Вы можете определять прежние столбцы первичного ключа как UNIQUE NOT NULL, чтобы провести в жизнь те же самые ограничения, как PRIMARY KEY, то есть, чтобы предотвратить двойные или нулевые значения в этих столбцах.

Если Вы распространяете соответствующую информацию через много таблиц, как правило, каждая таблица использует тот же самый столбец для своего первичного ключа. Например, у базы данных персонала могло бы быть несколько таблиц, каждая с первичным ключом номера служащего. У базы данных продаж могли бы быть некоторые таблицы с первичным ключом номера заказчика и другие таблицы с первичным ключом порядкового номера. Поскольку поиски, используя первичный ключ очень быстры, Вы можете создать эффективные запросы для таких таблиц.

Если Вы не используете PRIMARY KEY, MySQL создает невидимый. Это 6-байтовое значение, которое могло бы быть более длинным, чем надо, таким образом тратя впустую место. Поскольку это скрыто, Вы не можете обратиться к этому в запросах.

Соображения потребительских свойств

Дополнительная надежность и особенности масштабируемости InnoDB действительно потребуют большего количества дискового места, чем эквивалентные таблицы MyISAM. Вы могли бы изменить столбец и определения индекса для лучшего использования пространства, уменьшенного ввода/вывода и потребления памяти, обрабатывая наборы результатов, и лучших планов оптимизации запроса, делающих эффективное использование поисков по индексу.

Если Вы действительно настраиваете числовой столбец ID для первичного ключа, используйте это значение, чтобы перекрестно сослаться со связанными значениями в любых других таблицах, особенно для запросов join. Например, вместо того, чтобы принять название страны как входное значение и сделать запросы, ищущие то же самое имя, сделайте один поиск, чтобы определить ID страны, затем сделайте другие запросы (или единственный запрос), чтобы искать релевантную информацию в нескольких таблицах. Вместо того, чтобы хранить клиента или номер изделия по каталогу как строку цифр, потенциально израсходовав несколько байтов, преобразуйте это в числовой ID для хранения и запросов. 4 байтный столбец INT может индексировать более чем 4 миллиарда элементов. Для диапазонов различных типов целого числа см. раздел 12.2.1.

Файлы, связанные с таблицами InnoDB

Файлы InnoDB требуют большей заботы, чем MyISAM:

16.8.5. Обработка AUTO_INCREMENT в InnoDB

InnoDB обеспечивает конфигурируемый механизм блокировки, который может значительно улучшить масштабируемость и исполнение запросов SQL, которые добавляют строки к таблицам со столбцами AUTO_INCREMENT. Чтобы использовать механизм AUTO_INCREMENT с таблицей InnoDB, столбец AUTO_INCREMENT должен быть определен как часть индексирования таким образом, что возможно выполнить эквивалент индексированного поиска SELECT MAX(ai_col) на таблице, чтобы получить максимальное значение столбца. Как правило, это достигнуто, делая столбец, который индексирует первый столбец некоторой таблицы.

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

Режимы блокировки AUTO_INCREMENT

Этот раздел описывает поведение режимов блокировки AUTO_INCREMENT, и как каждый режим блокировки затрагивает репликацию. Режимы блокировки сконфигурированы при запуске, используя innodb_autoinc_lock_mode.

Следующие термины использованы в описании innodb_autoinc_lock_mode:

Есть три возможных настройки для innodb_autoinc_lock_mode. Это 0, 1 или 2, соответственно для режимов traditional, consecutive или interleaved.

Значения использования режима блокировки AUTO_INCREMENT

Инициализация счетчика InnoDB AUTO_INCREMENT

Этот раздел описывает как InnoDB инициализирует счетчики AUTO_INCREMENT.

Если Вы определяете столбец AUTO_INCREMENT для таблица, табличный объект в памяти содержит специальный счетчик, названный счетчиком auto-increment, который используется, назначая новые значения для столбца.

В MySQL 5.7 и ранее счетчик автоинкремента сохранен только в основной памяти, не на диске. Инициализируя счетчик автоинкремента после перезапуска сервера, InnoDB выполнил бы эквивалент следующего запроса о первой вставке в таблицу, содержащую столбец AUTO_INCREMENT.

SELECT MAX(ai_col) FROM table_name FOR UPDATE;

В MySQL 8.0 это не так. Текущее максимальное значение счетчика написано в журнал redo каждый раз, когда это изменяется и сохранено в приватной системной таблице механизма на каждой контрольной точке. Эти изменения делают текущее максимальное значение счетчика постоянным через перезапуски сервера.

При перезапуске сервера после нормального завершения работы InnoDB инициализирует счетчик в памяти с использованием текущего максимального значения, сохраненного в системной таблице словаря данных.

При перезапуске во время восстановления катастрофического отказа InnoDB инициализирует счетчик в памяти с использованием текущего максимального значения, сохраненного в системной таблице словаря данных, и просматривает журнал redo для значений счетчика, записанных, начиная с последней контрольной точки. Если зарегистрированное значение больше, чем встречное значение в памяти, зарегистрированное значение применено. Однако, в случае катастрофического отказа сервера, повторное использование ранее выделенного значения не может быть гарантировано. Каждый раз, когда текущее максимальное значение изменено из-за INSERT или UPDATE, новое значение записано в журнал, но если катастрофический отказ происходит прежде, чем журнал сброшен на диск, ранее выделенное значение могло быть снова использовано, когда счетчик инициализирован после того, как сервер перезапущен.

Единственное обстоятельство, когда InnoDB использует эквивалент SELECT MAX(ai_col) FROM table_name FOR UPDATE в MySQL 8.0, это инициализируя счетчик, импортируя табличное пространство без файла метаданных .cfg. Иначе текущее максимальное значение счетчика считано из файла метаданных .cfg.

В MySQL 5.7 и ранее, перезапуск сервера отменяет эффект опции AUTO_INCREMENT = N, которая может использоваться в CREATE TABLE или ALTER TABLE, чтобы установить начальное значение или изменить существующее значение, соответственно. В MySQL 8.0 перезапуск сервера не отменяет эффект AUTO_INCREMENT=N . Если Вы инициализируете автоинкремент в противоречии с определенным значением, или если Вы изменяете счетчик к большему значению, новое значение сохранено через перезапуски сервера.

ALTER TABLE ... AUTO_INCREMENT = N может изменить счетчик только к значению больше, чем текущий максимум.

В MySQL 5.7 и ранее перезапуск сервера немедленно после a ROLLBACK мог привести к повторному использованию значений автоинкремента, которые были ранее выделены отмененной транзакции, эффективно понижая текущее максимальное значение автоинкремента до прежнего уровня. В MySQL 8.0, текущее максимальное значение сохранено, предотвращая повторное использование ранее выделенных значений.

Если SHOW TABLE STATUS исследует таблицу прежде, чем счетчик будет инициализирован, InnoDB открывает таблицу и инициализирует значение, используя текущее максимальное значение автоинкремента, которое сохранено в системной таблице словаря данных. Значение сохранено в памяти для использования позже. Инициализация встречного значения использует нормальное исключительно блокирующее чтение на таблице, которое длится до конца транзакции. InnoDB следует за той же самой процедурой, инициализируя счетчик автоинкремента для недавно составленной таблицы, у которой есть определенное пользователем значение, которое больше 0.

После того, как счетчик инициализирован, если Вы явно не определяете значение автоинкремента, вставляя строку, InnoDB неявно постепенно увеличивает счетчик и назначает новое значение столбцу. Если Вы вставляете строку, которая явно определяет значение столбца auto-increment, и значение больше, чем текущее максимальное значение, счетчик установлен в указанное значение.

InnoDB использует счетчик auto-increment в памяти пока выполняется сервер. Когда сервер остановлен и перезапущен, InnoDB повторно инициализирует счетчик, как описано ранее.

Опция auto_increment_offset определяет начальную точку для значения AUTO_INCREMENT. Настройка по умолчанию 1.

Опция auto_increment_increment управляет интервалом между последовательными значениями столбцов. Настройка по умолчанию 1.

16.8.6. InnoDB и ограничения FOREIGN KEY

Этот раздел описывает различия в обработке механизма хранения InnoDB внешних ключей по сравнению с MySQL Server.

Для информации об использовании внешнего ключа и примеров см. раздел 14.1.15.3.

Определения внешнего ключа

Определения внешнего ключа для InnoDB таблицы подвергаются следующим условиям:

Ссылочные действия

Ссылочные действия для внешних ключей таблицы InnoDB подвергаются следующим условиям:

Ограничения внешнего ключа для произведенных столбцов и виртуальных индексов

Использование внешнего ключа и информация об ошибке

Вы можете получить общую информацию о внешних ключах и их использовании, запрашивая таблицу INFORMATION_SCHEMA.KEY_COLUMN_USAGE, больше информации, более определенной для таблиц InnoDB, может быть найдено в таблицах INNODB_SYS_FOREIGN и INNODB_SYS_FOREIGN_COLS базы данных INFORMATION_SCHEMA.

В дополнение к SHOW ERRORS, в случае ошибочного вовлечения внешнего ключа таблицами InnoDB (обычно Error 150 в MySQL Server), Вы можете получить подробное объяснение ошибки внешнего ключа, проверяя вывод SHOW ENGINE INNODB STATUS.

16.8.7. Пределы на таблицах InnoDB

Это не хорошая идея сконфигурировать InnoDB, чтобы использовать файлы с данными или файлы системного журнала на томах NFS. Файлы могли бы быть заблокированы другими процессами и становиться недоступными к использованию MySQL.

Максимумы и минимумы

Ограничения на таблицы InnoDB

Блокировка и транзакции

16.8.8. Кластеризируемый и вторичный индексы

У каждой таблицы InnoDB есть специальный кластеризируемый индекс, где данные для строк хранятся. Как правило, кластеризируемый индекс синонимичен с первичным ключом. Чтобы получить лучшую работу от запросов, вставок и других операций базы данных, Вы должны понять, как использовать кластеризируемый индекс, чтобы оптимизировать наиболее распространенный поиск и операции DML для каждой таблицы.

Как кластеризируемый индекс ускоряет запросы

Доступ к строке через кластеризируемый индекс быстр, потому что поиск приводит непосредственно к странице со всеми данными о строке. Если таблица является большой, кластеризируемый индекс часто уменьшает дисковую нагрузку ввода/вывода по сравнению с организациями хранения, которые хранят данные о строке, используя иную страницу для индексной записи. Например, MyISAM использует один файл для строк данных и другой для индексных записей.

Как вторичный индекс связан с кластеризируемым

Все индексирует кроме кластеризируемого известны как вторичные. В InnoDB каждая запись во вторичном индексе содержит столбцы первичного ключа для строки, так же как столбцы, определенные для вторичного индекса. InnoDB применяет это значение первичного ключа, чтобы искать строку в кластеризируемом индексе.

Если первичный ключ длинен, вторичные индексы используют больше пространства, таким образом, выгодно иметь короткий первичный ключ.

См. подробности в разделах 9.3.2, 9.3, 9.5 и 9.3.2.

16.8.9. Индексы InnoDB FULLTEXT

Индексы FULLTEXT создаются на основанных на тексте столбцах (CHAR, VARCHAR или TEXT), чтобы ускорить запросы и операции DML на данных в пределах тех столбцов, опуская любые слова, которые определены как stopword.

Индекс FULLTEXT может быть определен как часть CREATE TABLE или добавлен позже с использованием ALTER TABLE или CREATE INDEX.

Полнотекстовый поиск выполнен, используя MATCH() ... AGAINST. Подробности в разделе 13.9.

Проект индекса Full-Text

Индексы InnoDB FULLTEXT имеют проект инвертированного индекса. Инвертированные индексы хранят список слов, и для каждого слова, список документов, в которых появляется слово. Чтобы поддержать поиск близости, информация о положении для каждого слова также сохранена, как смещение байта.

Таблицы полнотекстового индекса

Для каждого индекса FULLTEXT ряд индексных таблиц создается, как показано в следующем примере:

CREATE TABLE opening_lines (id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY
       KEY, opening_line TEXT(500), author VARCHAR(200),
       title VARCHAR(200), FULLTEXT idx (opening_line)) ENGINE=InnoDB;

mysql> SELECT table_id, name, space from
                 INFORMATION_SCHEMA.INNODB_SYS_TABLES
                 WHERE name LIKE 'test/%';
+----------+----------------------------------------------------+-------+
| table_id | name                                               | space |
+----------+----------------------------------------------------+-------+
|  333     | test/FTS_0000000000000147_00000000000001c9_INDEX_1 |   289 |
|  334     | test/FTS_0000000000000147_00000000000001c9_INDEX_2 |   290 |
|  335     | test/FTS_0000000000000147_00000000000001c9_INDEX_3 |   291 |
|  336     | test/FTS_0000000000000147_00000000000001c9_INDEX_4 |   292 |
|  337     | test/FTS_0000000000000147_00000000000001c9_INDEX_5 |   293 |
|  338     | test/FTS_0000000000000147_00000000000001c9_INDEX_6 |   294 |
|  330     | test/FTS_0000000000000147_BEING_DELETED            |   286 |
|  331     | test/FTS_0000000000000147_BEING_DELETED_CACHE      |   287 |
|  332     | test/FTS_0000000000000147_CONFIG                   |   288 |
|  328     | test/FTS_0000000000000147_DELETED                  |   284 |
|  329     | test/FTS_0000000000000147_DELETED_CACHE            |   285 |
|  327     | test/opening_lines                                 |   283 |
+----------+----------------------------------------------------+-------+

Первые шесть таблиц представляют инвертированный индекс и упоминаются, как вспомогательные индексные таблицы. Когда поступающие документы размечены, отдельные слова (также называемые токенами) вставлены в индексные таблицы наряду с информацией о положении и связанным Document ID (DOC_ID). Слова полностью сортированы и разделены среди этих шести индексных таблиц, основываясь на весе вида набора символов первого символа слова.

Инвертированный индекс разделен на шесть вспомогательных индексных таблицы, чтобы поддержать параллельное создание индексов. По умолчанию два потока размечают, сортируют и вставляют слова и связанные данные в таблицы. Число потоков конфигурируемое с использованием опции innodb_ft_sort_pll_degree. Создавая FULLTEXT на больших таблицах, рассмотрите увеличивание числа потоков.

Имена таблиц предварительно установлены с префиксом FTS_ и постфиксом INDEX_*. Каждая таблица связана с индексированной таблицей значением в имени индексной таблицы, которое соответствует table_id индексированной таблицы. Например, table_id из test/opening_lines 327 для которого шестнадцатеричное значение 0x147. Как показано в предыдущем примере, 147 появляется в названиях индексных таблиц, которые связаны с test/opening_lines.

Значение представляющее index_id индекса FULLTEXT также появляется в именах вспомогательных индексных таблиц. Например, во вспомогательном имени таблицы test/FTS_0000000000000147_00000000000001c9_INDEX_1 это 1c9, в десятичном виде 457. Индекс определен в таблице opening_lines (idx) и может быть идентифицирован, запрашивая из таблицы INFORMATION_SCHEMA.INNODB_SYS_INDEXES его значение (457).

mysql> SELECT index_id, name, table_id, space
                 from INFORMATION_SCHEMA.INNODB_SYS_INDEXES
                 WHERE index_id=457;
+----------+------+----------+-------+
| index_id | name | table_id | space |
+----------+------+----------+-------+
|  457     | idx  |  327     |   283 |
+----------+------+----------+-------+

Индексные таблицы сохранены в их собственном табличном пространстве, если основная таблица составлена в табличном пространстве file-per-table.

Другие индексные таблицы, показанные в предыдущем примере, используются для обработки удаления и для того, чтобы сохранить внутреннее состояние индекса FULLTEXT.

Кэш полнотекстового индекса

Когда документ вставлен, он размечен, и отдельные слова и связанные данные вставлены в таблицу, чтобы рассмотреть размеченные данные для недавно вставленных строк. Этот процесс, даже для маленьких документов, мог привести к многочисленным небольшим вставкам во вспомогательные таблицы, делая параллельный доступ к этим таблицам предметом спора. Чтобы избежать этой проблемы, InnoDB использует кэш индекса FULLTEXT, чтобы временно кэшировать табличные вставки для недавно вставленных строк. Эта структура в кэш-памяти содержит вставки, пока кэш не заполнится, и затем пакетом сбрасывает их на диск (к вспомогательной индексной таблице). Вы можете запросить таблицу INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE, чтобы смотреть размеченные данные для недавно вставленных строк.

Поведение кэширования и пакета избегает частых обновлений вспомогательных таблиц, которые могли привести к параллельным проблемам доступа во время занятой вставки и обновления. Метод группирования также избегает многократных вставок для того же самого слова и минимизирует двойные записи. Вместо того, чтобы сбросить каждое слово индивидуально, вставки для того же самого слова слиты и сбрасываются на диск как единственная запись, улучшая эффективность вставки, в то время как размер индексных таблиц как можно меньше.

Переменная innodb_ft_cache_size используется, чтобы сконфигурировать размер кэша (на основе таблицы), который затрагивает, как часто полнотекстовый индексный кэш сбрасывается. Вы можете также определить глобальный предел размера кэша для всех таблиц в приведенном примере, используя опцию innodb_ft_total_cache_size.

Полнотекстовый индексный кэш хранит ту же самую информацию, как и вспомогательные индексные таблицы. Однако, полнотекстовый индексный кэш кэширует только размеченные данные для недавно вставленных строк. Данные, которые уже сброшены на диск (к полнотекстовым вспомогательным таблицам) не возвращены в кэш когда запрошены. Данные во вспомогательных таблицах запрошены непосредственно, и результаты из вспомогательных таблиц слиты с результатами из кэша прежде, чем быть возвращенными.

ID документа и столбец FTS_DOC_ID

InnoDB использует уникальный идентификатор документа, называемый Document ID (DOC_ID), чтобы отобразить слова в полнотекстовом индекс на записи, где слово появляется. Отображение требует столбца FTS_DOC_ID в индексированной таблице. Если FTS_DOC_ID не определен, InnoDB автоматически добавляет скрытый столбец FTS_DOC_ID, когда полнотекстовый индекс создается. Следующий пример демонстрирует это поведение.

Следующее табличное определение не включает FTS_DOC_ID:

CREATE TABLE opening_lines (id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY
       KEY, opening_line TEXT(500), author VARCHAR(200),
       title VARCHAR(200)) ENGINE=InnoDB;

Когда Вы создаете полнотекстовый индекс, используя CREATE FULLTEXT INDEX, предупреждение возвращено, которое сообщает о том, что InnoDB переделывает таблицу, чтобы добавить столбец FTS_DOC_ID.

mysql> CREATE FULLTEXT INDEX idx ON opening_lines(opening_line);
Query OK, 0 rows affected, 1 warning (0.19 sec)
Records: 0  Duplicates: 0  Warnings: 1

mysql> SHOW WARNINGS;
+---------+------+--------------------------------------------------+
| Level   | Code | Message                                          |
+---------+------+--------------------------------------------------+
| Warning |  124 | InnoDB rebuilding table to add column FTS_DOC_ID |
+---------+------+--------------------------------------------------+

То же самое предупреждение возвращено, используя ALTER TABLE, чтобы добавить полнотекстовый индекс к таблице, которая не имеет столбца FTS_DOC_ID. Если Вы создаете полнотекстовый индекс через CREATE TABLE и не определяете FTS_DOC_ID, InnoDB добавляет скрытый столбец FTS_DOC_ID без предупреждения.

Определение FTS_DOC_ID в CREATE TABLE уменьшает время, требуемое, чтобы создать полнотекстовый индекс на таблице, которая уже загружена данными. Если столбец FTS_DOC_ID определен на таблице до загрузки данных, таблица и индекс не должны быть переделаны, чтобы добавить новый столбец. InnoDB создает скрытый столбец FTS_DOC_ID наряду с уникальным индексом (FTS_DOC_ID_INDEX) на столбце FTS_DOC_ID. Если Вы хотите создать свой собственный FTS_DOC_ID, столбец должен быть определен как BIGINT UNSIGNED NOT NULL и назван FTS_DOC_ID (все буквы большие), как в следующем примере:

Столбец FTS_DOC_ID не должен быть определен как AUTO_INCREMENT, но AUTO_INCREMENT мог сделать загрузку данных легче.

CREATE TABLE opening_lines (
       FTS_DOC_ID BIGINT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
       opening_line TEXT(500), author VARCHAR(200), title VARCHAR(200))
       ENGINE=InnoDB;

Если Вы хотите определять FTS_DOC_ID самостоятельно, Вы ответственны за управление столбцом, чтобы избежать пустых или двойных значений. Значения FTS_DOC_ID не могут быть снова использованы, что означает, что значения FTS_DOC_ID должны когда-либо увеличиваться.

Произвольно Вы можете создать необходимый уникальный FTS_DOC_ID_INDEX на столбце FTS_DOC_ID.

CREATE UNIQUE INDEX FTS_DOC_ID_INDEX on opening_lines(FTS_DOC_ID);

Если Вы не создаете FTS_DOC_ID_INDEX, InnoDB создает это автоматически.

Разрешенный промежуток между используемым самым большим значением FTS_DOC_ID и новым значением FTS_DOC_ID 65535.

Обработка удаления полнотекстового индекса

Удаление записи, у которой есть полнотекстовый индекс, может привести к многочисленным маленьким удалениям во вспомогательных индексных таблицах, делая параллельный доступ к этим таблицам предметом спора. Чтобы избежать этой проблемы, Document ID (DOC_ID) из удаленного документа зарегистрирован в спецтаблице FTS_*_DELETED всякий раз, когда запись удалена из индексированной таблицы, и запись остается в полнотекстовом индексе. Перед возвращением результатов запроса, информация в FTS_*_DELETED используется, чтобы отфильтровать удаленные Document ID. Выгода этого проекта то, что удаления быстры и недороги. Недостаток состоит в том, что размер индекса не был немедленно уменьшен после удаления записей. Чтобы удалить полнотекстовые индексные записи, надо выполнить OPTIMIZE TABLE на индексированной таблице с innodb_optimize_fulltext_only=ON, чтобы восстановить полнотекстовый индекс.

Обработка транзакций Full-Text

Индексы FULLTEXT имеют специальные операционные характеристики управляемости, описывающие поведение кэширования и пакетной обработки данных. Определенно, обновления и вставки на индексе FULLTEXT обработаны в момент закрытия транзакции, что означает, что поиск FULLTEXT может видеть только переданные данные. Следующий пример демонстрирует это поведение. FULLTEXT возвращает результат после того, как вставленные строки переданы.

mysql> CREATE TABLE opening_lines (
                 id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
                 opening_line TEXT(500), author VARCHAR(200),
                 title VARCHAR(200), FULLTEXT idx (opening_line))
                 ENGINE=InnoDB;
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO opening_lines(opening_line,author,title) VALUES
   ('Call me Ishmael.','Herman Melville','Moby-Dick'),
   ('A screaming comes across the sky.','Thomas Pynchon','Gravity\'s Rainbow'),
   ('I am an invisible man.','Ralph Ellison','Invisible Man'),
   ('Where now? Who now? When now?','Samuel Beckett','The Unnamable'),
   ('It was love at first sight.','Joseph Heller','Catch-22'),
   ('All this happened, more or less.','Kurt Vonnegut','Slaughterhouse-Five'),
   ('Mrs. Dalloway said she would buy the flowers herself.','Virginia Woolf','Mrs. Dalloway'),
   ('It was a pleasure to burn.','Ray Bradbury','Fahrenheit 451');
Query OK, 8 rows affected (0.00 sec)
Records: 8  Duplicates: 0  Warnings: 0

mysql> SELECT COUNT(*) FROM opening_lines WHERE MATCH(opening_line)
                 AGAINST('Ishmael');
+----------+
| COUNT(*) |
+----------+
| 0        |
+----------+

mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT COUNT(*) FROM opening_lines WHERE MATCH(opening_line)
                 AGAINST('Ishmael');
+----------+
| COUNT(*) |
+----------+
| 1        |
+----------+

Контроль полнотекстовых индексов

Вы можете контролировать и исследовать специальные относящиеся к обработке текстов аспекты InnoDB FULLTEXT, запрашивая следующие таблицы INFORMATION_SCHEMA:

Вы можете также рассмотреть основную информацию для индексов FULLTEXT и таблиц, запрашивая INNODB_SYS_INDEXES и INNODB_SYS_TABLES .

См. раздел 16.14.4.

16.8.10. Физическая структура индексов InnoDB

За исключением пространственного индекса, индексы InnoDB это структуры данных B-tree. Пространственный индекс использует R-tree, которые являются специализированными структурами данных для того, чтобы индексировать многомерные данные. Индексные записи сохранены в страницах листа их структуры данных B-tree или R-tree. Размер по умолчанию индексной страницы составляет 16 КБ.

Когда новые записи вставлены в кластеризируемый индекс, InnoDB попытается оставить 1/16 страницы свободной для будущих вставок и обновлений. Если индексные записи вставлены в последовательном порядке (возрастание или убывание), получающиеся индексные страницы полны на 15/16. Если записи вставлены в случайном порядке, страницы полны от 1/2 до 15/16.

InnoDB выполняет оптовую загрузку, когда создает B-tree индексов. Этот метод создания индекса известен как сортированный индекс. innodb_fill_factor определяет процент пространства на каждой странице B-дерева, который заполнен во время создания сортированного индекса с остающимся пространством, сохраненным для будущего роста. Создание сортированного индекса не поддержанр для пространственного индекса. Для получения дополнительной информации см. раздел 16.8.11. innodb_fill_factor устанавливает 1/16 пространства в кластеризируемых индексных страницах свободным для будущего роста.

Если коэффициент заполнения индексной страницы понижается ниже MERGE_THRESHOLD, который составляет 50% по умолчанию, если не определен InnoDB пробует сократить индексное дерево, чтобы освободить страницу. MERGE_THRESHOLD относится к B-tree и R-tree. Подробности в разделе 16.6.11.

Вы можете сконфигурировать размер страницы для всех табличных пространств InnoDB, задав опцию innodb_page_size прежде, чем создать экземпляр. Как только размер страницы установлен, Вы не можете изменить его. Поддержанные размеры составляют 64KB, 32KB, 16KB (значение по умолчанию), 8KB и 4KB, соответствуя значениям опции 64k, 32k, 16k, 8k и 4k.

16.8.11. Создание сортированного индекса

InnoDB выполняет оптовую загрузку вместо того, чтобы вставить каждую запись в то время, когда создает индекс. Этот метод известен как создание сортированного индекса. Сортированный индекс не поддержан для пространственного индекса.

Есть три фазы создания индекса. В первой фазе кластеризируемый индекс просмотрен, и индексные записи произведены и добавлены к буферу. Когда буфер сортировки становится полным, записи сортированы и записаны во временный промежуточный файл. Этот процесс также известен как run. Во второй фазе, с одним или более выполнениями, записанными во временный промежуточный файл, сортировка слиянием выполнена на всех записях в файле. В третьей и заключительной фазе сортированные записи вставлены в B-tree.

До введения сортированных индексов записи были вставлены в B-tree поштучно, используя insert API. Этот метод вовлекал открытие B-tree курсора, чтобы найти позицию вставки, а затем вставку записей в страницу B-tree, используя оптимистическуювставку. Если бы вставка потерпела неудачу из-за полной страницы, то пессимистическая вставка была бы выполнена, которая вовлекает открытие курсора B-tree, разделение и слияние узлов B-tree по мере необходимости, чтобы найти пространство для входа. Недостатки этого метод создания индексирования являются стоимостью поиска позиции вставки и постоянного разделения и слияния узлов B-tree.

Сортированный индекс использует восходящий подход к созданию индекса. С этим подходом ссылка на самую правую страницу листа проводится на всех уровнях B-tree. Самая правая страница листа в необходимой глубине B-tree выделена, и записи вставлены согласно их сортированному порядку. Как только страница листа полна, указатель узла приложен к родительской странице, и страница листа выделена для следующей вставки. Этот процесс продолжается, пока все записи не вставлены, что может привести к вставкам до уровня корня. Когда страница выделена, ссылка на ранее прикрепленную страницу листа выпущена, и недавно выделенная страница листа становится самой правой страницей листа (и новым значением по умолчанию места для вставки).

Резервирование места на страницах B-tree для будущего роста индекса

Чтобы отложить пространство для будущего индексного роста, Вы можете использовать опцию innodb_fill_factor, чтобы зарезервировать процент пространства страницы B-tree. Например, установка innodb_fill_factor в 80 резервирует 20 процентов пространства в страницах B-tree во время создания сортированного индекса. Эта установка относится к страницам листа и не к страницам листа B-tree. Это не относится к внешним страницам, используемым для TEXT или BLOB. Количество пространства, которое сохранено, не может быть точно сконфигурировано, поскольку innodb_fill_factor интерпретируется как подсказка, а не жесткий предел.

Создание сортированного индекса и поддержка Fulltext Index

Создание сортированного индекса поддерживается для индексов fulltext. Ранее SQL использовался, чтобы вставить записи в индексы fulltext.

Создание сортированного индекса и сжатые таблицы

Для сжатых таблиц предыдущие метод создания индекса добавляет записи в сжатые и в несжатые страницы. Когда журнал модификации (представляющий свободное пространство на сжатой странице) станет полным, сжатая страница будет пересжата. Если бы сжатие потерпело неудачу из-за недостатка места, то страница была бы разделена. С сортированным индексом записи добавлены только к несжатым страницам. Когда несжатая страница становится полной, она сжата. Адаптивное дополнение используется, чтобы гарантировать, что сжатие преуспевает в большинстве случаев, но если сжатие терпит неудачу, страница разделена, и сжатие предпринято снова. Этот процесс продолжается, пока сжатие не пройдет успешно. Для дополнительной информации о сжатии страниц B-Tree см. раздел 16.9.1.5.

Создание сортированного индекса и журнал Redo

Журнал Redo выключен во время создания сортированного индекса. Вместо этого есть контрольная точка, чтобы гарантировать, что индексирование может противостоять катастрофическому отказу. Контрольная точка вызывает запись всех грязных страниц на диск. Во время создания сортированного индекса поток уборщика страницы вызван периодически, чтобы сбросить грязные страницы, чтобы гарантировать, что работа контрольной точки может быть обработана быстро. Обычно поток уборщика сбрасывает грязные страницы, когда число чистых страниц падает ниже порога набора. При создании сортированного индекса грязные страницы сбрасываются быстро, чтобы уменьшить издержки контрольной точки.

Создание сортированного индекса и статистика оптимизатора

Создание сортированного индекса может привести к статистическим данным, которые отличаются от произведенных предыдущим методом создания индекса, используемым в более ранних выпусках MySQL. Различие в статистике, которое, как ожидают, не затронет рабочую нагрузку, происходит из-за различного алгоритма, который используется, чтобы заполнить индекс.

16.9. Таблица InnoDB и сжатие страницы

Этот раздел предоставляет информацию о табличном сжатии и особенности сжатия страницы. Особенность сжатия страницы также упоминается как прозрачное сжатие страницы.

Используя функции сжатия InnoDB, Вы можете составить таблицы, где данные хранятся в сжатой форме. Сжатие может помочь улучшить сырую работу и масштабируемость. Сжатие означает, что меньше данных передано между диском и памятью, и занимает меньше места на диске и в памяти. Выгода усилена для таблиц с вторичными индексами , потому что индексные данные сжаты также. Сжатие может быть особенно важным для устройств хранения данных SSD из-за их низкой емкости.

16.9.1. Табличное сжатие InnoDB

Этот раздел описывает табличное сжатие, которое поддержано таблицами, которые находятся в табличных пространствах file_per_table или общих табличных пространствах . Табличное сжатие включено, используя атрибут ROW_FORMAT=COMPRESSED с CREATE TABLE или ALTER TABLE.

16.9.1.1. Краткий обзор табличного сжатия

Поскольку процессоры и кэш-память увеличили в скорости больше, чем дисковые устройства хранения данных, много рабочих нагрузок являются зависящими от диска. Сжатие данных приводит к меньшему размеру базы данных, уменьшенному вводу/выводу и улучшенной пропускной способности, при маленькой стоимости увеличенного использования центрального процессора. Сжатие особенно ценно для интенсивных чтением приложений, на системах с достаточным количеством RAM, чтобы сохранить часто используемые данные в памяти.

Таблица, составленная с ROW_FORMAT=COMPRESSED может использовать меньший размер страницы на диске, чем сконфигурировано innodb_page_size . Меньшие страницы требуют меньше ввода/вывода, который особенно ценен для устройств SSD.

Сжатый размер страницы определен через параметр KEY_BLOCK_SIZE в CREATE TABLE или ALTER TABLE . Различный размер страницы требует, чтобы таблица была помещена в табличное пространство file-per-table или в общее табличное пространство, а не в системное табличное пространство, поскольку системное табличное пространство не может сохранить сжатые таблицы. Для получения дополнительной информации см. разделы 16.7.4 и 16.7.9.

Уровень сжатия не зависит от KEY_BLOCK_SIZE. Поскольку Вы определяете меньшие значения для KEY_BLOCK_SIZE, Вы извлекаете пользу ввода/вывода из все более и более меньших страниц. Но если Вы определяете значение, которое является слишком маленьким, будут лишние накладные расходы, чтобы реорганизовать страницы, когда значения данных не могут быть сжаты достаточно, чтобы разместить много строк в каждой странице. Есть жесткий предел нижнего размера KEY_BLOCK_SIZE, который может быть для таблицы, основанный на длинах ключевых столбцов для каждого из индексов. Определите значение, которое является слишком маленьким, и CREATE TABLE или ALTER TABLE не сработают.

В буферном пуле сжатые данные проводятся в маленьких страницах, с размером страницы, основанным на KEY_BLOCK_SIZE. Для извлечения или обновления значений столбцов MySQL также создает несжатую страницу в буферном пуле с несжатыми данными. В буферном пуле любые обновления несжатой страницы также переписаны назад к эквивалентной сжатой странице. Вы, возможно, должны были бы измерить свой буферный пул, чтобы приспособить дополнительные данные и сжатых и несжатых страниц, хотя несжатые страницы вычеркиваются из буферного пула, когда пространство необходимо, и затем разсжаты снова при следующем доступе.

16.9.1.2. Составление сжатых таблиц

Сжатые таблицы могут быть составлены в табличных пространствах file-per-table или в общих табличных пространствах . Табличное сжатие недоступно для системного табличного пространства. Системное табличное пространство (файлы .ibdata) может содержать создаваемые пользователем таблицы, но оно также содержит внутренние системные данные, которые никогда не сжимаются. Таким образом, сжатие применяется только к таблицам и индексам, сохраненным в file-per-table или общих табличных пространствах.

Составление сжатой таблицы в табличном пространстве File-Per-Table

Чтобы создать сжатую таблицу в табличном пространстве file-per-table, innodb_file_per_table должен быть включен (значение по умолчанию). Вы можете установить эти параметры в конфигурационном файле MySQL (my.cnf или my.ini) или динамически с использованием SET.

После настройки опции innodb_file_per_table определите параметр ROW_FORMAT=COMPRESSED, KEY_BLOCK_SIZE или оба в CREATE TABLE или ALTER TABLE, чтобы составить сжатую таблицу в табличном пространстве file-per-table.

Например, Вы могли бы использовать следующие запросы:

SET GLOBAL innodb_file_per_table=1;
CREATE TABLE t1 (c1 INT PRIMARY KEY) ROW_FORMAT=COMPRESSED
       KEY_BLOCK_SIZE=8;
Составление сжатой таблицы в общем табличном пространстве

Чтобы создать сжатую таблицу в общем табличном пространстве, FILE_BLOCK_SIZE должен быть определен для общего табличного пространства, которое определено, когда табличное пространство создается. FILE_BLOCK_SIZE должно быть допустимым сжатым размером страницы относительно innodb_page_size, размер страницы сжатой таблицы, определенной параметром KEY_BLOCK_SIZE в CREATE TABLE или ALTER TABLE должен быть равным FILE_BLOCK_SIZE/1024. Например, если innodb_page_size=16384 и FILE_BLOCK_SIZE=8192, KEY_BLOCK_SIZE должен быть 8. Для получения дополнительной информации см. раздел 16.7.9.

Следующий пример демонстрирует создание общего табличного пространства и добавление сжатой таблицы. Пример принимает значение по умолчанию innodb_page_size 16K. FILE_BLOCK_SIZE = 8192 требует, чтобы у сжатой таблицы был KEY_BLOCK_SIZE = 8.

mysql> CREATE TABLESPACE `ts2` ADD DATAFILE 'ts2.ibd'
                 FILE_BLOCK_SIZE = 8192 Engine=InnoDB;
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE t4 (c1 INT PRIMARY KEY) TABLESPACE ts2
                 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
Query OK, 0 rows affected (0.00 sec)
Примечания
Ограничения на сжатые таблицы

16.9.1.3. Настройка сжатия для таблиц InnoDB

Потому что эффективность сжатия зависит от природы Ваших данных, Вы можете принять решения, которые затрагивают исполнение сжатых таблиц:

Когда Вы готовы провести долгосрочное тестирование и поместить сжатые таблицы в производство см. раздел 16.9.1.4 для способов проверить эффективность выбора в условиях реального мира.

Когда использовать сжатие

Вообще, сжатие работает лучше всего с таблицами, которые включают разумное число столбцов символьных строк и где данные считаны намного чаще, чем записаны. Поскольку нет никаких гарантируемых способов предсказать, приносит ли сжатие пользу в особой ситуации, всегда проверяйте с определенной рабочей нагрузкой и набором данных, работающим на представительной конфигурации. Рассмотрите следующие факторы, решая которые таблицы сжать.

Характеристики данных и сжатие

Ключевой детерминант эффективности сжатия в сокращении размера файлов с данными является природой данных. Вспомните, что сжатие работает, идентифицируя повторные строки байтов в блоке данных. Полностью рандомизированные данные худший случай. Типичные данные часто повторяют значения, там сжатие эффективно. Строки символов часто сжимаются хорошо, независимо от типа столбца CHAR, VARCHAR, TEXT или BLOB. С другой стороны, таблицы, содержащие главным образом двоичные данные (целые числа или числа с плавающей запятой) или данные, которые ранее сжаты (например, изображения JPEG или PNG), возможно, не сжимаются хорошо, значительно или вообще.

Вы выбираете, включить ли сжатие для каждой таблицы InnoDB. Таблица и весь индекс используют тот же самый (сжатый) размер страницы. Могло бы случиться так, что that the первичный ключ (кластеризируемый) индекс, который содержит данные для всех столбцов таблицы, сжимается эффективнее, чем вторичный индекс. Для тех случаев, где есть длинные строки, использование сжатия могло бы привести к длинным значениям столбцов, сохраненным вне страницы, как обсуждает раздел 16.10.3. Те страницы переполнения можно сжать хорошо. Для многих приложений некоторые таблицы сжимаются эффективнее, чем другие, и Вы могли бы найти, что Ваша рабочая нагрузка выступает лучше всего только с подмножеством сжатых таблиц.

Чтобы определить, сжать ли особую таблицу, проведите эксперименты. Вы можете получить грубую оценку того, как эффективно Ваши данные могут быть сжаты при использовании утилиты, которая осуществляет сжатие LZ77 (такой, как gzip или WinZip) на копии файла .ibd для несжатой таблицы. Вы можете ожидать, что будет меньше сжатия от MySQL для таблицы, чем от основанных на файле инструментов сжатия, потому что MySQL сжимает данные в кусках, основанных на размере страницы, 16KB по умолчанию. В дополнение к пользовательским данным формат страницы включает некоторые внутренние системные данные, которые не сжаты. Основанные на файле утилиты сжатия могут исследовать намного большие куски данных, и так найти повторные строки в огромном файле, чем MySQL может найти в отдельной странице.

Другой способ проверить сжатие на определенной таблице состоит в том, чтобы скопировать некоторые данные от Вашей несжатой таблицы в подобную сжатую таблицу (имеющую все те же индексы) в табличном пространстве file-per-table и смотреть на размер получающегося файла .ibd:

use test;
set global innodb_file_per_table=1;
set global autocommit=0;

-- Create an uncompressed table with a million or two rows.
create table big_table as select * from information_schema.columns;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
commit;
alter table big_table add id int unsigned not null primary key auto_increment;
show create table big_table\G
select count(id) from big_table;

-- Check how much space is needed for the uncompressed table.
\! ls -l data/test/big_table.ibd

create table key_block_size_4 like big_table;
alter table key_block_size_4 key_block_size=4 row_format=compressed;

insert into key_block_size_4 select * from big_table;
commit;

-- Check how much space is needed for a compressed table
-- with particular compression settings.
\! ls -l data/test/key_block_size_4.ibd

Этот эксперимент произвел следующие числа, которые, конечно, могли значительно измениться в зависимости от Вашей структуры таблицы и данных:

-rw-rw----  1 cirrus  staff  310378496 Jan  9 13:44 data/test/big_table.ibd
-rw-rw----  1 cirrus  staff   83886080 Jan  9 15:10 data/test/key_block_size_4.ibd

Чтобы понять, эффективно ли сжатие для Вашей особой рабочей нагрузки:

Сжатие базы данных против сжатия приложения

Решите, сжать ли данные в Вашем приложении или в таблице, не используйте оба типа сжатия для тех же самых данных. Когда Вы сжимаете данные в приложении и храните результаты в сжатой таблице, дополнительная экономия пространства крайне маловероятна, и двойное сжатие только тратит впустую циклы центрального процессора.

Сжатие в базе данных

Когда включено, табличное сжатие MySQL является автоматическим и относится ко всем столбцам. Столбцы могут все еще быть проверены с такими операторами, как LIKE, и операции сортировки могут все еще использовать индекс, даже когда индексированные значения сжаты. Поскольку индекс часто существенная фракция полного размера базы данных, сжатие могло привести к существенной экономии в хранении, вводе/выводе или времени процессора. Операции сжатия и декомпрессии происходят на сервере базы данных, который, вероятно, является сильной системой, которая измерена, чтобы обработать ожидаемую загрузку.

Сжатие в приложении

Если Вы сжимаете данные, такие как текст в Вашем приложении, прежде, чем это будет вставлено в базу данных, Вы могли бы сохранить заголовок для данных, которые не сжимаются хорошо, сжимая некоторые столбцы. Этот подход использует циклы центрального процессора для сжатия на машине клиента, а не сервере базы данных, который мог бы быть подходящим для распределенного приложения со многими клиентами, или где у машины клиента есть запасные циклы центрального процессора.

Гибридный подход

Конечно, возможно объединить эти подходы. Для некоторых приложений может быть уместно использовать некоторые сжатые таблицы и некоторые несжатые таблицы. Может быть лучшим внешне сжать некоторые данные (и сохранить в несжатых таблицах) и позволить MySQL сжимать другие таблицы приложения. Как всегда, грамотный проект и реальное тестирование ценны в достижении правильного решения.

Характеристики рабочей нагрузки и сжатие

В дополнение к выбору, какие таблицы сжать (и размер страницы), рабочая нагрузка это другой ключевой детерминант работы. Если приложение в основном читает, а не обновлено, меньше страниц должно быть реорганизовано и повторно сжато после того, как индексная страница исчерпывает место для страницы в журнале модификаций, который MySQL поддерживает для сжатых данных. Если обновления преобладающе изменяют неиндексированные столбцы или те, которые содержат BLOB или большие строки, которые сохранены вне страницы, издержки сжатия могут быть приемлемыми. Если единственные изменения таблицы INSERT, которые используют монотонно увеличивающийся первичный ключ, и есть немногие вторичные индексы, есть небольшая потребность реорганизовать и повторно сжать индексные страницы. Так как MySQL может помечать как удаленные и удалять строки на сжатых страницах на месте, изменяя несжатые данные, операцииDELETE на таблице относительно эффективны.

Для некоторой окружающей среды время, чтобы загрузить данные, может быть столь же важным, как извлечение во время выполнения. Особенно в окружающей среде хранилища данных много таблиц могут быть только для чтения или чтения главным образом. В тех случаях это могло бы или не могло бы быть приемлемым заплатить цену сжатия с точки зрения увеличенного времени загрузки, если получающиеся сбережения в меньшем количестве дисковых чтений или в стоимости хранения не являются существенными.

Сжатие работает лучше всего, когда время центрального процессора доступно для сжатия и разсжатия данных. Таким образом, если Ваша рабочая нагрузка ввод/вывод, а не центральный процессор, сжатие может улучшить эффективность работы. Когда Вы проверяете потребительские свойства с различными конфигурациями сжатия, проверяйте на платформе, подобной запланированной конфигурации производственной системы.

Характеристики конфигурации и сжатие

Чтение и запись страниц базы данных с диска являются самым медленным аспектом работы. Сжатие пытается уменьшить ввод/вывод при использовании времени центрального процессора, чтобы сжать данные, и является самым эффективным, когда ввод/вывод относительно недостаточный ресурс по сравнению с циклами процессора.

Когда страница сжатой таблицы находится в памяти, MySQL часто использует дополнительную память, как правило 16 КБ, в буферном пуле для несжатой копии страницы. Адаптивный алгоритм LRU пытается сбалансировать использование памяти между сжатыми и несжатыми страницами, чтобы принять во внимание, работает ли рабочая нагрузка в манере I/O или CPU. Однако, конфигурация с большей памятью, посвященной буферному пулу, имеет тенденцию работать лучше, когда используется сжатие таблицы, чем конфигурация, где память чрезвычайно ограничена.

Выбор сжатого размера страницы

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

Устанавливая сжатый размер страницы слишком большим, затратите некоторое пространство, но страницы не должны быть сжаты часто. Если сжатый размер страницы установлен слишком маленьким, вставки или обновления могут потребовать отнимающего много времени пересжатия, и узлы B-tree, вероятно, придется разделять чаще, приводя к большим файлам с данными и менее эффективной индексации.

Как правило, Вы устанавливаете сжатый размер страницы в 8K или 4K. Учитывая, что максимальный размер строки для таблицы InnoDB составляет приблизительно 8K, KEY_BLOCK_SIZE=8 обычно безопасный выбор.

16.9.1.4. Контроль сжатия во время выполнения

Полные потребительские свойства, центральный процессор и использование ввода/вывода и размер дисковых файлов это хорошие индикаторы того, как эффективно сжатие для Вашего приложения. Этот раздел основывается на совете из раздела 16.9.1.3 и показывает, как найти проблемы, которые не могли бы проявиться во время начального тестирования.

Вы можете контролировать работу сжатия во время выполнения, используя таблицы Information Schema , описанные в примере 16.10. Эти таблицы отражают внутреннее пользование памяти и уровни сжатия, используемого повсюду.

Таблица INNODB_CMP сообщает о информацию о деятельности сжатия для каждого сжатого размера страницы (KEY_BLOCK_SIZE). Информация в этих таблицах в масштабе всей системы: это суммирует статистику сжатия через все сжатые таблицы в Вашей базе данных. Вы можете использовать эти данные, чтобы помочь решить, сжать ли таблицу, исследуя эти таблицы, когда ни к каким другим сжатым таблицам не получают доступ. Это вовлекает относительно низкие издержки на сервере, таким образом, Вы могли бы периодически запрашивать это на производственном сервере, чтобы проверить полную эффективность сжатия.

Таблица INNODB_CMP_PER_INDEX сообщает о информацию о деятельности сжатия для отдельных таблиц и индексов. Эта информация предназначена и более полезна для того, чтобы оценить эффективность сжатия и диагностировать исполнительные проблемы одной таблицы или индекса за один раз. Поскольку каждая таблица представлена как кластеризируемый индекс, MySQL не делает большое различие между таблицами и индексами в этом контексте. Таблица INNODB_CMP_PER_INDEX действительно вовлекает существенные издержки, таким образом, это является более подходящим для серверов развития, где Вы можете сравнить эффекты различных рабочих нагрузок, данных и настроек сжатия в изоляции. Чтобы принять меры против наложения этого контроля на издержки, Вы должны включить опцию innodb_cmp_per_index_enabled прежде, чем Вы сможете запросить таблицу INNODB_CMP_PER_INDEX.

Ключевые статистические данные являются числом, и количеством времени на выполнение сжатия. Так как MySQL разделяет узлы B-tree, когда они слишком полны, чтобы содержать сжатые данные после модификации, сравните число успешных операций сжатия с числом таких операций вообще. Основываясь на информации в таблицах INNODB_CMP и INNODB_CMP_PER_INDEX , Вы могли бы произвести изменения в своей конфигурации аппаратных средств, скорректировать размер буферного пула, выбрать иной размер страницы или выбрать набор таблиц, чтобы сжать.

Если количество времени центрального процессора, требуемого для сжатия высоко, изменение на быстрый центральный процессор может помочь улучшить работу с теми же самыми данными, рабочую нагрузку приложения и набор сжатых таблиц. Увеличение размера буферного пула могло бы также помочь работе, так, чтобы несжатые страницы могли остаться в памяти, уменьшая потребность разсжимать страницы, которые существуют в памяти только в сжатой форме.

Большое количество операций сжатия (по сравнению с числом INSERT, UPDATE и DELETE в Вашем приложении и размером базы данных), может указать, что некоторые из Ваших сжатых таблиц обновляются слишком сильно для эффективного сжатия. Если это так, выберите больший размер страницы или разберитесь, которые таблицы Вы сжимаете.

Если число успешных операций сжатия (COMPRESS_OPS_OK) выше процента общего количества операций сжатия (COMPRESS_OPS), тогда система, вероятно, работает хорошо. Если отношение низко, то MySQL реорганизует, пересжимает и разделяет узлы B-tree чаще, чем желательно. В этом случае избегайте сжимать некоторые таблицы или увеличьте KEY_BLOCK_SIZE для некоторых из сжатых таблиц. Вы могли бы выключить сжатие для таблиц, которые заставляют число неудачных сжатий в Вашем приложении составлять больше 1%-2%. Такое отношение отказа могло бы быть приемлемым во время временной работы, такой как загрузка данных.

16.9.1.5. Как работает сжатие для таблиц InnoDB

Этот раздел описывает некоторые внутренние детали выполнения сжатия для таблиц InnoDB. Информация, представленная здесь, может быть полезной в настройке для работы, но не необходима, чтобы знать для основного использования сжатия.

Алгоритмы сжатия

Некоторые операционные системы осуществляют сжатие на уровне файловой системы. Файлы, как правило, делятся на блоки фиксированного размера, которые сжаты в блоки переменного размера, который легко приводит к фрагментации. Каждый раз, когда что-то в блоке изменено, целый блок повторно сжат прежде, чем он будет записан на диск. Эти свойства делают этот метод сжатия неподходящим для использования в интенсивной обновляемой системе базы данных.

MySQL осуществляет сжатие с помощью известной библиотеки zlib, которая осуществляет алгоритм сжатия LZ77. Этот алгоритм сжатия является зрелым, здравым и эффективным в использовании центрального процессора и в сокращении размера данных. Алгоритм без потерь, чтобы оригинальные несжатые данные могли всегда быть восстановлены от сжатой формы. Сжатие LZ77 работает, находя последовательности данных, которые повторены в пределах данных, которые будут сжаты. Образцы значений в Ваших данных определяют, как хорошо они сжимаются, но типичные пользовательские данные часто сжимаются на 50% или даже лучше.

В отличие от сжатия, выполненного приложением или особенностями сжатия некоторых других систем управления базой данных, сжатие InnoDB применяется к пользовательским данным и индексам. Во многих случаях индекс может составить 40-50% полного размера базы данных, таким образом, это различие является существенным. Когда сжатие работает хорошо на наборе данных, размер файлов с данными InnoDB (табличное пространство file-per-table общее табличное пространство файлы .idb) ужимает на 25%-50%. В зависимости от рабочей нагрузки, эта меньшая база данных может в свою очередь привести к сокращению ввода/вывода и увеличению пропускной способности по скромной стоимости с точки зрения увеличенного использования центрального процессора. Вы можете скорректировать баланс между уровнем сжатия и нагрузкой на центральный процессор, изменяя параметр innodb_compression_level.

Хранение данных InnoDB и сжатие

Все пользовательские данные в таблицах InnoDB хранятся в страницах, включающих индекс B-tree (кластеризируемый индекс). В некоторых других системах базы данных этот тип индекса назван index-organized table. Каждая строка в индексном узле содержит значение (определенное пользователем или произведенное системой) первичного ключа и все другие столбцы таблицы.

Вторичные индексы в InnoDB также B-tree, содержащие пары значений: ключ индекса и указатель на строку в кластеризируемом индексе. Указатель фактически значение первичного ключа таблицы, который используется, чтобы получить доступ к кластеризируемому индексу, если столбцы кроме индексного ключа и первичного ключа требуются. Вторичный индекс должен всегда соответствовать на единственной странице B-дерева.

Сжатие узлов B-дерева (кластеризируемого и вторичного индексов) обработано отлично от сжатия страниц переполнения, используемых, чтобы хранить столбцы VARCHAR, BLOB или TEXT, как объяснено в следующих разделах.

Сжатие страниц B-дерева

Поскольку они часто обновляются, страницы B-дерева требуют специального режима. Важно минимизировать число раз разделения узлов B-дерева, так же как минимизировать потребность разсжать и повторно сжать их контент.

Один метод, который использует MySQL, должен поддержать некоторую информацию о системе в узле B-дерева в несжатой форме, таким образом облегчая определенные оперативные обновления. Например, это позволяет строкам быть отмеченными для удаления и удаленными без любой работы подсистемы сжатия.

Кроме того, MySQL пытается избежать ненужного и пересжатия индексных страниц, когда они изменены. В пределах каждой страницы B-дерева система сохраняет несжатый журнал изменений, чтобы сделать запись изменений, произведенных в странице. Обновления и вставки небольших записей могут быть записаны в этот журнал модификации не требуя, чтобы вся страница была полностью восстановлена.

Когда пространство для журнала модификации заканчивается, InnoDB разжимает страницу, применяет изменения и повторно сжимает страницу. Если пересжатие терпит неудачу (ситуация, известная как отказ сжатия), узлы B-дерева разделены, и процесс повторен до успеха.

Чтобы избежать частых отказов сжатия в интенсивных по записи рабочих нагрузках, что касается приложений OLTP, MySQL иногда резервирует некоторое пустое место (дополнение) в странице, чтобы журнал модификации заполнился скорее, и страница повторно сжата, в то время как есть все еще достаточно места, чтобы избежать разделения. Количество дополнения пространства, оставленного в каждой странице, изменяется, поскольку система отслеживает частоту разделений страницы. На занятом сервере, делающем частые записи сжатых таблиц, Вы можете корректировать опции innodb_compression_failure_threshold_pct и innodb_compression_pad_pct_max и точно настроить этот механизм.

Вообще, MySQL требует, чтобы каждая страница B-дерева в таблице InnoDB могла вместить по крайней мере две записи. Для сжатых таблиц было смягчено это требование. Страницы листа узлов B-дерева (из первичного ключа или вторичного) должны вмещать только одну запись, но что она должна заполниться, в несжатой форме, в журнале модификации для страницы. Если innodb_strict_mode ON, MySQL проверяет максимальный размер строки во время CREATE TABLE или CREATE INDEX. Если строка не соответствует, следующее сообщение об ошибке выпущено: ERROR HY000: Too big row.

Если Вы составляете таблицу, когда innodb_strict_mode OFF, и последующий INSERT или UPDATE пытается создать индексную запись, которая не помещается в размер сжатой страницы, работа терпит неудачу с ERROR 42000: Row size too large . Это сообщение об ошибке не называет индекс, для которого запись является слишком большой, или упоминает длину индексной записи или максимального размера записи на этой индексной странице. Чтобы решить эту проблему, пересоздайте таблицу с помощью ALTER TABLE и выберите больший сжатый размер страницы (KEY_BLOCK_SIZE), сократите префикс столбца индекса или отключите сжатие полностью с ROW_FORMAT=DYNAMIC или ROW_FORMAT=COMPACT.

innodb_strict_mode не применимо к общим табличным пространствам, которые также поддерживают сжатые таблицы. Управленческие правила табличного пространства для общих табличных пространств строго проведены в жизнь, независимо от innodb_strict_mode . Подробности в разделе 14.1.16.

Сжатие BLOB, VARCHAR и TEXT

В таблице столбцы BLOB, VARCHAR и TEXT, которые не являются частью первичного ключа, могут быть сохранены на отдельно выделенных страницах переполнения. Мы именуем эти столбцы столбцы вне страницы. Их значения сохранены в отдельно-связанных списках страниц переполнения.

Для таблиц, составленных с ROW_FORMAT=DYNAMIC или ROW_FORMAT=COMPRESSED, значения BLOB, TEXT или VARCHAR могут быть сохранены полностью вне страницы, в зависимости от их длины и длины всей строки. Для столбцов, которые сохранены вне страницы, кластеризируемые индексные записи содержит только 20-байтовые указатели на страницы переполнения, один на столбец. Сохранены ли какие-либо столбцы вне страницы, зависит от размера страницы и полного размера строки. Когда строка является слишком длинной, чтобы поместиться полностью в пределах страницы кластеризируемого индекса, MySQL выбирает самые длинные столбцы для хранения вне страницы на кластеризируемой индексной странице. Как отмечено выше, если строка не помещается отдельно на сжатой странице, происходит ошибка.

Для таблиц, составленных в ROW_FORMAT=DYNAMIC или ROW_FORMAT=COMPRESSED, столбцы TEXT и BLOB, которые меньше или равны 40 байтам, всегда сохранены местно.

Таблицы с ROW_FORMAT=REDUNDANT и ROW_FORMAT=COMPACT сохраняют первые 768 байтов столбцов BLOB, VARCHAR и TEXT в кластеризируемой индексной записи наряду с первичным ключом. 768-байтовая приставка сопровождается 20-байтовым указателем на страницы переполнения, которые содержат остальную часть значения столбца.

Когда таблица находится в формате COMPRESSED, все данные, написанные на страницу переполнения, сжаты как есть , то есть, MySQL применяет алгоритм сжатия zlib ко всему элементу данных. Кроме данных, сжатые страницы переполнения содержат несжатый заголовок и метку конца, включающую контрольную сумму страницы и ссылку на следующую страницу переполнения. Поэтому, очень существенная экономия хранения может быть получена для больших BLOB, TEXT или VARCHAR, если данные очень сжимаемы, как это часто бывает с текстовыми данными. Данные изображений (к примеру, JPEG), как правило, уже сжаты и не извлекают выгоду из сохранения в сжатой таблице, двойное сжатие может потратить впустую циклы центрального процессора для небольшой или никакой экономии пространства.

Страницы переполнения имеют тот же самый размер, как другие страницы. Строка, содержащая десять столбцов, сохраненная вне страницы, занимает десять страниц переполнения, даже если полная длина столбцов составляет только 8K. В несжатой таблице десять несжатых страниц переполнения занимают 160K. В сжатой таблице с размером страницы 8K они занимают только 80K. Таким образом, часто более эффективно использовать сжатый формат таблицы для таблиц с длинными значениями столбцов.

Для табличных пространств file-per-table, используя размера сжатой страницы 16K, можно уменьшить затраты ввода/вывода для BLOB, VARCHAR или TEXT, потому что такие данные часто сжимаются хорошо, и могли бы поэтому потребовать меньшего количества страниц переполнения, даже при том, что узлы самого B-дерева берут так много страниц в несжатой форме. Общие табличные пространства не поддерживают размер сжатой страницы 16K (KEY_BLOCK_SIZE). Подробности в разделе 16.7.9.

Сжатие и буферный пул

В сжатой таблице каждая сжатая страница соответствует несжатой странице 16K (или меньшего размера, если innodb_page_size задана). Чтобы получить доступ к данным в странице, MySQL читает сжатую страницу с диска, если это еще не находится в буферном пуле, затем разсжимает страницу к оригинальной форме. Этот раздел описывает, как InnoDB управляет буферным пулом относительно страниц сжатых таблиц.

Чтобы минимизировать ввод/вывод и уменьшить потребность расжимать страницу, буферный пул содержит сжатую и несжатую форму страницы базы данных. Чтобы создать место для других необходимых страниц базы данных, MySQL может вычеркнуть из буферного пула несжатую страницу, оставляя сжатую страницу в памяти. Или, если к странице не получили доступ некоторое время, сжатая форма страницы могла бы быть записана на диск, освобождая пространство для других данных. Таким образом, в любой момент времени буферный пул мог бы содержать сжатые и несжатые формы страницы, только сжатую форму страницы, или ни одной.

MySQL отслеживает, какие страницы хранятся в памяти, а какие можно вычеркнуть с применением алгоритма (LRU), чтобы горячие (часто используемые) данные имели тенденцию оставаться в памяти. Когда к сжатым таблицам получают доступ, MySQL использует адаптивный алгоритм LRU, чтобы достигнуть соответствующего баланса сжатых и несжатых страниц в памяти. Этот адаптивный алгоритм чувствителен к тому, работает ли система в нагрузке I/O-bound или CPU-bound. Цель состоит в том, чтобы избежать тратить слишком много времени обработки на распаковку страниц, когда центральный процессор занят, и избегать делать лишний ввод/вывод, когда у центрального процессора есть запасные циклы, которые могут использоваться для того, чтобы разсжать сжатые страницы (которые могут уже быть в памяти). Когда система I/O-bound, алгоритм предпочитает вычеркивать несжатую копию страницы, а не обе копии, делать больше места для других дисковых страниц. Когда система лимитирована центральным процессором, MySQL предпочитает вычеркивать сжатую и несжатую страницу, чтобы больше памяти могло использоваться для горячих страниц.

Сжатие и файлы системного журнала Redo

Прежде, чем сжатая страница записана в файл с данными, MySQL пишет копию страницы в redo-журнал (если это было повторно сжато с прошлого раза, это было записано в базе данных). Это сделано, чтобы гарантировать, что журналы, применимы для восстановления катастрофического отказа, даже в маловероятном случае что библиотека zlib обновлена, и это изменение начинает проблему совместимости со сжатием данных. Поэтому, некоторое увеличение размера файлов системного журнала или потребность в более частых контрольных точках может ожидаться, используя сжатие. Количество увеличения размера файла системного журнала или частоты контрольной точки зависит от числа изменений сжатых страниц.

Чтобы создать сжатую таблицу в табличном пространстве innodb_file_per_table должен быть включен. Нет никакой зависимости от innodb_file_per_table, составляя сжатую таблицу в общем табличном пространстве. Для получения дополнительной информации см. раздел 16.7.9.

16.9.1.6. Сжатие для рабочих нагрузок OLTP

Традиционно сжатие рекомендовалась прежде всего для рабочих нагрузок только для чтения, например, для хранилища данных . Распространение устройств хранения данных SSD, которые являются быстрыми, но относительно маленькими и дорогими, делает сжатие привлекательным также для OLTP: высокий трафик, интерактивные веб-сайты могут уменьшить свои требования хранения и свои операции в секунду ввода/вывода (IOPS) при использовании сжатых таблиц с приложениями, которые действительно часто используют INSERT, UPDATE и DELETE.

Эти параметры конфигурации позволяют Вам корректировать способ, которым сжатие работает с акцентом на работу и масштабируемость для разных действий:

Поскольку работа со сжатыми данными иногда вовлекает хранение сжатых и несжатых версий страницы в памяти в то же самое время, используя сжатие с рабочей нагрузкой OLTP-стиля, будьте готовы увеличить значение опции innodb_buffer_pool_size.

16.9.1.7. Предупреждения синтаксиса сжатия SQL и ошибки

Этот раздел описывает предупреждения и ошибки, с которыми Вы можете столкнуться, используя табличную функцию сжатия с табличными пространствами file-per-table и общими табличными пространствами.

Предупреждения синтаксиса сжатия SQL и ошибки для табличных пространств File-Per-Table

Когда innodb_strict_mode включен (значение по умолчанию), определение ROW_FORMAT=COMPRESSED или KEY_BLOCK_SIZE в CREATE TABLE или ALTER TABLE производит следующую ошибку, если innodb_file_per_table отключен.

ERROR 1031 (HY000): Table storage engine for 't1' doesn't have this option

Таблица не составлена, если текущая конфигурация не разрешает использовать сжатые таблицы.

Когда innodb_strict_mode отключен, определение ROW_FORMAT=COMPRESSED или KEY_BLOCK_SIZE в CREATE TABLE или ALTER TABLE производят следующие предупреждения, если innodb_file_per_table отключен.

mysql> SHOW WARNINGS;
+---------+------+---------------------------------------------------------------+
| Level   | Code | Message                                                       |
+---------+------+---------------------------------------------------------------+
| Warning | 1478 | InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.        |
| Warning | 1478 | InnoDB: ignoring KEY_BLOCK_SIZE=4.                            |
| Warning | 1478 | InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table. |
| Warning | 1478 | InnoDB: assuming ROW_FORMAT=DYNAMIC.                          |
+---------+------+---------------------------------------------------------------+

Эти сообщения только предупреждения, не ошибки, и таблица составлена без сжатия, как будто опции не были определены.

Поведение non-strict позволяет Вам импортировать файл mysqldump в базу данных, которая не поддерживает сжатые таблицы, даже если исходная база данных содержала сжатые таблицы. В этом случае MySQL составляет таблицу в ROW_FORMAT=DYNAMIC.

Чтобы импортировать файл дампа в новую базу данных и обновить таблицы, поскольку они существуют в оригинальной базе данных, гарантируюйте, что у сервера есть надлежащая установка для innodb_file_per_table.

Признак KEY_BLOCK_SIZE разрешен только, когда ROW_FORMAT определен как COMPRESSED или опущен. Определение KEY_BLOCK_SIZE с любым другим ROW_FORMAT производит предупреждение, которое Вы можете рассмотреть с SHOW WARNINGS. Однако, таблица несжата: указанное KEY_BLOCK_SIZE проигнорировано).

УровеньCodeСообщение
Предупреждение1478 InnoDB: ignoring KEY_BLOCK_SIZE=n unless ROW_FORMAT=COMPRESSED.

Если Вы работаете с innodb_strict_mode, комбинация KEY_BLOCK_SIZE с любым ROW_FORMAT, кроме COMPRESSED, производит ошибку, а не предупреждение, и таблица не составлена.

Таблица 16.6 обеспечивает краткий обзор опций ROW_FORMAT и KEY_BLOCK_SIZE, которые используются с CREATE TABLE или ALTER TABLE.

Table 16.6. Опции ROW_FORMAT и KEY_BLOCK_SIZE

ОпцияКак использоватьОписание
ROW_FORMAT=REDUNDANT Формат хранения, используемый до MySQL 5.0.3Менее эффективный, чем ROW_FORMAT=COMPACT, для обратной совместимости.
ROW_FORMAT=COMPACTФормат хранения по умолчанию, начиная с MySQL 5.0.3Хранит префикс 768 байтов длинных значений столбцов в кластеризируемой индексной странице, с остающимися байтами, сохраненными в странице переполнения.
ROW_FORMAT=DYNAMIC Храните значения в пределах кластеризируемой индексной страницы, если они там поместятся, в противном случае хранит только 20-байтовый указатель на страницу переполнения (никакого префикса).
ROW_FORMAT=COMPRESSED Сжимает таблицу и индексы с использованием zlib.
KEY_BLOCK_SIZE=n Определяет сжатый размер страницы 1, 2, 4, 8 или 16 килобайтов, подразумевает ROW_FORMAT=COMPRESSED. Для общих табличных пространств KEY_BLOCK_SIZE равный размеру страницы не разрешен.

Таблица 16.7 суммирует состояния ошибки, которые происходят с определенными комбинациями параметров конфигурации и опций в CREATE TABLE или ALTER TABLE и то, как опции появляются в выводе SHOW TABLE STATUS.

Когда innodb_strict_mode OFF, MySQL создает или изменяет таблицу, но игнорирует определенные настройки как показано ниже. Вы можете видеть предупреждающие сообщения в журнале ошибок MySQL. Когда innodb_strict_mode ON, эти указанные комбинации опций производят ошибки, и таблица не составлена или изменена. Чтобы видеть полное описание состояния ошибки, скомандуйте SHOW ERRORS:

mysql> CREATE TABLE x (id INT PRIMARY KEY, c INT)
    -> ENGINE=INNODB KEY_BLOCK_SIZE=33333;
ERROR 1005 (HY000): Can't create table 'test.x' (errno: 1478)

mysql> SHOW ERRORS;
+-------+------+-------------------------------------------+
| Level | Code | Message                                   |
+-------+------+-------------------------------------------+
| Error | 1478 | InnoDB: invalid KEY_BLOCK_SIZE=33333.     |
| Error | 1005 | Can't create table 'test.x' (errno: 1478) |
+-------+------+-------------------------------------------+

Таблица 16.7. Предупреждения и ошибки CREATE/ALTER TABLE, когда InnoDB Strict Mode OFF

СинтаксисПредупреждение или состояние ошибки Результирующий ROW_FORMAT, как показано в SHOW TABLE STATUS
ROW_FORMAT=REDUNDANTНет REDUNDANT
ROW_FORMAT=COMPACTНетCOMPACT
ROW_FORMAT=COMPRESSED, ROW_FORMAT=DYNAMIC или KEY_BLOCK_SIZE указанПроигнорирован для табличных пространств file-per-table, если включена innodb_file_per_table . Общие табличные пространства поддерживают все форматы строки. См. раздел 16.7.9. Формат строки по умолчанию для file-per-table, указанный формат строки для общего табличного пространства
Неправильный KEY_BLOCK_SIZE (не 1, 2, 4, 8 или 16) KEY_BLOCK_SIZE пропущен Указанный формат строки или формат строки по умолчанию
ROW_FORMAT=COMPRESSED и допустимый KEY_BLOCK_SIZE определеныНет, используется определенный KEY_BLOCK_SIZECOMPRESSED
KEY_BLOCK_SIZE определен с форматом строки REDUNDANT, COMPACT или DYNAMIC KEY_BLOCK_SIZE пропущенREDUNDANT, COMPACT или DYNAMIC
ROW_FORMAT не REDUNDANT, COMPACT, DYNAMIC или COMPRESSED Проигнорирован, если признан анализатором MySQL. Иначе ошибка. Формат строки значения по умолчанию или N/A

Когда innodb_strict_mode ON, MySQL отклоняет недопустимый ROW_FORMAT или KEY_BLOCK_SIZE и выдает ошибку. Строгий режим ON по умолчанию. Когда innodb_strict_mode OFF, MySQL выдает предупреждения вместо ошибок для проигнорированных недопустимых параметров.

Невозможно видеть выбранный KEY_BLOCK_SIZE через SHOW TABLE STATUS. SHOW CREATE TABLE покажет KEY_BLOCK_SIZE (даже если это было проигнорировано, составляя таблицу). Реальный сжатый размер страницы таблицы не может быть выведен на экран MySQL.

Предупреждения синтаксиса сжатия SQL и ошибки для общих табличных пространств

innodb_strict_mode не применимо к общим табличным пространствам. Управленческие правила табличного пространства для общих табличных пространств строго проведены в жизнь независимо от innodb_strict_mode . Подробности в разделе 14.1.16.

16.9.2. Сжатие страницы InnoDB

InnoDB поддерживает сжатие на уровне страницы для таблиц, которые находятся в табличных пространствах file-per-table. Эта особенность упоминается как Прозрачное сжатие страницы. Сжатие страницы включено, определяя COMPRESSION в CREATE TABLE или ALTER TABLE. Поддержанные алгоритмы сжатия включают Zlib и LZ4.

Поддержанные платформы

Сжатие страницы поддержано на Windows с NTFS, и на следующем подмножестве MySQL-поддержанных платформ Linux, где уровень ядра оказывает поддержку hole punching:

Все доступные файловые системы для данного дистрибутива Linux, возможно, не поддерживают hole punching.

Как сжатие страницы работает

Когда страница написана, она сжата, используя указанный алгоритм сжатия. Если сжатие терпит неудачу, данные записаны как есть.

Hole Punch в Linux

В Linux размер блока файловой системы это размер модуля, используемый для hole punching. Поэтому сжатие страницы работает только, если данные о странице могут быть сжаты к размеру, который меньше или равен размеру страницы минус размер блока файловой системы. Например, если innodb_page_size=16K и размер блока файловой системы составляет 4K, данные о странице должны в сжатом виде быть меньше или равны 12K.

Hole Punch в Windows

В Windows основная инфраструктура для sparse-файлов основана на сжатии NTFS. Размер Hole punching это модуль сжатия NTFS, который в 16 раз больше размером кластера NTFS. Размеры кластера и их модули сжатия показаны в следующей таблице:

Таблица 16.8. Размер кластера и модули сжатия NTFS

Размер кластераМодуль сжатия
512 байт8 KB
1 KB16 KB
2 KB32 KB
4 KB64 KB

Сжатие страницы на системах Windows работает, если данные о странице могут быть сжаты к размеру, который меньше или равен размеру страницы минус размер модуля сжатия.

Размер кластера NTFS по умолчанию составляет 4K, для которого размер модуля сжатия составляет 64K. Это означает, что сжатие страницы не обладает никаким преимуществом для Windows NTFS, поскольку максимум innodb_page_size 64K.

Для сжатия страницы под Windows файловая система должна быть создана с размером кластера меньше 4K, и innodb_page_size должен быть, по крайней мере, двойным размером модуля сжатия. Например, для сжатия страницы в Windows Вы могли создать файловую систему с размером кластера 512 байтов (у которого есть модуль сжатия 8 КБ) и инициализировать InnoDB с innodb_page_size 16K или больше.

Включение сжатия страницы

Чтобы включить сжатие страницы, определите атрибут COMPRESSION в CREATE TABLE :

CREATE TABLE t1 (c1 INT) COMPRESSION="zlib";

Вы можете также включить сжатие страницы в ALTER TABLE. Но ALTER TABLE ... COMPRESSION только обновляет признак сжатия табличного пространства. Записи в табличное пространство, которые происходят после установки нового алгоритма сжатия, используют новую установку, но чтобы применять новый алгоритм сжатия к существующим страницам, Вы должны пересоздать таблицу с использованием OPTIMIZE TABLE .

ALTER TABLE t1 COMPRESSION="zlib";
OPTIMIZE TABLE t1;

Отключение сжатия страницы

Чтобы отключить сжатие страницы, установите COMPRESSION=None через ALTER TABLE. Записи в табличное пространство, которые происходят после установки COMPRESSION=None, больше не используют сжатие страницы. Чтобы распаковать существующие страницы, Вы должны пересоздать таблицу с использованием OPTIMIZE TABLE после установки COMPRESSION=None.

ALTER TABLE t1 COMPRESSION="None";
OPTIMIZE TABLE t1;

Метаданные о сжатии страницы

Метаданные о сжатии страницы найдены в таблице INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES в следующих столбцах:

Примените SHOW CREATE TABLE , чтобы смотреть текущую установку сжатия страницы (Zlib, Lz4 или None). Таблица может содержать соединение страниц с различными настройками сжатия.

В следующем примере метаданные о сжатии страницы для таблицы служащих получены от INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES.

# Create the employees table with Zlib page compression
CREATE TABLE employees (emp_no INT NOT NULL, birth_date DATE NOT NULL,
                        first_name VARCHAR(14) NOT NULL,
                        last_name VARCHAR(16) NOT NULL,
                        gender ENUM ('M','F') NOT NULL,
                        hire_date DATE NOT NULL, PRIMARY KEY (emp_no))
                        COMPRESSION="zlib";

# Insert data (not shown)
# Query page compression metadata in INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES

mysql> SELECT SPACE, NAME, FS_BLOCK_SIZE, FILE_SIZE, ALLOCATED_SIZE FROM
                 INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES
                 WHERE NAME='employees/employees'\G
*************************** 1. row ***************************
SPACE: 45
NAME: employees/employees
FS_BLOCK_SIZE: 4096
FILE_SIZE: 23068672
ALLOCATED_SIZE: 19415040

Метаданные о сжатии страницы для таблицы служащих показывают, что очевидный размер файла составляет 23068672 байта, в то время как фактический размер файла (со сжатием страницы) составляет 19415040 байт. Размер блока файловой системы составляет 4096 байтов, что является размером блока, используемым для hole punching.

Ограничения сжатия страницы и примечания использования

16.10. Форматы хранения и строки InnoDB

Этот раздел обсуждает InnoDB, такие как табличное сжатие, хранение вне страницы длинных значений столбцов переменной длины и большой индексный ключевой префикс, контролируемые форматом строки таблицы InnoDB. Это также обсуждает соображения о том, как выбрать правильный формат строки и совместимость форматов строки между выпусками MySQL.

16.10.1. Краткий обзор хранения строки InnoDB

Хранение для строк и связанных столбцов затрагивает работу для запросов и операций DML. Поскольку больше строк вписывается в единственную дисковую disk страницу, запросы и индексные поиски могут работать быстрее, меньше кэш-памяти требуется в буферном пуле InnoDB и меньше ввода/вывода нужно, чтобы записывать обновленные значения для числовых и коротких строковых столбцов.

Данные в каждой таблице InnoDB разделены на страницы. Страницы, которые составляют каждую таблицу, расположены в структуре данных дерева, названной индекс B-tree. Табличные данные и вторичные индексы применяют этот тип структуры. Индекс B-tree, который представляет всю таблицу, известен как кластеризируемый индекс, который организован согласно столбцам первичного ключа. Узлы индексной структуры данных содержат значения всех столбцов в той строке (для кластеризируемого индекса) или индексные столбцы и столбцы первичного ключа (для вторичного индекса).

Столбцы переменной длины исключение из этого правила. Столбцы BLOB и VARCHAR слишком длинные, чтобы поместиться на странице B-дерева, сохранены на отдельно выделенных дисковых страницах, названных страницами переполнения . Мы называем такие столбцы столбцами вне страницы. Значения этих столбцов сохранены в отдельно-связанных списках страниц переполнения, и у каждого такого столбца есть свой собственный список из одной или более страниц переполнения. В некоторых случаях префикс длинного значения столбца сохранен в B-дереве, чтобы избежать тратить впустую место и избавиться от необходимости читать отдельную страницу.

Следующие разделы описывают, как сконфигурировать формат строки таблицы, чтобы управлять, как сохранены значения столбцов переменной длины. Конфигурация формата строки также решает доступность табличного сжатия и поддержки больших префиксов индексных ключей.

16.10.2. Определение формата строки для таблицы

Формат строки по умолчанию определен параметром innodb_default_row_format, у которого есть значение по умолчанию DYNAMIC. Формат строки по умолчанию используется, когда табличная опция ROW_FORMAT не определена явно, или когда определено ROW_FORMAT=DEFAULT.

Формат строки таблицы может быть определен явно, используя табличную опцию ROW_FORMAT в CREATE TABLE или ALTER TABLE:

CREATE TABLE t1 (c1 INT) ROW_FORMAT=DYNAMIC;

Явно определенный ROW_FORMAT переопределяет неявное значение по умолчанию. Определение ROW_FORMAT=DEFAULT эквивалентно использованию неявного значения по умолчанию.

Опция innodb_default_row_format может быть установлена динамически:

mysql> SET GLOBAL innodb_default_row_format=DYNAMIC;

Допустимые значения innodb_default_row_format включают DYNAMIC, COMPACT и REDUNDANT. Формат строки COMPRESSED, который не поддержан для использования в системном табличном пространстве, не может быть определен как значение по умолчанию. Это может быть определено только явно в CREATE TABLE или ALTER TABLE. Попытка установить innodb_default_row_format в COMPRESSED возвращает эту ошибку:

mysql> SET GLOBAL innodb_default_row_format=COMPRESSED;
ERROR 1231 (42000): Variable 'innodb_default_row_format'
can't be set to the value of 'COMPRESSED'

Недавно составленные таблицы используют формат строки, определенный innodb_default_row_format, когда ROW_FORMAT не определена явно или когда ROW_FORMAT=DEFAULT. Например, следующие CREATE TABLE используют формат строки, определенный innodb_default_row_format.

CREATE TABLE t1 (c1 INT);
CREATE TABLE t2 (c1 INT) ROW_FORMAT=DEFAULT;

Когда опция ROW_FORMAT не определена явно, или когда ROW_FORMAT=DEFAULT, любая операция, которая пересоздает таблицу, также тихо изменяет формат строки таблицы к формату, определенному innodb_default_row_format.

Пересоздающие таблицу операции включают ALTER TABLE с использованием ALGORITHM=COPY или ALTER TABLE с использованием ALGORITM=INPLACE, где табличное восстановление требуется. См. таблицу 16.9 для краткого обзора состояния операций DDL. OPTIMIZE TABLE тоже пересоздает таблицу.

Следующий пример демонстрирует восстанавливающую таблицу работу, которая тихо изменяет формат строки таблицы, составленной без явно определенного формата строки.

mysql> SELECT @@innodb_default_row_format;
+-----------------------------+
| @@innodb_default_row_format |
+-----------------------------+
| dynamic                     |
+-----------------------------+

mysql> CREATE TABLE t1 (c1 INT);
mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
                   WHERE NAME LIKE 'test/t1' \G
*************************** 1. row ***************************
 TABLE_ID: 54
 NAME: test/t1
 FLAG: 33
   N_COLS: 4
SPACE: 35
   ROW_FORMAT: Dynamic
ZIP_PAGE_SIZE: 0
   SPACE_TYPE: Single

mysql> SET GLOBAL innodb_default_row_format=COMPACT;
mysql> ALTER TABLE t1 ADD COLUMN (c2 INT);
mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
                   WHERE NAME LIKE 'test/t1' \G
*************************** 1. row ***************************
 TABLE_ID: 55
 NAME: test/t1
 FLAG: 1
   N_COLS: 5
SPACE: 36
   ROW_FORMAT: Compact
ZIP_PAGE_SIZE: 0
   SPACE_TYPE: Single

Рассмотрите следующие потенциальные проблемы прежде, чем изменить формат строки существующих таблиц с REDUNDANT или COMPACT на DYNAMIC.

Чтобы смотреть формат строки таблицы, скомандуйте SHOW TABLE STATUS или запросите INFORMATION_SCHEMA.TABLES .

SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
         WHERE NAME LIKE 'test/t1' \G

Формат строки определяет физическую структуру строки. См. раздел 16.8.2.

16.10.3. Форматы строки DYNAMIC и COMPRESSED

Когда таблица составлена с ROW_FORMAT=DYNAMIC или ROW_FORMAT=COMPRESSED, InnoDB может сохранить длинные значения столбцов переменной длины (для типов VARCHAR, VARBINARY, BLOB и TEXT) полностью вне страницы, с кластеризируемой индексной записью, содержащий только 20-байтовый указатель на страницу переполнения. InnoDB может также сохранить значения столбцов CHAR вне страницы, если значение столбца больше или равно 768 байтам, что может произойти, если максимальная длина байта набора символов больше 3, как это с набором utf8mb4.

Сохранены ли какие-либо столбцы вне страницы, зависит от размера страницы и полного размера строки. Когда строка является слишком длинной, InnoDB выбирает самые длинные столбцы для хранения вне страницы, пока записи кластеризируемого индекса помещаются на странице B-tree. Столбцы TEXT и BLOB, которые меньше или равны 40 байтам, всегда сохранены на месте.

Формат строки DYNAMIC поддерживает эффективность хранения всей строки в индексном узле, если она там помещается (так же, как и форматы COMPACT и REDUNDANT), но DYNAMIC избегает проблемы заполняющихся узлов B-дерева с большим количеством байтов данных длинных столбцов. DYNAMIC основан на идее, что если часть большого значения данных сохранена вне страницы, обычно самым эффективным будет сохранить все значение вне страницы. С форматом DYNAMIC более короткие столбцы, вероятно, останутся в узле B-дерева, минимизируя число страниц переполнения, необходимых для любой данной строки.

Формат строки COMPRESSED использует подобные внутренние детали для хранения вне страницы, как DYNAMIC с дополнительными соображениями в плане сжатых данных таблицы и индекса и использования меньших размеров страницы. С COMPRESSED опция KEY_BLOCK_SIZE управляет, сколько данных столбца хранится в кластеризируемом индексе, а сколько помещено на страницах переполнения. Для полного изложения формата COMPRESSED см. раздел 16.9.

DYNAMIC и COMPRESSED поддерживают префикс индексного ключа в 3072 байт.

Таблицы, которые используют COMPRESSED могут быть создан в табличных пространствах file-per-table или общих табличных пространствах . Системное табличное пространство не поддерживает формат строки COMPRESSED. Чтобы сохранить таблицу COMPRESSED в табличном пространстве file-per-table, параметр innodb_file_per_table должен быть включен. Опция innodb_file_per_table не применима к общим табличным пространствам. Общие табличные пространства поддерживают все форматы строки, но сжатые и несжатые таблицы не могут сосуществовать в том же самом общем табличном пространстве из-за различных физических размеров страницы. Для получения дополнительной информации об общих табличных пространствах см. раздел 16.7.9.

Таблицы DYNAMIC могут быть сохранены в табличных пространствах file-per-table, общих табличных пространствах и системном табличном пространстве. Чтобы сохранить DYNAMIC в системном табличном пространстве, Вы можете отключить innodb_file_per_table и использовать CREATE TABLE или ALTER TABLE или Вы можете использовать табличную опцию TABLESPACE [=] innodb_system с CREATE TABLE или ALTER TABLE не имея необходимость изменять innodb_file_per_table . Опция innodb_file_per_table неприменима к общим табличным пространствам, и при этом они неприменимы, используя опцию TABLESPACE [=] innodb_system, чтобы сохранить таблицы DYNAMIC в системном табличном пространстве.

InnoDB не поддерживает сжатые временные таблицы. Когда innodb_strict_mode включен (значение по умолчанию), CREATE TEMPORARY TABLE возвращает ошибку, если задан ROW_FORMAT=COMPRESSED или KEY_BLOCK_SIZE. Если innodb_strict_mode выключен, предупреждения выпущены, и временная таблица составлена, используя несжатый формат строки.

DYNAMIC и COMPRESSED это варианты COMPACT и поэтому обрабатывают CHAR аналогично подходу COMPACT. Подробности в разделе 16.8.2.

16.10.4. Форматы строки COMPACT и REDUNDANT

Таблицы, которые используют COMPACT или REDUNDANT, хранят первые 768 байт столбцов переменной длины (VARCHAR, VARBINARY, BLOB и TEXT) в индексной записи в пределах узла B-tree с остатком, сохраненным в страницах переполнения.

Для таблиц, определенных с ROW_FORMAT=COMPACT, CHAR обработан как столбец переменной длины, если длина значения столбца больше или равна 768 байтам, что может произойти, если максимальная длина байта набора символов больше 3, как это с utf8mb4.

Для COMPACT или REDUNDANT , если значение столбца составляет 768 байтов или меньше, никакая страница переполнения не нужна и некоторая экономия во вводе/выводе может получиться, так как значение находится в узле B-дерева. Это работает хорошо на относительно коротких BLOB, но может заставить узлы B-дерева заполняться данными, а не значениями ключа, уменьшая их эффективность. Таблицы со многими столбцами BLOB могут заставить узлы B-дерева становиться слишком полными данными и содержать слишком мало строк, заставляя все индексировать менее эффективно, чем если бы строки были короче или если значения столбцов были сохранены вне страницы.

Формат строки по умолчанию DYNAMIC, как определено опцией innodb_default_row_format. См. раздел 16.10.3.

Для информации о физической структуре строки таблиц, которые используют форматы REDUNDANT или COMPACT, см. раздел 16.8.2.

16.11. Управление вводом/выводом и местом в файлах

Как DBA, Вы должны управлять дисковым вводом/выводом, чтобы препятствовать перегрузке подсистемы ввода/вывода и управлять дисковым пространством, чтобы избежать переполнения устройства хранения данных. Модель ACID требует определенного количества ввода/вывода, который мог бы казаться избыточным, но помогает гарантировать надежность данных. В пределах этих ограничений InnoDB предпринимает попытки оптимизировать базу данных и организацию дисковых файлов, чтобы минимизировать количество дискового ввода/вывода. Иногда, ввод/вывод отложен, пока база данных не освободится или пока все должно быть приведено в последовательное состояние, как во время перезапуска базы данных после быстрого завершения работы.

Этот раздел обсуждает основные соображения для ввода/вывода и дискового пространства с таблицами MySQL InnoDB):

16.11.1. Дисковый ввод/вывод

InnoDB использует асинхронный дисковый ввод/вывод где только возможно, создавая много потоков, чтобы обработать операции ввода/вывода, разрешая другим операциям базы данных продолжиться в то время, как ввод/вывод все еще происходит. На Linux и платформах Windows InnoDB использует доступные функции OS и библиотеки, чтобы выполнить нативный асинхронный ввод/вывод. На других платформах InnoDB все еще использует потоки ввода/вывода, но потоки могут фактически ждать запросов ввода/вывода, этот метод известен как симулированный асинхронный ввод/вывод.

Чтение вперед

Если InnoDB может решить, что есть высокая вероятность, что данные могли бы скоро быть необходимы, это выполняет операции чтения вперед, чтобы принести те данные в буферный пул так, чтобы это было доступно в памяти. Обращение с несколькими большими запросами чтения для непрерывных данных может быть более эффективным чем обращение с несколькими маленькими. Есть две эвристики чтения вперед в InnoDB:

Подробности в разделе 16.6.3.5.

Буфер Doublewrite

InnoDB использует новый метод сброса файла, вовлекающий структуру, названную буфер doublewrite, который включен по умолчанию в большинстве случаев (innodb_doublewrite=ON ). Это добавляет безопасности восстановлению после отключения электричества катастрофического отказа и улучшает работу относительно большинства вариантов Unix, уменьшая потребность в операциях fsync().

Перед записью страниц в файл с данными InnoDB сначала пишет их в непрерывной области табличного пространства, названной буфером doublewrite. Только после завершения записи в буфер doublewrite, делается запись страниц на их надлежащие позиции в файле с данными. Если есть катастрофический отказ процесса mysqld или чего-то еще в середине записи страницы, InnoDB может позже найти хорошую копию страницы в буфере doublewrite во время восстановления.

Если системные файлы табличного пространства (файлы ibdata ) расположены на устройствах Fusion-io, которые поддерживают атомные записи, буферизация doublewrite автоматически отключена, и Fusion-io используются для всех файлов с данными. Поскольку буферная установка doublewrite глобальна, doublewrite-буферизация также отключена для файлов с данными, находящихся на не-Fusion-io аппаратных средствах. Эта функция поддерживается только на аппаратных средствах Fusion-io NVMFS в Linux. Чтобы в полной мере воспользоваться этой особенностью, установите innodb_flush_method в O_DIRECT.

16.11.2. Управление пространством файла

Файлы с данными, которые Вы определяете в конфигурационном файле, используя опцию innodb_data_file_path создают системное табличное пространство. Файлы логически связаны, чтобы сформировать системное табличное пространство. В использовании нет никакого чередования. Вы не можете определить, где в пределах системного табличного пространства Ваши таблицы выделены. В создаваемом системном табличном пространстве InnoDB выделяет место, начиная с первого файла с данными.

Чтобы избежать проблем, которые идут с хранением всех таблиц и индексов в системном табличном пространстве, Вы можете включить опцию innodb_file_per_table (значение по умолчанию), которая хранит каждую недавно составленную таблицу в отдельном файле табличного пространства (с расширением .ibd). Для таблицы, сохраненной этим путем, есть меньше фрагментации в пределах дискового файла, и когда таблица усечена, пространство возвращено к операционной системе вместо того, чтобы все еще быть сохраненным InnoDB в пределах системного табличного пространства. Для получения дополнительной информации см. раздел 16.7.4.

Вы можете также сохранить таблицы в общих табличных пространствах . Общие табличные пространства это совместно используемые табличные пространства, создаваемые с CREATE TABLESPACE. Они могут быть созданы за пределами каталога данных MySQL, способны к хранению многих таблиц и поддерживают таблицы всех форматов строки. Для получения дополнительной информации см. раздел 16.7.9.

Страницы, сегменты и табличные пространства

Каждое табличное пространство состоит из страниц. У каждого табличного пространства в случае MySQL есть тот же самый размер страницы. По умолчанию у всех табличных пространств есть размер страницы 16KB, Вы можете уменьшить размер страницы до 8 КБ или 4 КБ, определяя опцию innodb_page_size , когда Вы создаете экземпляр MySQL. Вы можете также увеличить размер страницы до 32 КБ или 64 КБ. Для получения дополнительной информации обратитесь к описанию опции innodb_page_size.

Страницы сгруппированы в экстенты размера 1 МБ для страниц до 16 КБ в размере (64 последовательных страницы по 16 КБ, 128 страниц по 8KB или 256 страниц по 4KB). Для размера страницы 32 КБ размер экстента 2MB. Для размера страницы 64KB размер экстента 4MB. Файлы в табличном пространстве называют сегментами в InnoDB. Эти сегменты отличаются от сегмента отмены, который фактически содержит много сегментов табличного пространства.

Когда сегмент растет в табличном пространстве, InnoDB выделяет первые 32 страницы по одной. После этого InnoDB начинает выделять целые экстенты сегменту. InnoDB может добавить до 4 экстентов за один раз к большому сегменту, чтобы гарантировать хорошее размещение данных.

Два сегмента выделены для каждого индекса. Один для безлистных узлов B-tree, другой для узлов с листьями. Хранение узлов листа непрерывными на диске улучшает последовательные операции ввода/вывода, потому что эти узлы листа содержат фактические табличные данные.

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

Когда Вы запрашиваете доступное свободное пространство в табличном пространстве посредством SHOW TABLE STATUS, InnoDB сообщает экстенты, которые определенно свободны в табличном пространстве. InnoDB всегда имеет в запасе некоторые экстенты для уборки и других внутренних целей, эти сохраненные экстенты не включены в свободное пространство.

Когда Вы удаляете данные из таблицы, InnoDB сокращает соответствующее B-дерево индексов. Становится ли освобожденное пространство доступным другим пользователям, зависит от того, освобождаются ли отдельные страницы или экстенты в табличном пространстве. Удаление таблицы или удаление всех строк из нее будет освобождать пространство другим пользователям, но помните, что удаленные строки физически удалены только чисткой, которая происходит автоматически через некоторое время после того, как они больше не нужны для операционных отмен или последовательных чтений. См. раздел 16.3.

Как страницы касаются строк таблицы

Максимальная длина строки немного меньше, чем половина страницы базы данных для 4KB, 8KB, 16KB и 32KB innodb_page_size . Например, максимальная длина строки немного меньше, чем 8 КБ для значения по умолчанию 16 КБ размера страницы InnoDB. Для страниц 64 КБ максимальная длина строки немного меньше 16 КБ.

Если строка не превышает максимальную длину строки, все это сохранено в местном масштабе в пределах страницы. Если строка превышает максимальную длину строки, столбцы переменной длины выбраны для внешнего хранения вне страницы в пределах максимального предела длины строки. Внешнее хранение вне страницы для столбцов переменной длины отличается форматом строки:

Столбцы LONGBLOB и LONGTEXT должны быть меньше 4 ГБ, и суммарная длина строки, включая BLOB и TEXT, должна быть меньше 4 ГБ.

16.11.3. Контрольные точки InnoDB

Создание Ваших очень больших файлов системного журнала может уменьшить дисковый ввод/вывод во время установки контрольных точек. Часто имеет смысл устанавливать полный размер файлов системного журнала столь же большим, как буферный пул или еще больше.

Как обработка контрольной точки работает

InnoDB осуществляет механизм контрольной точки, известный как нечеткая установка контрольных точек. InnoDB сбрасывает измененные страницы базы данных из буферного пула в маленьких пакетах. Нет никакой потребности сбрасывать буферный пул в одном огромном пакете, который разрушил бы обработку пользовательских запросов SQL во время процесса установки контрольных точек.

Во время восстановления катастрофического отказа InnoDB ищет метку контрольной точки, записанную в файлы системного журнала. Это знает, что все модификации базы данных перед меткой присутствуют в образе базы данных на диске. Тогда InnoDB просматривает файлы системного журнала вперед от контрольной точки, применяя зарегистрированные модификации к базе данных.

16.11.4. Дефрагментация таблиц

Случайные вставки или удаления из вторичного индекса могут заставить индексирование становится фрагментированным. Фрагментация означает, что физическое упорядочивание индексных страниц на диске не близко к индексному упорядочиванию записей на страницах, или что есть много неиспользованных страниц в блоках на 64 страницы, которые были выделены индексу.

Один признак фрагментации: что таблица занимает больше места, чем она должна занимать. То, сколько это точно, трудно определить. Все данные InnoDB и индексы сохранены в B-tree, и их коэффициент заполнения может измениться от 50% до 100%. Другой признак фрагментации: сканирование таблицы, такое как это, занимает больше времени, чем должно:

SELECT COUNT(*) FROM t WHERE non_indexed_column <> 12345;

Предыдущий запрос требует, чтобы MySQL выполнил полное сканирование таблицы, самый медленный тип запроса для большой таблицы.

Чтобы убыстрить индексные просмотры, Вы можете периодически выполнять нулевой ALTER TABLE, которая заставляет MySQL восстанавливать таблицу:

ALTER TABLE tbl_name ENGINE=INNODB

Вы можете также использовать ALTER TABLE tbl_name FORCE, чтобы выполнить нулевую работу, которая восстанавливает таблицу.

ALTER TABLE tbl_name ENGINE=INNODB и ALTER TABLE tbl_name FORCE используют online DDL (ALGORITHM=COPY). Подробности в разделе 16.12.1.

Другой способ выполнить работу дефрагментации состоит в том, чтобы использовать mysqldump , чтобы вывести таблицу в дамп, удалить таблицу и перезагрузить ее из файла дампа.

Если вставки в индекс всегда растут, а записи удалены только из конца, управленческий алгоритм InnoDB гарантирует, что фрагментация в индексе не происходит.

16.11.5. Восстановление дискового пространства с TRUNCATE TABLE

Чтобы восстановить дисковое пространство операционной системы, усекая таблицу, эта таблица должна быть сохранена в ее собственном файле .ibd. Для таблицы, которая будет сохранена в ее собственном файле .ibd, innodb_file_per_table должен быть включен, когда таблица составлена. Дополнительно не может быть ограничения внешнего ключа между таблицей для усечения и другими таблицами, иначе TRUNCATE TABLE выдаст ошибку. Ограничение внешнего ключа между двумя столбцами в той же самой таблице, однако, разрешено.

Когда таблица является усеченной, она удалена и пересоздана в новом файле .ibd, а освобожденное пространство возвращено операционной системе. Это в отличие от усечения таблиц, которые сохранены в пределах системного табличного пространства (таблицы, составленные, когда innodb_file_per_table=OFF) и таблиц, сохраненных в совместно используемых общих табличных пространствах, где только InnoDB может использовать освобожденное пространство после того, как таблица усечена.

Способность усечь таблицы и возвратить дисковое пространство операционной системе также означает, что физические резервные копии могут быть меньшими. Усечение таблиц, которые сохранены в системном табличном пространстве (таблицы, составленные, когда innodb_file_per_table=OFF) или в общем табличном пространстве оставляет блоки неиспользуемого места в табличном пространстве.

16.12. InnoDB и Online DDL

online DDL улучшает много типов ALTER TABLE , чтобы избежать табличного копирования или блокирования операций DML в то время, как DDL происходит.

Особенность online DDL обладает следующими преимуществами:

16.12.1. Обзор Online DDL

Исторически, много операций DDL в таблицах InnoDB были дороги. Многие ALTER TABLE работали, составляя новую, пустую, таблицу, определенную с требуемыми табличными опциями и индексами, затем копируя существующие строки к новой таблице поштучно, обновляя индексирование по мере того, как строки были вставлены. После того, как все строки оригинальной таблицы были скопированы, старая таблица была удалена, а копия переименована с названием оригинальной таблицы.

MySQL 5.5 и MySQL 5.1 с InnoDB Plugin оптимизировали CREATE INDEX и DROP INDEX, чтобы избегать копирующего таблицу поведения. Та особенность была известна, как быстрое создание индекса . MySQL 5.6 улучшил много других типов ALTER TABLE, чтобы избежать копировать таблицу. Другое улучшение позволило запросам SELECT INSERT, UPDATE и DELETE (DML) продолжиться в то время, как таблица изменяется. В MySQL 5.7 ALTER TABLE RENAME INDEX был также улучшен, чтобы избежать табличного копирования. Эта комбинация особенностей теперь известна как online DDL.

Этот механизм также означает, что Вы можете вообще ускорить полный процесс создания и загрузки таблицы, составляя таблицу без вторичного индекса, затем добавляя, вторичный индекс после того, как данные загружены.

Хотя никакие изменения синтаксиса не требуются в CREATE INDEX или DROP INDEX, некоторые факторы затрагивают работу и семантику этой работы (см. раздел 16.12.9).

Возможность online DDL в MySQL 5.6 улучшила много операций DDL, которые прежде требовали табличной копии или блокировали операции DML на таблице. Таблица 16.9 показывает изменения ALTER TABLE как особенность DDL онлайн относится к каждому запросу.

За исключением параметров разделения в ALTER TABLE, online DDL для разделенных таблиц следуют тем же самым правилам, которые относятся к обычным таблицам. Для получения дополнительной информации см. раздел 16.12.8.

Таблица 16.9. Резюме состояния онлайн для операций DDL

ОперацияIn-Place? Copies Table? Allows Concurrent DML?Allows Concurrent Query? Примечания
CREATE INDEX , ADD INDEX Yes*No*Да ДаНекоторые ограничения для индекса FULLTEXT.
ADD FULLTEXT INDEXДаNo* НетДа Создание первого индекса FULLTEXT для таблицы, вовлекает табличную копию, если нет столбца FTS_DOC_ID. Последующие индексы FULLTEXT на той же самой таблице могут быть созданы оперативно.
ADD SPATIAL INDEX ДаНет НетДа Оптовая загрузка не поддержана.
RENAME INDEX ДаНет ДаДа Только изменяет табличные метаданные.
DROP INDEX ДаНет ДаДа Только изменяет табличные метаданные.
OPTIMIZE TABLE ДаДа ДаДа ALGORITHM=COPY используется, если old_alter_table=1 или включена опция mysqld --skip-new. OPTIMIZE TABLE использует онлайн DDL (ALGORITHM=INPLACE), не поддерживая таблицы с индексами FULLTEXT.
Установить значение по умолчанию для столбца. ДаНет ДаДа Только изменяет табличные метаданные.
Изменить для столбца значение auto-increment. ДаНетДа ДаИзменяет значение, сохраненное в памяти, а не в файле с данными.
Добавить ограничение внешнего ключаYes*No* ДаДа Чтобы избежать копировать таблицу, отключите foreign_key_checks во время создания ограничения.
Удалить ограничение внешнего ключаДаНет ДаДа foreign_key_checks может быть включена или отключена.
Переименовать столбецYes* No*Yes*Да Чтобы позволить параллельный DML, сохраните тот же самый тип данных и измените только имя столбца. ALGORITHM=INPLACE не поддержан для того, чтобы переименовать произведенный столбец.
ДобавитьYes* Yes*Yes*Да Параллельный DML не позволен, добавляя столбец auto-increment. Хотя ALGORITHM=INPLACE позволен, данные реорганизованы существенно, таким образом, это все еще дорогая работа. ALGORITHM=INPLACE поддержан для того, чтобы добавить произведенный виртуальный столбец, но не для того, чтобы добавить произведенный сохраненный столбец. Добавление произведенного виртуального столбца не требует табличной копии.
Удалить столбецДа Yes*ДаДа Хотя ALGORITHM=INPLACE позволен, данные реорганизованы существенно, таким образом, это все еще дорогая работа. ALGORITHM=INPLACE поддержан для того, чтобы удалить произведенный столбец. Удаление произведенного виртуального столбца не требует табличной копии.
Reorder columnsДа ДаДаДа Хотя ALGORITHM=INPLACE позволен, данные реорганизованы существенно, таким образом, это все еще дорогая работа.
Изменить свойства ROW_FORMAT ДаДаДа Да Хотя ALGORITHM=INPLACE позволен, данные реорганизованы существенно, таким образом, это все еще дорогая работа.
Изменить свойства KEY_BLOCK_SIZE ДаДаДа Да Хотя ALGORITHM=INPLACE позволен, данные реорганизованы существенно, таким образом, это все еще дорогая работа.
Сделать столбец NULL ДаДаДа Да Хотя ALGORITHM=INPLACE позволен, данные реорганизованы существенно, таким образом, это все еще дорогая работа.
Сделать столбец NOT NULL Yes*ДаДа ДаSTRICT_ALL_TABLES или STRICT_TRANS_TABLES SQL_MODE требуется для работы. Работа терпит неудачу, если столбец содержит значения NULL. Сервер запрещает изменения столбцов внешнего ключа, у которых есть потенциал, чтобы вызвать потерю ссылочной целостности. Для получения дополнительной информации см. раздел 14.1.7. Хотя ALGORITHM=INPLACE позволен, данные реорганизованы существенно, таким образом, это все еще дорогая работа.
Изменить тип столбцаNo* Yes*НетДа Исключение: VARCHAR может быть увеличен, используя онлайн ALTER TABLE.
Добавить primary keyYes*Да ДаДа Хотя ALGORITHM=INPLACE позволен, данные реорганизованы существенно, таким образом, это все еще дорогая работа. ALGORITHM=INPLACE не позволен при определенных условиях, если столбцы должны быть преобразованы в NOT NULL. См. Пример 16.9.
Удалить primary key и добавить другойДаДа ДаДа ALGORITHM=INPLACE позволен только, когда Вы добавляете новый первичный ключ в том же самом ALTER TABLE.
Удалить primary keyНетДа НетДа Ограничения применяются, когда Вы удаляете первичный ключ, не добавляя новый в том же самом ALTER TABLE.
Сменить набор символовНет ДаНетДа Пересоздает таблицу, если новая кодировка символов отличается.
Определить набор символовНет ДаНет ДаПересоздает таблицу, если новая кодировка символов отличается.
Пересоздать с опцией FORCE ДаДаДа ДаALGORITHM=COPY используется, если old_alter_table=1 или включена опция mysqld --skip-new. Пересоздание таблицы с использованием онлайн DDL (ALGORITHM=INPLACE) не поддержано для таблиц с индексами FULLTEXT.
Пересоздать с null ALTER TABLE ... ENGINE=INNODBДа ДаДаДа ALGORITHM=COPY используется, если old_alter_table=1 или включена опция mysqld --skip-new. Пересоздание таблицы с использованием онлайн DDL (ALGORITHM=INPLACE) не поддержано для таблиц с индексами FULLTEXT.
Установить постоянные опции статистики на уровне таблицы (STATS_PERSISTENT, STATS_AUTO_RECALC STATS_SAMPLE_PAGES). ДаНетДа Да Только изменяет табличные метаданные.

Следующие разделы показывают основной синтаксис и примечания использования, связанные с DDL онлайн, для каждой из главных операций, которые могут быть выполнены с параллельным DML:

Вторичные индексы

Создание и удаление вторичного индекса на таблице пропускает копирующее таблицу поведение.

Таблица остается доступной для чтения и записи в то время, как индекс создается или удаляется. CREATE INDEX или DROP INDEX заканчивается только после того, как все транзакции, которые получают доступ к таблице, завершены, чтобы начальное состояние индекса отразило новое содержание таблицы. Ранее изменение таблицы в то время, как индекс создается или удаляется, как правило, приводило к тупику, который отменял INSERT, UPDATE или DELETE.

Свойства столбца

Внешние ключи

Если внешние ключи уже присутствуют в измененной таблице (то есть, это дочерняя таблица, содержащая любой FOREIGN KEY ... REFERENCE), дополнительные ограничения относятся к операциям онлайн DDL, даже те, которые непосредственно не вовлекают столбцы внешнего ключа:

Замечания по ALGORITHM=COPY

Любая ALTER TABLE, выполненная с ALGORITHM=COPY, предотвращает параллельные операции DML. Параллельные запросы все еще позволены. Таким образом, копирующая таблицу работа всегда включает, по крайней мере, ограничения параллелизма LOCK=SHARED (позволяет запросы, но не DML). Вы можете далее ограничить параллелизм для таких операций, определяя LOCK=EXCLUSIVE, что предотвращает DML и запросы.

Параллельный DML, но табличная копия все еще необходима

Некоторый другой вызов ALTER TABLE позволяет параллельный DML, но все еще требует табличной копии.

Поддержание CREATE TABLE

Поскольку Ваша схема базы данных развивается с новыми столбцами, типами данных, ограничениями, индексами и так далее, держите Ваш CREATE TABLE современным с последними табличными определениями. Даже с исполнительными усовершенствованиями DDL онлайн, более эффективно создать устойчивые структуры базы данных вначале, вместо того, чтобы создать часть схемы и затем использовать ALTER TABLE позже.

Основное исключение: вторичные индексы на таблицах с большими количествами строк. Является, как правило, самым эффективным составить таблицу со всеми деталями, кроме вторичного индекса, загрузите данные, затем создать вторичный индекс. Вы можете использовать тот же самый метод с внешними ключами, если Вы знаете, что исходные данные чисты и не нуждаются в проверках непротиворечивости во время процесса загрузки.

Безотносительно последовательности CREATE TABLE, CREATE INDEX , ALTER TABLE и подобных запросов, Вы можете получить SQL, который должен восстановить текущую форму таблицы, делая запрос SHOW CREATE TABLE table\G (верхний регистр \G нужен для опрятного форматирования). Этот вывод показывает такие пункты, как числовая точность, NOT NULL и CHARACTER SET, это иногда добавляется негласно, которые Вы можете не учесть, клонируя таблицу на новой системе или настраивая столбцы внешнего ключа с идентичным типом.

16.12.2. Работа и соображения параллелизма для Online DDL

Online DDL улучшает несколько аспектов работы MySQL, таких как работа, параллелизм, доступность и масштабируемость:

Если работа онлайн требует временных файлов, InnoDB создает их во временном каталоге по умолчанию, а не в каталоге, содержащем оригинальную таблицу. Если этот каталог не является достаточно большим, чтобы содержать такие файлы, Вы, возможно, должны установить tmpdir к иному каталогу. Альтернативно, Вы можете определить отдельный временный каталог для операций InnoDB online ALTER TABLE, применяя опцию innodb_tmpdir. Эта опция была введена, чтобы помочь избежать временных переполнений каталога, которые могли произойти в результате больших временных файлов, создаваемых во время онлайн ALTER TABLE . Подробности в разделе B.5.3.5.

Опции блокировки для Online DDL

В то время, как таблица InnoDB изменяется работой DDL, таблица может или не может быть блокирована, в зависимости от внутренних работ и параметра LOCK ALTER TABLE. По умолчанию MySQL использует такую небольшую блокировку, насколько возможно, во время работы DDL, Вы определяете параметр, чтобы сделать блокировку более сильной, чем обычно (таким образом ограничиваете параллельный DML или DML и запросов), или гарантировать, что некоторая ожидаемая степень блокировки позволена для работы. Если LOCK определяет уровень блокировки, которая не доступна для того определенного вида работы DDL, например, LOCK=SHARED или LOCK=NONE создавая или удаляя первичный ключ, пункт работает как утверждение, заставляя запрос потерпеть неудачу с ошибкой. Следующий список показывает различные возможности для LOCK, от самой разрешающей до самой строгой:

В зависимости от внутренних работ online DDL и LOCK в ALTER TABLE, online DDL может ждать того, чтобы в настоящее время выполняемые транзакции, которые получают доступ к таблице, завершились прежде, чем завершиться, потому что эксклюзивный доступ к таблице требуется в течение краткого времени во время начальных и заключительных фаз работы DDL. Эти online DDL также ждут завершения получающих доступ к таблице транзакций, запущенных в то время, как DDL происходит. Следовательно, в случае долгого рабочего операционного выполнения вставки, обновления, удаления или SELECT ... FOR UPDATE на таблице, онлайн ALTER TABLE может исчерпать время, поскольку это ждет эксклюзивного доступа к таблице. Операции DML, которые выполнены на таблице в то время, как онлайн ALTER TABLE ждет исключительной табличной блокировки, могут также быть заблокированы.

Поскольку есть некоторая работа обработки, связанная с записью изменений, произведенных параллельными операциями DML, затем применяя те изменения в конце, работа DDL онлайн могла занять больше времени, чем механизм в старинном стиле, который блокирует табличный доступ от других сеансов. Сокращение сырой работы сбалансировано относительно лучшего отклика для приложений, которые используют таблицу. Оценивая идеальные методы для структуры изменения таблицы, рассмотрите восприятие конечного пользователя работы, основанной на факторах, таких как времена загрузки для веб-страниц.

Недавно создаваемый вторичный индекс \содержит только преданные данные в таблице в то время, как CREATE INDEX или ALTER TABLE заканчивает выполняться. Это не содержит нейтральных значений, старых версий значений или отмеченных для удаления значений.

Исполнение оперативных операций DDL против копирующих таблицу

Сырое исполнение работы DDL онлайн в значительной степени определено тем, выполнена ли работа оперативно или требует копирования и восстановления всей таблицы. См. таблицу 16.9 , чтобы видеть, какие виды операций могут быть выполнены оперативно, и любые требования для того, чтобы избежать операций табличной копии.

Исполнительное ускорение от оперативного DDL относится к операциям на вторичном индексе, не к первичному ключу. Строки таблицы InnoDB сохранены в кластеризируемом индексе организованном, основываясь на primary key, формируя то, что некоторые системы базы данных называют index-organized table. Поскольку структура таблицы близко связана с первичным ключом, пересмотр первичного ключа все еще требует копирования данных.

Когда работа с первичным ключом использует ALGORITHM=INPLACE, даже при том, что данные все еще скопированы, это более эффективно, чем использование ALGORITHM=COPY:

Чтобы судить относительное исполнение операций DDL онлайн, Вы можете выполнить такие операции на большой таблице InnoDB, используя текущие и более ранние версии MySQL. Вы можете также выполнить все тесты производительности под последней версией MySQL, моделируя предыдущее поведение DDL для предыдущих результатов, устанавливая old_alter_table. Скомандуйте set old_alter_table=1 в сеансе и примените DDL, чтобы сделать запись предварительных чисел. Затем верните set old_alter_table=0, чтобы повторно включить более новое, более быстрое поведение и выполните операции DDL снова, чтобы сделать запись чисел после .

Для основной идеи о том, делает ли работа DDL свои оперативные изменения или выполняет табличную копию, см. значение rows affected , выведенное на экран после того, как команда заканчивается. Например, вот строки, которые Вы могли бы видеть после выполнения различных типов операций DDL:

Например, прежде, чем выполнить работу DDL на большой таблице, Вы могли бы проверить, будет ли работа быстра или замедлится следующим образом:

  1. Клонируйте структуру таблицы.

  2. Заполните клонированную таблицу крошечным объемом данных.
  3. Выполните работу DDL на клонированной таблице.
  4. Проверьте, является ли rows affected нолем или нет. Ненулевое значение означает, что работа потребует восстановления всей таблицы, которая могла бы потребовать специального планирования. Например, Вы могли бы сделать работу DDL во время периода запланированного времени простоя, или на каждом ведомом сервере репликации по одному.

Для более глубокого понимания сокращения обработки MySQL, исследуйте таблицы performance_schema и INFORMATION_SCHEMA, связанные с InnoDB, до и после DDL, чтобы видеть число физических чтений, записей, распределения памяти и так далее.

16.12.3. Синтаксис SQL для онлайн DDL

Как правило, Вы не должны сделать ничего специального, чтобы включить online DDL, используя ALTER TABLE. См. таблицу 16.9 для видов операций DDL, которые могут быть выполнены оперативно, позволяя параллельный DML. Некоторые изменения требуют особых комбинаций настроек конфигурации или параметров ALTER TABLE .

Вы можете управлять различными аспектами особой работы DDL онлайн при использовании LOCK и ALGORITHM в ALTER TABLE. Эти пункты стоят в конце запроса, отделенные от таблицы и технических требований столбца запятыми. LOCK полезен для точной настройки степени параллельного доступа к таблице. ALGORITHM прежде всего предназначен для исполнительных сравнений и как отступление к более старому копирующему таблицу поведению в случае, если Вы сталкиваетесь с любыми проблемами с существующим кодом DDL. Например:

См. раздел 16.12.2 для большего количества деталей о LOCK. Для полных примеров использования онлайн DDL см. раздел 16.12.5.

16.12.4. Объединение или отделение запросов DDL

Перед введением online DDL было обычной практикой объединить много операций DDL в один запрос ALTER TABLE. Поскольку каждый ALTER TABLE вовлекал копирование и восстановление таблицы, было более эффективно произвести несколько изменений в той же самой таблице сразу, так как те изменения могли все быть сделаны сразу. Проблема была в том, что код SQL, вовлекающий операции DDL, было трудно поддержать и снова использовать в различных скриптах. Определенные изменения отличались каждый раз, когда Вам, возможно, придется создать новый ALTER TABLE для каждого немного отличающегося скрипта.

Для DDL, которые могут быть сделаны оперативно, как показано в таблице 16.9, теперь Вы можете разделить их на отдельные ALTER TABLE для более легких сценариев и обслуживания, не жертвуя эффективностью. Например, Вы могли бы взять сложный запрос, такой как:

ALTER TABLE t1 ADD INDEX i1(c1), ADD UNIQUE INDEX i2(c2),
      CHANGE c4_old_name c4_new_name INTEGER UNSIGNED;

и поделить это на более простые части, которые могут быть проверены и выполнены независимо:

ALTER TABLE t1 ADD INDEX i1(c1);
ALTER TABLE t1 ADD UNIQUE INDEX i2(c2);
ALTER TABLE t1 CHANGE c4_old_name c4_new_name INTEGER UNSIGNED NOT NULL;

Вы могли бы все еще использовать многослойный ALTER TABLE для:

16.12.5. Примеры Online DDL

Вот примеры кода, показывающих некоторые операции, работа которых, параллелизм и масштабируемость улучшены последними улучшениями online DDL.

Пример 16.1. Установки схемы для экспериментов DDL онлайн

Вот код, который настраивает начальные таблицы, используемые в этих демонстрациях:

/*
Setup code for the online DDL demonstration:
- Set up some config variables.
- Create 2 tables that are clones of one of the INFORMATION_SCHEMA tables
  that always has some data. The "small" table has a couple of thousand rows.
  For the "big" table, keep doubling the data until it reaches over a million rows.
- Set up a primary key for the sample tables, since we are demonstrating InnoDB aspects.
*/

set autocommit = 0;
set foreign_key_checks = 1;
set global innodb_file_per_table = 1;
set old_alter_table=0;
prompt mysql:

use test;

\! echo "Setting up 'small' table:"
drop table if exists small_table;
create table small_table as select * from information_schema.columns;
alter table small_table add id int unsigned not null primary key auto_increment;
select count(id) from small_table;

\! echo "Setting up 'big' table:"
drop table if exists big_table;
create table big_table as select * from information_schema.columns;
show create table big_table\G

insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
insert into big_table select * from big_table;
commit;

alter table big_table add id int unsigned not null primary key auto_increment;
select count(id) from big_table;

Running this code gives this output, condensed for brevity and with the most important points bolded:

Setting up 'small' table:
Query OK, 0 rows affected (0.01 sec)

Query OK, 1678 rows affected (0.13 sec)
Records: 1678  Duplicates: 0  Warnings: 0

Query OK, 1678 rows affected (0.07 sec)
Records: 1678  Duplicates: 0  Warnings: 0
+-----------+
| count(id) |
+-----------+
|  1678 |
+-----------+
1 row in set (0.00 sec)

Setting up 'big' table:
Query OK, 0 rows affected (0.16 sec)

Query OK, 1678 rows affected (0.17 sec)
Records: 1678  Duplicates: 0  Warnings: 0

*************************** 1. row ***************************
   Table: big_table
Create Table: CREATE TABLE `big_table` (
  `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0',
  `COLUMN_DEFAULT` longtext CHARACTER SET utf8,
  `IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL,
  `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL,
  `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

Query OK, 1678 rows affected (0.09 sec)
Records: 1678  Duplicates: 0  Warnings: 0

Query OK, 3356 rows affected (0.07 sec)
Records: 3356  Duplicates: 0  Warnings: 0

Query OK, 6712 rows affected (0.17 sec)
Records: 6712  Duplicates: 0  Warnings: 0

Query OK, 13424 rows affected (0.44 sec)
Records: 13424  Duplicates: 0  Warnings: 0

Query OK, 26848 rows affected (0.63 sec)
Records: 26848  Duplicates: 0  Warnings: 0

Query OK, 53696 rows affected (1.72 sec)
Records: 53696  Duplicates: 0  Warnings: 0

Query OK, 107392 rows affected (3.02 sec)
Records: 107392  Duplicates: 0  Warnings: 0

Query OK, 214784 rows affected (6.28 sec)
Records: 214784  Duplicates: 0  Warnings: 0

Query OK, 429568 rows affected (13.25 sec)
Records: 429568  Duplicates: 0  Warnings: 0

Query OK, 859136 rows affected (28.16 sec)
Records: 859136  Duplicates: 0  Warnings: 0

Query OK, 0 rows affected (0.03 sec)
Query OK, 1718272 rows affected (1 min 9.22 sec)
Records: 1718272  Duplicates: 0  Warnings: 0
+-----------+
| count(id) |
+-----------+
|   1718272 |
+-----------+
1 row in set (1.75 sec)

Пример 16.2. Скорость и эффективность CREATE INDEX и DROP INDEX

Вот последовательность запросов, демонстрирующих относительную скорость CREATE INDEX и DROP INDEX. Для маленькой таблицы прошедшее время меньше, чем секунда, используем ли мы быстрый или медленный метод, таким образом, мы смотрим на rows affected, чтобы проверить, какие операции могут избежать пересоздания таблицы. Для большой таблицы различие в эффективности очевидно, потому что пропуск пересоздания таблицы экономит существенное время.

\! clear

\! echo "=== Create and drop index (small table, new/fast technique) ==="
\! echo
\! echo "Data size (kilobytes) before index created: "
\! du -k data/test/small_table.ibd
create index i_dtyp_small on small_table (data_type), algorithm=inplace;
\! echo "Data size after index created: "
\! du -k data/test/small_table.ibd
drop index i_dtyp_small on small_table, algorithm=inplace;

-- Compare against the older slower DDL.

\! echo "=== Create and drop index (small table, old/slow technique) ==="
\! echo
\! echo "Data size (kilobytes) before index created: "
\! du -k data/test/small_table.ibd
create index i_dtyp_small on small_table (data_type), algorithm=copy;
\! echo "Data size after index created: "
\! du -k data/test/small_table.ibd
drop index i_dtyp_small on small_table, algorithm=copy;

-- In the above example, we examined the "rows affected" number,
-- ideally looking for a zero figure. Let's try again with a larger
-- sample size, where we'll see that the actual time taken can
-- vary significantly.

\! echo "=== Create and drop index (big table, new/fast technique) ==="
\! echo
\! echo "Data size (kilobytes) before index created: "
\! du -k data/test/big_table.ibd
create index i_dtyp_big on big_table (data_type), algorithm=inplace;
\! echo "Data size after index created: "
\! du -k data/test/big_table.ibd
drop index i_dtyp_big on big_table, algorithm=inplace;

\! echo "=== Create and drop index (big table, old/slow technique) ==="
\! echo
\! echo "Data size (kilobytes) before index created: "
\! du -k data/test/big_table.ibd
create index i_dtyp_big on big_table (data_type), algorithm=copy;
\! echo "Data size after index created: "
\! du -k data/test/big_table.ibd
drop index i_dtyp_big on big_table, algorithm=copy;

Выполнение этого кода дает этот вывод, сжатый для краткости и с выделенными наиболее важными моментами:

Query OK, 0 rows affected (0.00 sec)

=== Create and drop index (small table, new/fast technique) ===

Data size (kilobytes) before index created:
384  data/test/small_table.ibd
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

Data size after index created:
432  data/test/small_table.ibd
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

Query OK, 0 rows affected (0.00 sec)

=== Create and drop index (small table, old/slow technique) ===

Data size (kilobytes) before index created:
432  data/test/small_table.ibd
Query OK, 1678 rows affected (0.12 sec)
Records: 1678  Duplicates: 0  Warnings: 0

Data size after index created:
448  data/test/small_table.ibd
Query OK, 1678 rows affected (0.10 sec)
Records: 1678  Duplicates: 0  Warnings: 0

Query OK, 0 rows affected (0.00 sec)

=== Create and drop index (big table, new/fast technique) ===

Data size (kilobytes) before index created:
315392  data/test/big_table.ibd
Query OK, 0 rows affected (33.32 sec)
Records: 0  Duplicates: 0  Warnings: 0

Data size after index created:
335872  data/test/big_table.ibd
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

Query OK, 0 rows affected (0.00 sec)

=== Create and drop index (big table, old/slow technique) ===

Data size (kilobytes) before index created:
335872  data/test/big_table.ibd
Query OK, 1718272 rows affected (1 min 5.01 sec)
Records: 1718272  Duplicates: 0  Warnings: 0

Data size after index created:
348160  data/test/big_table.ibd
Query OK, 1718272 rows affected (46.59 sec)
Records: 1718272  Duplicates: 0  Warnings: 0

Пример 16.3. Параллельные DML во время DML CREATE INDEX и DROP INDEX

Вот некоторые отрывки кода, которые выполнены в отдельных сессиях mysql, соединенных с той же самой базой данных, чтобы иллюстрировать запрос DML (вставка, обновление или удаление), работающий в то же самое время, как CREATE INDEX и DROP INDEX.

/*
CREATE INDEX statement to run against a table while
insert/update/delete statements are modifying the
column being indexed.
*/

-- Run this script in one session, while simultaneously creating and dropping
-- an index on test/big_table.table_name in another session.

use test;
create index i_concurrent on big_table(table_name);

/*
DROP INDEX statement to run against a table while
insert/update/delete statements are modifying the
column being indexed.
*/

-- Run this script in one session, while simultaneously creating and dropping
-- an index on test/big_table.table_name in another session.

use test;
drop index i_concurrent on big_table;

/*
Some queries and insert/update/delete statements to run against a table
while an index is being created or dropped. Previously, these operations
would have stalled during the index create/drop period and possibly
timed out or deadlocked.
*/

-- Run this script in one session, while simultaneously creating and dropping
-- an index on test/big_table.table_name in another session.

-- In the test instance, that column has about 1.7M rows, with 136 different values.
-- Sample values: COLUMNS (20480), ENGINES (6144), EVENTS (24576), FILES (38912),
-- TABLES (21504), VIEWS (10240).

set autocommit = 0;
use test;

select distinct character_set_name from big_table where table_name = 'FILES';
delete from big_table where table_name = 'FILES';
select distinct character_set_name from big_table where table_name = 'FILES';

-- I'll issue the final rollback interactively, not via script,
-- the better to control the timing.
-- rollback;

Выполнение этого кода дает этот вывод, сжатый для краткости и с выделенными наиболее важными моментами:

mysql: source concurrent_ddl_create.sql
Database changed
Query OK, 0 rows affected (1 min 25.15 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql: source concurrent_ddl_drop.sql
Database changed
Query OK, 0 rows affected (24.98 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql: source concurrent_dml.sql
Query OK, 0 rows affected (0.00 sec)

Database changed
+--------------------+
| character_set_name |
+--------------------+
| NULL               |
| utf8               |
+--------------------+
2 rows in set (0.32 sec)

Query OK, 38912 rows affected (1.84 sec)
Empty set (0.01 sec)

mysql: rollback;
Query OK, 0 rows affected (1.05 sec)

Пример 16.4. Переименование столбца

Вот демонстрация использования ALTER TABLE, чтобы переименовать столбец. Мы используем новый быстрый механизм DDL, чтобы изменить название, потом старый механизм DDL (с old_alter_table=1), чтобы восстановить оригинальное имя столбца.

Замечания:

/*
Run through a sequence of 'rename column' statements.
Because this operation involves only metadata, not table data,
it is fast for big and small tables, with new or old DDL mechanisms.
*/

\! clear
\! echo "Rename column (fast technique, small table):"
alter table small_table change `IS_NULLABLE` `NULLABLE` varchar(3) character
  set utf8 not null, algorithm=inplace;
\! echo "Rename back to original name (slow technique):"
alter table small_table change `NULLABLE` `IS_NULLABLE` varchar(3) character
  set utf8 not null, algorithm=copy;


\! echo "Rename column (fast technique, big table):"
alter table big_table change `IS_NULLABLE` `NULLABLE` varchar(3) character
  set utf8 not null, algorithm=inplace;
\! echo "Rename back to original name (slow technique):"
alter table big_table change `NULLABLE` `IS_NULLABLE` varchar(3) character
  set utf8 not null, algorithm=copy;

Выполнение этого кода дает этот вывод, сжатый для краткости и с выделенными наиболее важными моментами:

Rename column (fast technique, small table):
Query OK, 0 rows affected (0.05 sec)

Query OK, 0 rows affected (0.13 sec)
Records: 0  Duplicates: 0  Warnings: 0

Rename back to original name (slow technique):
Query OK, 0 rows affected (0.00 sec)

Query OK, 1678 rows affected (0.35 sec)
Records: 1678  Duplicates: 0  Warnings: 0

Rename column (fast technique, big table):
Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.11 sec)
Records: 0  Duplicates: 0  Warnings: 0

Rename back to original name (slow technique):
Query OK, 0 rows affected (0.00 sec)

Query OK, 1718272 rows affected (1 min 0.00 sec)
Records: 1718272  Duplicates: 0  Warnings: 0

Query OK, 0 rows affected (0.00 sec)

Пример 16.5. Удаление Foreign Keys

Вот демонстрация внешних ключей, включая усовершенствование скорости удаления ограничения внешнего ключа.

/*
Demonstrate aspects of foreign keys that are or aren't affected by the DDL improvements.
- Create a new table with only a few values to serve as the parent table.
- Set up the 'small' and 'big' tables as child tables using a foreign key.
- Verify that the ON DELETE CASCADE clause makes changes ripple from parent to child tables.
- Drop the foreign key constraints, and optionally associated indexes. (This is the operation that is sped up.)
*/

\! clear

-- Make sure foreign keys are being enforced, and allow
-- rollback after doing some DELETEs that affect both
-- parent and child tables.
set foreign_key_checks = 1;
set autocommit = 0;

-- Create a parent table, containing values that we know are already present
-- in the child tables.
drop table if exists schema_names;
create table schema_names (id int unsigned not null primary key
       auto_increment, schema_name varchar(64) character set utf8 not null,
       index i_schema (schema_name)) as select distinct
       table_schema schema_name from small_table;

show create table schema_names\G
show create table small_table\G
show create table big_table\G

-- Creating the foreign key constraint still involves a table rebuild when foreign_key_checks=1,
-- as illustrated by the "rows affected" figure.
alter table small_table add constraint small_fk foreign key i_table_schema (table_schema)
  references schema_names(schema_name) on delete cascade;
alter table big_table add constraint big_fk foreign key i_table_schema (table_schema)
  references schema_names(schema_name) on delete cascade;

show create table small_table\G
show create table big_table\G

select schema_name from schema_names order by schema_name;
select count(table_schema) howmany, table_schema from small_table
       group by table_schema;
select count(table_schema) howmany, table_schema from big_table
       group by table_schema;

-- big_table is the parent table.
-- schema_names is the parent table.
-- big_table is the child table.
-- (One row in the parent table can have many "children" in the child table.)
-- Changes to the parent table can ripple through to the child table.
-- For example, removing the value 'test' from schema_names.schema_name will
-- result in the removal of 20K or so rows from big_table.

delete from schema_names where schema_name = 'test';
select schema_name from schema_names order by schema_name;
select count(table_schema) howmany, table_schema from small_table
       group by table_schema;
select count(table_schema) howmany, table_schema from big_table
       group by table_schema;

-- Because we've turned off autocommit, we can still get back those deleted rows
-- if the DELETE was issued by mistake.
rollback;

select schema_name from schema_names order by schema_name;
select count(table_schema) howmany, table_schema from small_table
       group by table_schema;
select count(table_schema) howmany, table_schema from big_table
       group by table_schema;

-- All of the cross-checking between parent and child tables would be
-- deadly slow if there wasn't the requirement for the corresponding
-- columns to be indexed!

-- But we can get rid of the foreign key using a fast operation
-- that doesn't rebuild the table.
-- If we didn't specify a constraint name when setting up the foreign key, we would
-- have to find the auto-generated name such as 'big_table_ibfk_1' in the
-- output from 'show create table'.

-- For the small table, drop the foreign key and the associated index.
-- Having an index on a small table is less critical.

\! echo "DROP FOREIGN KEY and INDEX from small_table:"
alter table small_table drop foreign key small_fk, drop index small_fk;

-- For the big table, drop the foreign key and leave the associated index.
-- If we are still doing queries that reference the indexed column, the index is
-- very important to avoid a full table scan of the big table.
\! echo "DROP FOREIGN KEY from big_table:"
alter table big_table drop foreign key big_fk;
show create table small_table\G
show create table big_table\G

Выполнение этого кода дает этот вывод, сжатый для краткости и с выделенными наиболее важными моментами:

Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.01 sec)
Query OK, 4 rows affected (0.03 sec)
Records: 4  Duplicates: 0  Warnings: 0

*************************** 1. row ***************************
   Table: schema_names
Create Table: CREATE TABLE `schema_names` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `schema_name` varchar(64) CHARACTER SET utf8 NOT NULL,
  PRIMARY KEY (`id`), KEY `i_schema` (`schema_name`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

*************************** 1. row ***************************
   Table: small_table
Create Table: CREATE TABLE `small_table` (
  `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0',
  `COLUMN_DEFAULT` longtext CHARACTER SET utf8,
  `IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL,
  `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL,
  `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL,
  `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1679
  DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

*************************** 1. row ***************************
   Table: big_table
Create Table: CREATE TABLE `big_table` (
  `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0',
  `COLUMN_DEFAULT` longtext CHARACTER SET utf8,
  `IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL,
  `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL,
  `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL,
  `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`),
  KEY `big_fk` (`TABLE_SCHEMA`)
) ENGINE=InnoDB AUTO_INCREMENT=1718273 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

Query OK, 1678 rows affected (0.10 sec)
Records: 1678  Duplicates: 0  Warnings: 0

Query OK, 1718272 rows affected (1 min 14.54 sec)
Records: 1718272  Duplicates: 0  Warnings: 0

*************************** 1. row ***************************
   Table: small_table
Create Table: CREATE TABLE `small_table` (
  `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0',
  `COLUMN_DEFAULT` longtext CHARACTER SET utf8,
  `IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL,
  `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL,
  `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL,
  `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`),
  KEY `small_fk` (`TABLE_SCHEMA`),
  CONSTRAINT `small_fk` FOREIGN KEY (`TABLE_SCHEMA`)
REFERENCES `schema_names` (`schema_name`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1679 DEFAULT CHARSET=latin1
1 row in set (0.12 sec)

*************************** 1. row ***************************
   Table: big_table
Create Table: CREATE TABLE `big_table` (
  `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0',
  `COLUMN_DEFAULT` longtext CHARACTER SET utf8,
  `IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL,
  `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL,
  `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL,
  `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`),
  KEY `big_fk` (`TABLE_SCHEMA`),
  CONSTRAINT `big_fk` FOREIGN KEY (`TABLE_SCHEMA`)
  REFERENCES `schema_names` (`schema_name`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1718273 DEFAULT CHARSET=latin1
1 row in set (0.01 sec)

+--------------------+
| schema_name        |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.00 sec)

+---------+--------------------+
| howmany | table_schema       |
+---------+--------------------+
| 563     | information_schema |
| 286     | mysql              |
| 786     | performance_schema |
|  43     | test               |
+---------+--------------------+
4 rows in set (0.01 sec)

+---------+--------------------+
| howmany | table_schema       |
+---------+--------------------+
|  576512 | information_schema |
|  292864 | mysql              |
|  804864 | performance_schema |
|   44032 | test               |
+---------+--------------------+
4 rows in set (2.10 sec)
Query OK, 1 row affected (1.52 sec)

+--------------------+
| schema_name        |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)

+---------+--------------------+
| howmany | table_schema       |
+---------+--------------------+
| 563     | information_schema |
| 286     | mysql              |
| 786     | performance_schema |
+---------+--------------------+
3 rows in set (0.00 sec)

+---------+--------------------+
| howmany | table_schema       |
+---------+--------------------+
|  576512 | information_schema |
|  292864 | mysql              |
|  804864 | performance_schema |
+---------+--------------------+
3 rows in set (1.74 sec)
Query OK, 0 rows affected (0.60 sec)

+--------------------+
| schema_name        |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.00 sec)

+---------+--------------------+
| howmany | table_schema       |
+---------+--------------------+
| 563     | information_schema |
| 286     | mysql              |
| 786     | performance_schema |
|  43     | test               |
+---------+--------------------+
4 rows in set (0.01 sec)

+---------+--------------------+
| howmany | table_schema       |
+---------+--------------------+
|  576512 | information_schema |
|  292864 | mysql              |
|  804864 | performance_schema |
|   44032 | test               |
+---------+--------------------+
4 rows in set (1.59 sec)

DROP FOREIGN KEY and INDEX from small_table:
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

DROP FOREIGN KEY from big_table:
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

*************************** 1. row ***************************
   Table: small_table
Create Table: CREATE TABLE `small_table` (
  `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0',
  `COLUMN_DEFAULT` longtext CHARACTER SET utf8,
  `IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL,
  `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL,
  `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL,
  `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1679
  DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

*************************** 1. row ***************************
   Table: big_table
Create Table: CREATE TABLE `big_table` (
  `TABLE_CATALOG` varchar(512) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_SCHEMA` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `TABLE_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_NAME` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `ORDINAL_POSITION` bigint(21) unsigned NOT NULL DEFAULT '0',
  `COLUMN_DEFAULT` longtext CHARACTER SET utf8,
  `IS_NULLABLE` varchar(3) CHARACTER SET utf8 NOT NULL,
  `DATA_TYPE` varchar(64) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `CHARACTER_MAXIMUM_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_OCTET_LENGTH` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `NUMERIC_SCALE` bigint(21) unsigned DEFAULT NULL,
  `DATETIME_PRECISION` bigint(21) unsigned DEFAULT NULL,
  `CHARACTER_SET_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLLATION_NAME` varchar(32) CHARACTER SET utf8 DEFAULT NULL,
  `COLUMN_TYPE` longtext CHARACTER SET utf8 NOT NULL,
  `COLUMN_KEY` varchar(3) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `EXTRA` varchar(30) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `PRIVILEGES` varchar(80) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `COLUMN_COMMENT` varchar(1024) CHARACTER SET utf8 NOT NULL DEFAULT '',
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`), KEY `big_fk` (`TABLE_SCHEMA`)
) ENGINE=InnoDB AUTO_INCREMENT=1718273 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

Пример 16.6. Изменение значений Auto-Increment

Вот иллюстрация увеличения нижнего предела auto-increment для столбца таблицы, демонстрируя, как эта работа теперь обходит пересоздание таблицы плюс другие факты о столбцах InnoDB auto-increment.

/*
If this script is run after foreign_key.sql, the schema_names table is
already set up. But to allow this script to run multiple times without
running into duplicate ID errors, we set up the schema_names table
all over again.
*/

\! clear
\! echo "=== Adjusting the Auto-Increment Limit for a Table ==="
\! echo

drop table if exists schema_names;
create table schema_names (id int unsigned not null primary key auto_increment,
  schema_name varchar(64) character set utf8 not null, index i_schema (schema_name))
  as select distinct table_schema schema_name from small_table;

\! echo "Initial state of schema_names table."
\! echo "AUTO_INCREMENT is included in SHOW CREATE TABLE output."
\! echo "Note how MySQL reserved a block of IDs."
\! echo "Only 4 IDs are needed in this transaction. The next inserted values get IDs 8 and 9."
show create table schema_names\G
select * from schema_names order by id;

\! echo "Inserting even a tiny amount of data can produce gaps in the ID sequence."
insert into schema_names (schema_name) values ('eight'), ('nine');

\! echo "Bumping auto-increment lower limit to 20 (fast mechanism):"
alter table schema_names auto_increment=20, algorithm=inplace;

\! echo "Inserting 2 rows that should get IDs 20 and 21:"
insert into schema_names (schema_name) values ('foo'), ('bar');
commit;

\! echo "Bumping auto-increment lower limit to 30 (slow mechanism):"
alter table schema_names auto_increment=30, algorithm=copy;

\! echo "Inserting 2 rows that should get IDs 30 and 31:"
insert into schema_names (schema_name) values ('bletch'),('baz');
commit;

select * from schema_names order by id;

\! echo "Final state of schema_names table."
\! echo "AUTO_INCREMENT value shows the next inserted row would get ID=32."
show create table schema_names\G

Выполнение этого кода дает этот вывод, сжатый для краткости и с выделенными наиболее важными моментами:

=== Adjusting the Auto-Increment Limit for a Table ===

Query OK, 0 rows affected (0.01 sec)
Query OK, 4 rows affected (0.02 sec)
Records: 4  Duplicates: 0  Warnings: 0

Initial state of schema_names table.
AUTO_INCREMENT is included in SHOW CREATE TABLE output.
Note how MySQL reserved a block of IDs.
Only 4 IDs are needed in this transaction.
The next inserted values get IDs 8 and 9.
*************************** 1. row ***************************
   Table: schema_names
Create Table: CREATE TABLE `schema_names` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `schema_name` varchar(64) CHARACTER SET utf8 NOT NULL,
  PRIMARY KEY (`id`), KEY `i_schema` (`schema_name`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

+----+--------------------+
| id | schema_name        |
+----+--------------------+
|  1 | information_schema |
|  2 | mysql              |
|  3 | performance_schema |
|  4 | test               |
+----+--------------------+
4 rows in set (0.00 sec)

Inserting even a tiny amount of data can produce gaps in the ID sequence.
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

Query OK, 0 rows affected (0.00 sec)
Bumping auto-increment lower limit to 20 (fast mechanism):
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

Inserting 2 rows that should get IDs 20 and 21:
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)

Bumping auto-increment lower limit to 30 (slow mechanism):
Query OK, 8 rows affected (0.02 sec)
Records: 8  Duplicates: 0  Warnings: 0

Inserting 2 rows that should get IDs 30 and 31:
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

Query OK, 0 rows affected (0.01 sec)

+----+--------------------+
| id | schema_name        |
+----+--------------------+
|  1 | information_schema |
|  2 | mysql              |
|  3 | performance_schema |
|  4 | test               |
|  8 | eight              |
|  9 | nine               |
| 20 | foo                |
| 21 | bar                |
| 30 | bletch             |
| 31 | baz                |
+----+--------------------+
10 rows in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)

Final state of schema_names table.
AUTO_INCREMENT value shows the next inserted row would get ID=32.
*************************** 1. row ***************************
   Table: schema_names
Create Table: CREATE TABLE `schema_names` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `schema_name` varchar(64) CHARACTER SET utf8 NOT NULL,
  PRIMARY KEY (`id`), KEY `i_schema` (`schema_name`)
) ENGINE=InnoDB AUTO_INCREMENT=32
  DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

Пример 16.7. Параллелизм управления с LOCK

Этот пример показывает, как использовать LOCK в ALTER TABLE, чтобы позволить или лишить параллельного доступа к таблице, в то время как происходит работа DDL онлайн. Есть настройки, которые позволяют запросы DML (LOCK=NONE), только запросы (LOCK=SHARED) или никакой параллельный доступ вообще (LOCK=EXCLUSIVE).

В одном сеансе мы выполняем последовательность ALTER TABLE, чтобы создать и удалить индекс, используя различные значения для LOCK, чтобы видеть, что происходит с ожиданием или заведением в тупик в любом сеансе. Мы используем ту же самую таблицу BIG_TABLE, как в предыдущих примерах, запускающихся приблизительно с 1.7 миллионов строк. В целях иллюстрации мы индексируем и запросим столбец IS_NULLABLE. Хотя в действительности было бы глупо сделать индексирование для крошечного столбца только с 2 отличными значениями.

mysql: desc big_table;
+------------------+---------------------+------+-----+---------+-------+
| Field            | Type                | Null | Key | Default | Extra |
+------------------+---------------------+------+-----+---------+-------+
| TABLE_CATALOG    | varchar(512)        | NO   |     |         |       |
| TABLE_SCHEMA     | varchar(64)         | NO   |     |         |       |
| TABLE_NAME       | varchar(64)         | NO   |     |         |       |
| COLUMN_NAME      | varchar(64)         | NO   |     |         |       |
| ORDINAL_POSITION | bigint(21) unsigned | NO   |     | 0       |       |
| COLUMN_DEFAULT   | longtext            | YES  |     | NULL    |       |

| IS_NULLABLE      | varchar(3)          | NO   |     |         |       |
...
+------------------+---------------------+------+-----+---------+-------+
21 rows in set (0.14 sec)

mysql: alter table big_table add index i1(is_nullable);
Query OK, 0 rows affected (20.71 sec)

mysql: alter table big_table drop index i1;
Query OK, 0 rows affected (0.02 sec)

mysql: alter table big_table add index i1(is_nullable), lock=exclusive;
Query OK, 0 rows affected (19.44 sec)

mysql: alter table big_table drop index i1;
Query OK, 0 rows affected (0.03 sec)

mysql: alter table big_table add index i1(is_nullable), lock=shared;
Query OK, 0 rows affected (16.71 sec)

mysql: alter table big_table drop index i1;
Query OK, 0 rows affected (0.05 sec)

mysql: alter table big_table add index i1(is_nullable), lock=none;
Query OK, 0 rows affected (12.26 sec)

mysql: alter table big_table drop index i1;
Query OK, 0 rows affected (0.01 sec)

... repeat statements like the above while running queries ...
... and DML statements at the same time in another session ...

Ничто драматическое не происходит в сеансе, выполняющем запросы DDL. Иногда ALTER TABLE работает необычно долго, потому что это ждет завершения другой транзакции, так как та транзакция изменила таблицу во время DDL или запросила таблицу перед DDL:

mysql: alter table big_table add index i1(is_nullable), lock=none;
Query OK, 0 rows affected (59.27 sec)

mysql: -- The previous ALTER took so long because it was waiting for all the concurrent
mysql: -- transactions to commit or roll back.

mysql: alter table big_table drop index i1;
Query OK, 0 rows affected (41.05 sec)

mysql: -- Even doing a SELECT on the table in the other session first causes
mysql: -- the ALTER TABLE above to stall until the transaction
mysql: -- surrounding the SELECT is committed or rolled back.

Вот журнал от другого сеанса, работающего одновременно, где мы выпускаем запросы данных и запросы DML для таблицы прежде, во время и после операций DDL, показанных в предыдущих примерах. Первый листинг показывает только запросы. Мы ожидаем, что запросы будут позволены во время использования операций DDL через LOCK=NONE или LOCK=SHARED, и запроса будет ждать, пока DDL не закончен, если ALTER TABLE включает LOCK=EXCLUSIVE.

mysql: show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.01 sec)

mysql: -- A trial query before any ADD INDEX in the other session:
mysql: -- Note: because autocommit is enabled, each
mysql: -- transaction finishes immediately after the query.
mysql: select distinct is_nullable from big_table;
+-------------+
| is_nullable |
+-------------+
| NO          |
| YES         |
+-------------+
2 rows in set (4.49 sec)

mysql: -- Index is being created with LOCK=EXCLUSIVE on the ALTER statement.
mysql: -- The query waits until the DDL is finished before proceeding.
mysql: select distinct is_nullable from big_table;
+-------------+
| is_nullable |
+-------------+
| NO          |
| YES         |
+-------------+
2 rows in set (17.26 sec)

mysql: -- Index is being created with LOCK=SHARED on the ALTER statement.
mysql: -- The query returns its results while the DDL is in progress.
mysql: -- The same thing happens with LOCK=NONE on the ALTER statement.
mysql: select distinct is_nullable from big_table;
+-------------+
| is_nullable |
+-------------+
| NO          |
| YES         |
+-------------+
2 rows in set (3.11 sec)

mysql: -- Once the index is created, and with no DDL in progress,
mysql: -- queries referencing the indexed column are very fast:
mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
|   411648 |
+----------+
1 row in set (0.20 sec)

mysql: select distinct is_nullable from big_table;
+-------------+
| is_nullable |
+-------------+
| NO          |
| YES         |
+-------------+
2 rows in set (0.00 sec)

Теперь в этом параллельном сеансе, мы выполняем некоторые транзакции, включая запрос DML или комбинацию запросов DML и запросов данных. Применим DELETE, чтобы иллюстрировать предсказуемые изменения таблицы. Поскольку транзакции в этой части могут охватить много запросов, мы выполняем эти тесты с выключенным autocommit.

mysql: set global autocommit = off;
Query OK, 0 rows affected (0.00 sec)

mysql: -- Count the rows that will be involved in our DELETE statements:
mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
|   411648 |
+----------+
1 row in set (0.95 sec)

mysql: -- After this point, any DDL statements back in the other session
mysql: -- stall until we commit or roll back.

mysql: delete from big_table where is_nullable = 'YES' limit 11648;
Query OK, 11648 rows affected (0.14 sec)

mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
|   400000 |
+----------+
1 row in set (1.04 sec)

mysql: rollback;
Query OK, 0 rows affected (0.09 sec)

mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
|   411648 |
+----------+
1 row in set (0.93 sec)

mysql: -- OK, now we're going to try that during index creation with LOCK=NONE.
mysql: delete from big_table where is_nullable = 'YES' limit 11648;
Query OK, 11648 rows affected (0.21 sec)

mysql: -- We expect that now there will be 400000 'YES' rows left:
mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
|   400000 |
+----------+
1 row in set (1.25 sec)

mysql: -- In the other session, the ALTER TABLE is waiting before finishing,
mysql: -- because _this_ transaction hasn't committed or rolled back yet.
mysql: rollback;
Query OK, 0 rows affected (0.11 sec)

mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
|   411648 |
+----------+
1 row in set (0.19 sec)

mysql: -- The ROLLBACK left the table in the same state we originally found it.
mysql: -- Now let's make a permanent change while the index is being created,
mysql: -- again with ALTER TABLE ... , LOCK=NONE.
mysql: -- First, commit so the DROP INDEX in the other shell can finish;
mysql: -- the previous SELECT started a transaction that accessed the table.
mysql: commit;
Query OK, 0 rows affected (0.00 sec)

mysql: -- Now we add the index back in the other shell, then issue DML in this one
mysql: -- while the DDL is running.
mysql: delete from big_table where is_nullable = 'YES' limit 11648;
Query OK, 11648 rows affected (0.23 sec)

mysql: commit;
Query OK, 0 rows affected (0.01 sec)

mysql: -- In the other shell, the ADD INDEX has finished.
mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
|   400000 |
+----------+
1 row in set (0.19 sec)

mysql: -- At the point the new index is finished being created, it contains entries
mysql: -- only for the 400000 'YES' rows left when all concurrent transactions are finished.
mysql:
mysql: -- Now we will run a similar test, while ALTER TABLE ... , LOCK=SHARED is running.
mysql: -- We expect a query to complete during the ALTER TABLE, but for the DELETE
mysql: -- to run into some kind of issue.
mysql: commit;
Query OK, 0 rows affected (0.00 sec)

mysql: -- As expected, the query returns results while the LOCK=SHARED DDL is running:
mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
|   400000 |
+----------+
1 row in set (2.07 sec)

mysql: -- The DDL in the other session is not going to finish until this transaction
mysql: -- is committed or rolled back. If we tried a DELETE now and it waited because
mysql: -- of LOCK=SHARED on the DDL, both transactions would wait forever (deadlock).
mysql: -- MySQL detects this condition and cancels the attempted DML statement.
mysql: delete from big_table where is_nullable = 'YES' limit 100000;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
mysql: -- The transaction here is still going, so in the other shell, the ADD INDEX operation
mysql: -- is waiting for this transaction to commit or roll back.
mysql: rollback;
Query OK, 0 rows affected (0.00 sec)

mysql: -- Now let's try issuing a query and some DML, on one line, while running
mysql: -- ALTER TABLE ... , LOCK=EXCLUSIVE in the other shell.
mysql: -- Notice how even the query is held up until the DDL is finished.
mysql: -- By the time the DELETE is issued, there is no conflicting access
mysql: -- to the table and we avoid the deadlock error.
mysql: select count(*) from big_table where is_nullable = 'YES'; delete from big_table
  where is_nullable = 'YES' limit 100000;
+----------+
| count(*) |
+----------+
|   400000 |
+----------+

1 row in set (15.98 sec)

Query OK, 100000 rows affected (2.81 sec)

mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
|   300000 |
+----------+
1 row in set (0.17 sec)

mysql: rollback;
Query OK, 0 rows affected (1.36 sec)

mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
|   400000 |
+----------+
1 row in set (0.19 sec)

mysql: commit;
Query OK, 0 rows affected (0.00 sec)

mysql: -- Next, we try ALTER TABLE ... , LOCK=EXCLUSIVE in the other session
mysql: -- and only issue DML, not any query, in the concurrent transaction here.
mysql: delete from big_table where is_nullable = 'YES' limit 100000;
Query OK, 100000 rows affected (16.37 sec)

mysql: -- That was OK because the ALTER TABLE did not have to wait for the transaction
mysql: -- here to complete. The DELETE in this session waited until the index was ready.
mysql: select count(*) from big_table where is_nullable = 'YES';
+----------+
| count(*) |
+----------+
|   300000 |
+----------+
1 row in set (0.16 sec)

mysql: commit;
Query OK, 0 rows affected (0.00 sec)

В предыдущих примерах мы узнали что:

Пример 16.8. Установки схемы для экспериментов DDL онлайн

Вы можете создать много индексов на таблице одним вызовом ALTER TABLE. Это относительно эффективно, потому что кластеризируемый индекс таблицы должен быть просмотрен только однажды (хотя данные отсортированы отдельно для каждого нового индекса). Например:

CREATE TABLE T1(A INT PRIMARY KEY, B INT, C CHAR(1)) ENGINE=InnoDB;
INSERT INTO T1 VALUES (1,2,'a'), (2,3,'b'), (3,2,'c'), (4,3,'d'), (5,2,'e');
COMMIT;
ALTER TABLE T1 ADD INDEX (B), ADD UNIQUE INDEX (C);

Вышеупомянутые запросы составляют таблицу T1 с первичным ключом на столбце A, вставляют несколько строк, затем создают два новых индекса на столбцах B и C. Если было много строк, вставленных в T1 до ALTER TABLE, этот подход намного более эффективен, чем создание всех вторичных индексов прежде, чем загрузить данные.

Поскольку удаление вторичного индекса, также не требует никакого копирования табличных данных, одинаково эффективно удалить много индексов одним вызовом ALTER TABLE или несколькими DROP INDEX:

ALTER TABLE T1 DROP INDEX B, DROP INDEX C;

Или:

DROP INDEX B ON T1;
DROP INDEX C ON T1;

Пример 16.9. Создание и удаление первичного ключа

Реструктурирование кластеризируемого индекса всегда требует копирования табличных данных. Таким образом, лучше определять primary key, когда Вы составляете таблицу, вместо ALTER TABLE ... ADD PRIMARY KEY позже, чтобы избежать пересоздания таблицы.

Определение PRIMARY KEY позже требует копирования данных, как в следующем примере:

CREATE TABLE T2 (A INT, B INT);
INSERT INTO T2 VALUES (NULL, 1);
ALTER TABLE T2 ADD PRIMARY KEY (B);

Когда Вы создаете индекс UNIQUE или PRIMARY KEY, MySQL должен сделать некоторую дополнительную работу. Для UNIQUE MySQL проверяет, что таблица не содержит двойных значений для ключа. Для PRIMARY KEY MySQL также проверяет что ни один из столбцов PRIMARY KEY не содержит NULL.

Когда Вы добавляете первичный ключ, используя ALGORITHM=COPY, MySQL фактически преобразовывает NULL в связанных столбцах к значениям по умолчанию: 0 для чисел, пустая строка для символьно-ориентированных столбцов и BLOB, 0000-00-00 00:00:00 для DATETIME. Это нестандартное поведение, Oracle не рекомендует на него полагаться. Добавление использования первичного ключа ALGORITHM=INPLACE позволено только когда SQL_MODE включает the strict_trans_tables или strict_all_tables, когда SQL_MODE строгий, ADD PRIMARY KEY ... , ALGORITHM=INPLACE позволен, но запрос может все еще потерпеть неудачу, если требуемые столбцы первичного ключа содержат NULL. Поведение ALGORITHM=INPLACE более стандартно-послушно.

Следующие примеры показывают различные возможности для ADD PRIMARY KEY. С ALGORITHM=COPY работа преуспевает несмотря на присутствие NULL в столбцах первичного ключа, данные тихо изменены, что может вызвать проблемы.

mysql> CREATE TABLE add_pk_via_copy (c1 INT, c2 VARCHAR(10), c3 DATETIME);
Query OK, 0 rows affected (0.03 sec)

mysql> INSERT INTO add_pk_via_copy VALUES (1,'a','2014-11-03 11:01:37'),
                 (NULL,NULL,NULL);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SET sql_mode = '';
Query OK, 0 rows affected (0.00 sec)

mysql> ALTER TABLE add_pk_via_copy ADD PRIMARY KEY (c1,c2,c3),
                ALGORITHM=COPY;
Query OK, 2 rows affected, 3 warnings (0.07 sec)
Records: 2  Duplicates: 0  Warnings: 3

mysql> SHOW WARNINGS;
+---------+------+-----------------------------------------+
| Level   | Code | Message                                 |
+---------+------+-----------------------------------------+
| Warning | 1265 | Data truncated for column 'c1' at row 2 |
| Warning | 1265 | Data truncated for column 'c2' at row 2 |
| Warning | 1265 | Data truncated for column 'c3' at row 2 |
+---------+------+-----------------------------------------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM add_pk_via_copy;
+----+----+---------------------+
| c1 | c2 | c3                  |
+----+----+---------------------+
|  0 |    | 0000-00-00 00:00:00 |
|  1 | a  | 2014-11-03 11:01:37 |
+----+----+---------------------+
2 rows in set (0.00 sec)

С ALGORITHM=INPLACE работа могла потерпеть неудачу по различным причинам, потому что эта установка считает целостность данных высоким приоритетом: запрос дает ошибку, если SQL_MODE недостаточно строг, или если столбцы первичного ключа содержат NULL. Как только мы обращаемся к обоим требованиям, ALTER TABLE успешна.

mysql> CREATE TABLE add_pk_via_inplace (c1 INT, c2 VARCHAR(10),
                 c3 DATETIME);
Query OK, 0 rows affected (0.02 sec)

mysql> INSERT INTO add_pk_via_inplace VALUES (1, 'a',
                 '2014-11-03 11:01:37'),(NULL,NULL,NULL);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM add_pk_via_inplace;
+------+------+---------------------+
| c1   | c2   | c3                  |
+------+------+---------------------+
| 1    | a    | 2014-11-03 11:01:37 |
| NULL | NULL | NULL                |
+------+------+---------------------+
2 rows in set (0.00 sec)

mysql> SET sql_mode = '';
Query OK, 0 rows affected (0.00 sec)

mysql> ALTER TABLE add_pk_via_inplace ADD PRIMARY KEY (c1,c2,c3),
                ALGORITHM=INPLACE;
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: cannot silently convert NULL
values, as required in this SQL_MODE. Try ALGORITHM=COPY.

mysql> SET sql_mode ='strict_trans_tables';
Query OK, 0 rows affected (0.00 sec)

mysql> ALTER TABLE add_pk_via_inplace ADD PRIMARY KEY (c1,c2,c3),
                ALGORITHM=INPLACE;
ERROR 1138 (22004): Invalid use of NULL value
mysql> DELETE FROM add_pk_via_inplace WHERE c1 IS NULL OR c2 IS NULL OR
                 c3 IS NULL;
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM add_pk_via_inplace;
+----+----+---------------------+
| c1 | c2 | c3                  |
+----+----+---------------------+
| 1  | a  | 2014-11-03 11:01:37 |
+----+----+---------------------+
1 row in set (0.00 sec)

mysql> ALTER TABLE add_pk_via_inplace ADD PRIMARY KEY (c1,c2,c3),
                ALGORITHM=INPLACE;
Query OK, 0 rows affected (0.09 sec)
Records: 0  Duplicates: 0  Warnings: 0

Если Вы составляете таблицу без первичного ключа, InnoDB выбирает один для Вас, которые могут быть первым UNIQUE ключом, определенный на столбце NOT NULL или произведенный системой ключ. Чтобы избежать любой неуверенности и потенциального требования пространства для дополнительного скрытого столбца, определите PRIMARY KEY в CREATE TABLE.

16.12.6. Детали выполнения DDL онлайн

Каждой операцией ALTER TABLE для InnoDB управляют несколько аспектов:

Этот раздел объясняет, как эти факторы затрагивают различные виды ALTER TABLE.

Состояния ошибки для DDL онлайн

Вот основные причины, почему работа DDL онлайн могла потерпеть неудачу:

Хотя параметр конфигурации innodb_file_per_table имеет сильное воздействие на представление таблицы, все операции online DDL работают одинаково хорошо, включена ли та опция или отключена, и расположена ли таблица физически в ее собственном файле .ibd или в системном табличном пространстве.

У InnoDB есть два типа индексов: кластеризируемые, представляющие все данные в таблице, и дополнительные вторичные, чтобы ускорить запросы. Так как кластеризируемый индекс содержит значения данных в его узлах B-дерева, добавление или удаление кластеризируемого индекса действительно вовлекает копирование данных и создание новой копии таблицы. Вторичный индекс, однако, содержит только ключ индекса и значение первичного ключа. Этот тип индекса может быть создан или удален, не копируя данные в кластеризируемом индексе. Поскольку каждый вторичный индекс содержит копии значений первичного ключа (получает доступ к кластеризируемому индексу при необходимости), когда Вы изменяете определение первичного ключа, все вторичные индексы обновлены также.

Удаление вторичного индекса просто. Только внутренние системные таблицы InnoDB и таблицы словаря данных MySQL обновлены, чтобы отразить факт, что индекс больше не существует. InnoDB возвращает место для индекса табличному пространству, чтобы новый индекс или дополнительные строки таблицы могут использовать пространство.

Чтобы добавить вторичный индекс к существующей таблице, InnoDB просматривает таблицу и сортирует строки, используя буферы памяти и временные файлы, в порядке значений ключевых столбцов вторичного индекса. B-дерево тогда создано в порядке значений ключа, что более эффективно, чем вставка строк в индекс в случайном порядке. Поскольку узлы B-дерева разделены, когда они заполняются, создание индекса таким образом приводит к более высокому коэффициенту заполнения для индекса, делая это более эффективным для последующего доступа.

16.12.7. Восстановление катастрофического отказа с DDL онлайн

Хотя никакие данные не потеряны, если сервер отказывает в то время, как выполняется ALTER TABLE, процесс восстановления катастрофического отказа отличается для кластеризируемого и вторичного индексов.

Если сервер отказывает в то время, как идет создание вторичного индекса, после восстановления MySQL удаляет любой частично созданный индекс. Вы должны запустить повторно ALTER TABLE или CREATE INDEX.

Когда катастрофический отказ происходит во время создания кластеризируемого индекса, восстановление является более сложным, потому что данные в таблице должны быть скопированы к полностью новому кластеризируемому индексу. Помните, что все таблицы InnoDB сохранены как кластеризуемый индекс.

MySQL создает новый кластеризируемый индекс, копируя существующие данные от оригинальной таблицы InnoDB во временную таблицу, у которой есть желаемая структура индекса. Как только данные полностью скопированы к этой временной таблице, оригинальная таблица переименована. Временная таблица, включающая кластеризируемый индекс, переименована с названием оригинальной таблицы, а оригинальная таблица исключена из базы данных.

Если системный катастрофический отказ происходит в то время, как идет создание кластеризируемого индекса, никакие данные не потеряны, но Вы должны завершить процесс восстановления, используя временные таблицы, которые существуют во время процесса. Так как кластеризируемый индекса редко обновляется или пересматривают первичные ключи на больших таблицах, столкнуться с системным катастрофическим отказом во время этой работы шансов мало, поэтому это руководство не предоставляет информацию о восстановлении от этого сбоя.

16.12.8. Online DDL для разделенных таблиц InnoDB

За исключением параметров разделения в ALTER TABLE, online DDL следует тем же самым правилам, которые относятся к обычным таблицам. Правила DDL обрисованы в общих чертах в таблице 16.9.

Параметры разделения ALTER TABLE не проходят тот же самый внутренний DDL онлайн API, как обычные таблицы и позволены только в соединении с ALGORITHM=DEFAULT и LOCK=DEFAULT.

Если Вы используете параметры разделения в ALTER TABLE, разделенная таблица будет переразделена с использованием ALTER TABLE COPY. Другими словами, новая разделенная таблица составлена с новой схемой разделения. Недавно составленная таблица будет включать любые изменения, примененные ALTER TABLE, табличные данные будут скопированы в новую структуру таблицы.

Если Вы не изменяете разделения таблицы или выполняете любое другое управление разделением в Вашем ALTER TABLE, ALTER TABLE будет использовать INPLACE на каждом табличном разделе. Знайте, однако, что когда INPLACE ALTER TABLE выполнен на каждом разделе, будут увеличены требования к системным ресурсам из-за операций, выполняемых на многих разделах.

Даже при том, что разделы в ALTER TABLE не проходят тот же самый внутренний DDL онлайн API, как обычные таблицы, MySQL все еще пытается минимизировать копирование данных и блокировку где только возможно:

Полнотекстовый поиск (FTS) и внешние ключи не поддержаны разделенными таблицами InnoDB. Подробности в разделах 13.9.5 и 20.6.2.

16.12.9. Ограничения Online DDL

Примите следующие ограничения во внимание, выполняя операции online DDL:

16.13. Опции запуска InnoDB и системные переменные

Таблица 16.10. Опции и переменные InnoDB

ИмяCmd-LineФайл опций СистемнаяСтатуснаяОбласть видимости Динамическая
daemon_memcached_enable_binlogДаДаДа ГлобальнаяНет
daemon_memcached_engine_lib_nameДаДаДа ГлобальнаяНет
daemon_memcached_engine_lib_pathДаДаДа ГлобальнаяНет
daemon_memcached_optionДаДаДа ГлобальнаяНет
daemon_memcached_r_batch_sizeДаДаДа ГлобальнаяНет
daemon_memcached_w_batch_sizeДаДаДа ГлобальнаяНет
foreign_key_checks Да ОбеДа
ignore-builtin-innodbДаДа ГлобальнаяНет
- Переменные: ignore_builtin_innodb Да ГлобальнаяНет
innodbДа Да
innodb_adaptive_flushingДаДаДа ГлобальнаяДа
innodb_adaptive_flushing_lwmДаДаДа ГлобальнаяДа
innodb_adaptive_hash_indexДаДаДа ГлобальнаяДа
innodb_adaptive_hash_index_partsДаДаДа ГлобальнаяНет
innodb_adaptive_max_sleep_delayДаДаДа ГлобальнаяДа
innodb_api_bk_commit_intervalДаДаДа ГлобальнаяДа
innodb_api_disable_rowlockДаДаДа ГлобальнаяНет
innodb_api_enable_binlogДаДаДа ГлобальнаяНет
innodb_api_enable_mdlДаДаДа ГлобальнаяНет
innodb_api_trx_levelДаДаДа ГлобальнаяДа
innodb_autoextend_incrementДаДаДа ГлобальнаяДа
innodb_autoinc_lock_modeДаДаДа ГлобальнаяНет
Innodb_available_undo_logs Да ГлобальнаяНет
innodb_background_drop_list_emptyДаДаДа ГлобальнаяДа
Innodb_buffer_pool_bytes_data ДаГлобальнаяНет
Innodb_buffer_pool_bytes_dirty ДаГлобальнаяНет
innodb_buffer_pool_chunk_sizeДаДаДа ГлобальнаяНет
innodb_buffer_pool_debugДаДаДа ГлобальнаяНет
innodb_buffer_pool_dump_at_shutdownДаДаДа ГлобальнаяДа
innodb_buffer_pool_dump_nowДаДаДа ГлобальнаяДа
innodb_buffer_pool_dump_pctДаДаДа ГлобальнаяДа
Innodb_buffer_pool_dump_status ДаГлобальнаяНет
innodb_buffer_pool_filenameДаДаДа ГлобальнаяДа
innodb_buffer_pool_instancesДаДаДа ГлобальнаяНет
innodb_buffer_pool_load_abortДаДаДа ГлобальнаяДа
innodb_buffer_pool_load_at_startupДаДаДа ГлобальнаяНет
innodb_buffer_pool_load_nowДаДаДа ГлобальнаяДа
Innodb_buffer_pool_load_status ДаГлобальнаяНет
Innodb_buffer_pool_pages_data ДаГлобальнаяНет
Innodb_buffer_pool_pages_dirty ДаГлобальнаяНет
Innodb_buffer_pool_pages_flushed ДаГлобальнаяНет
Innodb_buffer_pool_pages_free ДаГлобальнаяНет
Innodb_buffer_pool_pages_latched ДаГлобальнаяНет
Innodb_buffer_pool_pages_misc ДаГлобальнаяНет
Innodb_buffer_pool_pages_total ДаГлобальнаяНет
Innodb_buffer_pool_read_ahead ДаГлобальнаяНет
Innodb_buffer_pool_read_ahead_evicted ДаГлобальнаяНет
Innodb_buffer_pool_read_ahead_rnd ДаГлобальнаяНет
Innodb_buffer_pool_read_requests ДаГлобальнаяНет
Innodb_buffer_pool_reads Да ГлобальнаяНет
Innodb_buffer_pool_resize_status ДаГлобальнаяНет
innodb_buffer_pool_sizeДаДаДа ГлобальнаяДа
Innodb_buffer_pool_wait_free ДаГлобальнаяНет
Innodb_buffer_pool_write_requests ДаГлобальнаяНет
innodb_change_buffer_max_sizeДаДаДа ГлобальнаяДа
innodb_change_bufferingДаДаДа ГлобальнаяДа
innodb_change_buffering_debugДаДаДа ГлобальнаяДа
innodb_checksum_algorithmДаДаДа ГлобальнаяДа
innodb_cmp_per_index_enabledДаДаДа ГлобальнаяДа
innodb_commit_concurrencyДаДаДа ГлобальнаяДа
innodb_compress_debugДаДаДа ГлобальнаяДа
innodb_compression_failure_threshold_pctДаДа Да ГлобальнаяДа
innodb_compression_levelДаДаДа ГлобальнаяДа
innodb_compression_pad_pct_maxДаДаДа ГлобальнаяДа
innodb_concurrency_ticketsДаДаДа ГлобальнаяДа
innodb_data_file_pathДаДаДа ГлобальнаяНет
Innodb_data_fsyncs Да ГлобальнаяНет
innodb_data_home_dirДаДаДа ГлобальнаяНет
Innodb_data_pending_fsyncs Да ГлобальнаяНет
Innodb_data_pending_reads Да ГлобальнаяНет
Innodb_data_pending_writes Да ГлобальнаяНет
Innodb_data_read ДаГлобальная Нет
Innodb_data_reads ДаГлобальная Нет
Innodb_data_writes ДаГлобальная Нет
Innodb_data_written ДаГлобальнаяНет
Innodb_dblwr_pages_written ДаГлобальнаяНет
Innodb_dblwr_writes ДаГлобальнаяНет
innodb_default_row_formatДаДаДа ГлобальнаяДа
innodb_disable_sort_file_cacheДаДаДа ГлобальнаяДа
innodb_doublewrite ДаДаДа ГлобальнаяНет
innodb_fast_shutdown ДаДаДа ГлобальнаяДа
innodb_fil_make_page_dirty_debugДаДаДа ГлобальнаяДа
innodb_file_per_tableДаДаДа ГлобальнаяДа
innodb_fill_factor ДаДаДа ГлобальнаяДа
innodb_flush_log_at_timeout Да ГлобальнаяДа
innodb_flush_log_at_trx_commitДаДаДа ГлобальнаяДа
innodb_flush_methodДаДаДа ГлобальнаяНет
innodb_flush_neighborsДаДаДа ГлобальнаяДа
innodb_flush_sync ДаДаДа ГлобальнаяДа
innodb_flushing_avg_loopsДаДаДа ГлобальнаяДа
innodb_force_load_corruptedДаДаДа ГлобальнаяНет
innodb_force_recoveryДаДаДа ГлобальнаяНет
innodb_ft_aux_tableДаДаДа ГлобальнаяДа
innodb_ft_cache_sizeДаДаДа ГлобальнаяНет
innodb_ft_enable_diag_printДаДаДа ГлобальнаяДа
innodb_ft_enable_stopwordДаДаДа ГлобальнаяДа
innodb_ft_max_token_sizeДаДаДа ГлобальнаяНет
innodb_ft_min_token_sizeДаДаДа ГлобальнаяНет
innodb_ft_num_word_optimizeДаДаДа ГлобальнаяДа
innodb_ft_result_cache_limitДаДаДа ГлобальнаяДа
innodb_ft_server_stopword_tableДаДаДа ГлобальнаяДа
innodb_ft_sort_pll_degreeДаДаДа ГлобальнаяНет
innodb_ft_total_cache_sizeДаДаДа ГлобальнаяНет
innodb_ft_user_stopword_tableДаДаДа ОбеДа
Innodb_have_atomic_builtins ДаГлобальнаяНет
innodb_io_capacity ДаДаДа Глобальная Да
innodb_io_capacity_maxДаДаДа ГлобальнаяДа
innodb_limit_optimistic_insert_debugДаДаДа ГлобальнаяДа
innodb_lock_wait_timeoutДаДаДа ОбеДа
innodb_log_buffer_sizeДаДаДа ГлобальнаяНет
innodb_log_checksums ДаДаДа Глобальная Да
innodb_log_compressed_pagesДаДаДа ГлобальнаяДа
innodb_log_file_size ДаДаДа Глобальная Нет
innodb_log_files_in_groupДаДаДа ГлобальнаяНет
innodb_log_group_home_dirДаДаДа ГлобальнаяНет
Innodb_log_waits ДаГлобальная Нет
innodb_log_write_ahead_sizeДаДаДа ГлобальнаяДа
Innodb_log_write_requests Да ГлобальнаяНет
Innodb_log_writes ДаГлобальная Нет
innodb_lru_scan_depthДаДаДа ГлобальнаяДа
innodb_max_dirty_pages_pctДаДаДа ГлобальнаяДа
innodb_max_dirty_pages_pct_lwmДаДаДа ГлобальнаяДа
innodb_max_purge_lag ДаДаДа Глобальная Да
innodb_max_purge_lag_delayДаДаДа ГлобальнаяДа
innodb_max_undo_log_sizeДаДаДа ГлобальнаяДа
innodb_merge_threshold_set_all_debugДаДа Да ГлобальнаяДа
innodb_monitor_disableДаДаДа ГлобальнаяДа
innodb_monitor_enableДаДаДа ГлобальнаяДа
innodb_monitor_resetДаДаДа ГлобальнаяДа
innodb_monitor_reset_allДаДаДа ГлобальнаяДа
Innodb_num_open_files Да ГлобальнаяНет
innodb_numa_interleaveДаДаДа ГлобальнаяНет
innodb_old_blocks_pctДаДаДа ГлобальнаяДа
innodb_old_blocks_timeДаДаДа ГлобальнаяДа
innodb_online_alter_log_max_sizeДаДаДа ГлобальнаяДа
innodb_open_files ДаДаДа Глобальная Нет
innodb_optimize_fulltext_onlyДаДаДа ГлобальнаяДа
Innodb_os_log_fsyncs Да ГлобальнаяНет
Innodb_os_log_pending_fsyncs ДаГлобальнаяНет
Innodb_os_log_pending_writes ДаГлобальнаяНет
Innodb_os_log_written Да ГлобальнаяНет
innodb_page_cleanersДаДаДа ГлобальнаяНет
Innodb_page_size ДаГлобальная Нет
innodb_page_size ДаДаДа Глобальная Нет
Innodb_pages_created Да ГлобальнаяНет
Innodb_pages_read ДаГлобальная Нет
Innodb_pages_written Да ГлобальнаяНет
innodb_print_all_deadlocksДаДаДа ГлобальнаяДа
innodb_purge_batch_sizeДаДаДа ГлобальнаяДа
innodb_purge_rseg_truncate_frequencyДаДа Да ГлобальнаяДа
innodb_purge_threads ДаДаДа Глобальная Нет
innodb_random_read_aheadДаДаДа ГлобальнаяДа
innodb_read_ahead_thresholdДаДаДа ГлобальнаяДа
innodb_read_io_threadsДаДаДа ГлобальнаяНет
innodb_read_onlyДаДаДа ГлобальнаяНет
innodb_replication_delayДаДаДа ГлобальнаяДа
innodb_rollback_on_timeoutДаДаДа ГлобальнаяНет
innodb_rollback_segmentsДаДаДа ГлобальнаяДа
Innodb_row_lock_current_waits ДаГлобальнаяНет
Innodb_row_lock_time ДаГлобальнаяНет
Innodb_row_lock_time_avg Да ГлобальнаяНет
Innodb_row_lock_time_max Да ГлобальнаяНет
Innodb_row_lock_waits Да ГлобальнаяНет
Innodb_rows_deleted ДаГлобальная Нет
Innodb_rows_inserted Да ГлобальнаяНет
Innodb_rows_read ДаГлобальная Нет
Innodb_rows_updated Да ГлобальнаяНет
innodb_saved_page_number_debugДаДаДа ГлобальнаяДа
innodb_sort_buffer_sizeДаДаДа ГлобальнаяНет
innodb_spin_wait_delayДаДаДа ГлобальнаяДа
innodb_stats_auto_recalcДаДаДа ГлобальнаяДа
innodb_stats_include_delete_markedДаДа Да ГлобальнаяДа
innodb_stats_methodДаДаДа ГлобальнаяДа
innodb_stats_on_metadataДаДаДа ГлобальнаяДа
innodb_stats_persistentДаДаДа ГлобальнаяДа
innodb_stats_persistent_sample_pagesДаДа Да ГлобальнаяДа
innodb_stats_transient_sample_pagesДаДаДа ГлобальнаяДа
innodb-status-fileДаДа
innodb_status_outputДаДаДа ГлобальнаяДа
innodb_status_output_locksДаДаДа ГлобальнаяДа
innodb_strict_modeДаДаДа ОбеДа
innodb_sync_array_sizeДаДаДа ГлобальнаяНет
innodb_sync_debugДаДаДа ГлобальнаяНет
innodb_sync_spin_loopsДаДаДа ГлобальнаяДа
innodb_table_locksДаДаДа ОбеДа
innodb_temp_data_file_pathДаДаДа ГлобальнаяНет
innodb_thread_concurrencyДаДаДа ГлобальнаяДа
innodb_thread_sleep_delayДаДаДа ГлобальнаяДа
innodb_tmpdir ДаДаДа ОбеДа
Innodb_truncated_status_writes ДаГлобальнаяНет
innodb_trx_purge_view_update_only_debugДаДа Да ГлобальнаяДа
innodb_trx_rseg_n_slots_debugДаДаДа ГлобальнаяДа
innodb_undo_directoryДаДаДа ГлобальнаяНет
innodb_undo_log_truncateДаДаДа ГлобальнаяДа
innodb_undo_logs ДаДаДа Глобальная Да
innodb_undo_tablespacesДаДаДа ГлобальнаяНет
innodb_use_native_aioДаДаДа ГлобальнаяНет
innodb_version Да ГлобальнаяНет
innodb_write_io_threadsДаДаДа ГлобальнаяНет
mecab_rc_file ДаДаДа Глобальная Нет
ngram_token_size ДаДаДа Глобальная Нет
unique_checks Да ОбеДа

Опции команд InnoDB

Системные переменные InnoDB

16.14. Таблицы InnoDB INFORMATION_SCHEMA

Этот раздел предоставляет информацию и примеры использования для таблиц InnoDB INFORMATION_SCHEMA.

Таблицы InnoDB INFORMATION_SCHEMA обеспечивают метаданные, информацию о статусе и статистику о различных аспектах механизма хранения InnoDB. Вы можете смотреть список таблиц InnoDB INFORMATION_SCHEMA с помощью SHOW TABLES в базе данных INFORMATION_SCHEMA:

mysql> SHOW TABLES FROM INFORMATION_SCHEMA LIKE 'INNODB%';

Для табличных определений см. раздел 22.30. Для общей информации относительно базы данных MySQL INFORMATION_SCHEMA см. главу 22.

16.14.1. InnoDB INFORMATION_SCHEMA о сжатии

Есть две пары таблиц InnoDB INFORMATION_SCHEMA о сжатии, которые могут обеспечить понимание, как хорошо сжатие работает:

16.14.1.1. INNODB_CMP и INNODB_CMP_RESET

INNODB_CMP и INNODB_CMP_RESET содержат информацию о статусе операций, связанных со сжатыми таблицами, которые описаны в разделе 16.9. PAGE_SIZE сообщает о сжатом размере страницы.

У этих двух таблиц есть идентичное содержание, но чтение изж INNODB_CMP_RESET сбрасывает статистику по операциям сжатия. Например, если Вы архивируете вывод INNODB_CMP_RESET каждые 60 минут, Вы видите статистику в течение каждого почасового периода. Если Вы контролируете вывод INNODB_CMP (никогда не читая INNODB_CMP_RESET), Вы видите накопленную статистику с момента старта InnoDB.

См. раздел 22.30.5.

16.14.1.2. INNODB_CMPMEM и INNODB_CMPMEM_RESET

INNODB_CMPMEM и INNODB_CMPMEM_RESET содержат информацию о сжатых страницах, которые находятся в буферном пуле. Пожалуйста, консультируйтесь с разделом 16.9 для дополнительной информации о сжатых таблицах и использовании буферного пула. INNODB_CMP и INNODB_CMP_RESET должны обеспечить более полезную статистику по сжатию.

Внутренние детали

InnoDB использует систему распределителя, чтобы управлять памятью, выделенной страницам различных размеров, от 1KB до 16KB. Каждая строка этих двух таблиц, описанных здесь, соответствует единственному размеру страницы.

INNODB_CMPMEM и INNODB_CMPMEM_RESET имеют идентичное содержание, но чтение INNODB_CMPMEM_RESET сбрасывает статистику по операциям перемещения. Например, если каждые 60 минут Вы заархивировали вывод INNODB_CMPMEM_RESET , это показало бы почасовую статистику. Если Вы никогда не читаете INNODB_CMPMEM_RESET и читаете вывод INNODB_CMPMEM , вместо этого, это показжет накопленную статистику с момента запуска InnoDB.

См. раздел 22.30.6.

16.14.1.3. Использование информации о сжатии

Пример 16.10. Использование информации о сжатии

Следующее типовой вывод базы данных, которая содержит сжатые таблицы (см. compressed tables (see раздел 16.9 , INNODB_CMP, INNODB_CMP_PER_INDEX и INNODB_CMPMEM ).

Следующая таблица показывает содержание INFORMATION_SCHEMA.INNODB_CMP при легкой рабочей нагрузке . Единственный сжатый размер страницы, который содержит буферный пул, составляет 8K. Сжатие страниц потребляло меньше секунды времени, статистические данные были сброшены, потому что столбцы COMPRESS_TIME и UNCOMPRESS_TIME = 0.

Размер страницыcompress ops compress ops okcompress timeuncompress ops uncompress time
10240000 0
204800000
409600000
81921048921061 0
1638400000

Согласно INNODB_CMPMEM , есть 6169 сжатых страницы по 8 КБ в буферном пуле. Единственный другой выделенный размер блока составляет 64 байта. Самый маленький PAGE_SIZE в INNODB_CMPMEM используется для описателей блока тех сжатых страниц, для которых никакая несжатая страница не существует в буферном пуле. Мы видим, что есть 5910 таких страниц. Косвенно мы видим, что 259 (6169-5910) сжатых страниц также существуют в буферном пуле в несжатой форме.

Следующая таблица показывает содержание INFORMATION_SCHEMA.INNODB_CMPMEM при легкой рабочей нагрузке. Некоторая память непригодна из-за фрагментации распределителя памяти для сжатых страниц: SUM(PAGE_SIZE*PAGES_FREE)=6784. Это потому что маленькие запросы распределения памяти выполнены, разделяя большие блоки, начиная с 16K блоков, которые выделены из основного буферного пула, используя систему распределения. Фрагментация низкая потому, что некоторые выделенные блоки были перемещены (скопированы), чтобы сформировать большие смежные свободные блоки. Это копирование SUM(PAGE_SIZE*RELOCATION_OPS) байт потребляло меньше секунды (SUM(RELOCATION_TIME)=0).

Размер страницыСтраниц занято Страниц свободноrelocation ops relocation time
645910024360
1280100
2560000
5120100
10240000
20480100
40960100
81926169050
163840000

16.14.2. Информация о транзакциях и блокировках в InnoDB INFORMATION_SCHEMA

Этот раздел описывает информацию о блокировке, предоставленную таблицами Performance Schema data_locks и data_lock_waits, которые заменяют INFORMATION_SCHEMA INNODB_LOCKS и INNODB_LOCK_WAITS в MySQL 8.0. Для подобного обсуждения, написанного с точки зрения более старых таблиц INFORMATION_SCHEMA, см. InnoDB INFORMATION_SCHEMA Transaction and Locking Information в MySQL 5.7 Reference Manual.

Одна таблица INFORMATION_SCHEMA и две таблицы Performance Schema позволяют Вам контролировать транзакции и диагностируют потенциальные проблемы блокировки:

См. разделы 22.30.28, 23.9.12.1 и 23.9.12.2.

16.14.2.1. Использование информации о транзакции и блокировке

Этот раздел описывает информацию о блокировке как выдано таблицами data_locks и data_lock_waits, которые заменяют INFORMATION_SCHEMA INNODB_LOCKS и INNODB_LOCK_WAITS в MySQL 8.0.

Идентификация транзакций блокирования

Иногда полезно идентифицировать, какая транзакция блокирует другую. Таблицы, которые содержат информацию о транзакции и блокировке данных, позволяют Вам определить, какая транзакция ждет другую и какой ресурс требует. Для описаний этих таблиц см. раздел 16.14.2 .

Предположите, что три сеанса работают одновременно. Каждый сеанс соответствует потоку MySQL и выполняет одну транзакцию за другой. Рассмотрите состояние системы, когда эти сеансы сделали следующие запросы, но ни один еще не передал свою транзакцию:

Используйте следующий запрос, чтобы видеть, какие транзакции ждут, а какие транзакции блокируют их:

SELECT r.trx_id waiting_trx_id, r.trx_mysql_thread_id waiting_thread,
       r.trx_query waiting_query, b.trx_id blocking_trx_id,
       b.trx_mysql_thread_id blocking_thread, b.trx_query blocking_query
       FROM performance_schema.data_lock_waits w
       INNER JOIN information_schema.innodb_trx b
       ON b.trx_id = w.blocking_engine_transaction_id
       INNER JOIN information_schema.innodb_trx r
       ON r.trx_id = w.requesting_engine_transaction_id;

Или, более просто, используйте представление innodb_lock_waits в схеме sys:

SELECT waiting_trx_id, waiting_pid, waiting_query, blocking_trx_id,
       blocking_pid, blocking_query FROM sys.innodb_lock_waits;
waiting trx idwaiting thread waiting queryblocking trx idblocking thread blocking query
A46 SELECT b FROM t FOR UPDATEA3 5SELECT SLEEP(100)
A57 SELECT c FROM t FOR UPDATEA3 5SELECT SLEEP(100)
A57 SELECT c FROM t FOR UPDATEA4 6SELECT b FROM t FOR UPDATE

В предыдущей таблице Вы можете идентифицировать сеансовые столбцы waiting query или blocking query:

Вы можете видеть основные данные в INFORMATION_SCHEMA INNODB_TRX и Performance Schema data_locks и data_lock_waits.

Следующая таблица показывает некоторое типовое содержание таблицы INNODB_TRX.

trx idtrx statetrx started trx requested lock idtrx wait startedtrx weight trx mysql thread idtrx query
A3RUNNING 2008-01-15 16:44:54NULL NULL25 SELECT SLEEP(100)
A4LOCK WAIT 2008-01-15 16:45:09A4:1:3:2 2008-01-15 16:45:092 6SELECT b FROM t FOR UPDATE
A5LOCK WAIT 2008-01-15 16:45:14A5:1:3:2 2008-01-15 16:45:142 7SELECT c FROM t FOR UPDATE

Следующая таблица показывает некоторое типовое содержание таблицы data_locks.

lock idlock trx idlock mode lock typelock schemalock tablelock index lock data
A3:1:3:2A3 XRECORDtest tPRIMARY0x0200
A4:1:3:2A4 XRECORDtest tPRIMARY0x0200
A5:1:3:2A5 XRECORDtest tPRIMARY0x0200

Следующая таблица показывает некоторое типовое содержание таблицы data_lock_waits.

requesting trx idrequested lock id blocking trx idblocking lock id
A4A4:1:3:2 A3A3:1:3:2
A5A5:1:3:2 A3A3:1:3:2
A5A5:1:3:2 A4A4:1:3:2
Корреляция транзакций InnoDB с сеансами MySQL

Иногда полезно коррелировать внутреннюю информацию блокировок InnoDB с информацией на уровне сеанса MySQL. Например, Вам могло бы понадобиться знать для данного ID транзакции соответствующий MySQL session ID и название сеанса, который может держать блокировку, и таким образом блокировать другие транзакции.

Следующий вывод INFORMATION_SCHEMA INNODB_TRX и Performance Schema data_locks и data_lock_waits взят от загруженной системы. Как может быть замечено, есть несколько транзакций.

Следующие таблицы data_locks и data_lock_waits показывают, что:

Могут быть несогласованности между запросами, показанными в таблицах INFORMATION_SCHEMA PROCESSLIST и INNODB_TRX. См. раздел 16.14.2.3 .

Следующая таблица показывает содержание таблицы PROCESSLIST для системы, выполняющей тяжелую рабочую нагрузку.

IDUSERHOSTDB COMMANDTIMESTATEINFO
384root localhosttest Query10 updateINSERT INTO t2 VALUES ...
257root localhosttest Query3update INSERT INTO t2 VALUES Б─╕
130root localhosttestQuery 0update INSERT INTO t2 VALUES Б─╕
61root localhosttestQuery 1update INSERT INTO t2 VALUES Б─╕
8root localhosttestQuery 1update INSERT INTO t2 VALUES Б─╕
4root localhosttest Query0 preparingSELECT * FROM PROCESSLIST
2root localhosttest Sleep566 NULL

Следующая таблица показывает содержание INNODB_TRX для системы, выполняющей тяжелую рабочую нагрузку.

trx idtrx statetrx started trx requested lock idtrx wait startedtrx weight trx mysql thread idtrx query
77FLOCK WAIT 2008-01-15 13:10:1677F 2008-01-15 13:10:161 876INSERT INTO t09 (D, B, C) VALUES ...
77ELOCK WAIT 2008-01-15 13:10:1677E 2008-01-15 13:10:161 875INSERT INTO t09 (D, B, C) VALUES ...
77DLOCK WAIT 2008-01-15 13:10:1677D 2008-01-15 13:10:161 874INSERT INTO t09 (D, B, C) VALUES ...
77BLOCK WAIT 2008-01-15 13:10:1677B:733:12:1 2008-01-15 13:10:164 873INSERT INTO t09 (D, B, C) VALUES ...
77ARUNб╜NING 2008-01-15 13:10:16NULL NULL4872 SELECT b, c FROM t09 WHERE Б─╕
E56LOCK WAIT 2008-01-15 13:10:06E56:743:6:2 2008-01-15 13:10:065 384INSERT INTO t2 VALUES ...
E55LOCK WAIT 2008-01-15 13:10:06E55:743:38:2 2008-01-15 13:10:13965 257INSERT INTO t2 VALUES Б─╕
19CRUNб╜NING 2008-01-15 13:09:10NULL NULL2900130 INSERT INTO t2 VALUES Б─╕
E15RUNNING 2008-01-15 13:08:59NULL NULL539561 INSERT INTO t2 VALUES Б─╕
51DRUNб╜NING 2008-01-15 13:08:47NULL NULL98078 INSERT INTO t2 VALUES Б─╕

Следующая таблица показывает содержание data_lock_waits для системы, выполняющей тяжелую рабочую нагрузку.

requesting trx idrequested lock id blocking trx idblocking lock id
77F77F:806 77E77E:806
77F77F:806 77D77D:806
77F77F:806 77B77B:806
77E77E:806 77D77D:806
77E77E:806 77B77B:806
77D77D:806 77B77B:806
77B77B:733:12:1 77A77A:733:12:1
E56E56:743:6:2 E55E55:743:6:2
E55E55:743:38:2 19C19C:743:38:2

Следующая таблица показывает содержание data_locks для системы, выполняющей тяжелую рабочую нагрузку.

lock idlock trx idlock mode lock typelock schemalock tablelock index lock data
77F:80677F AUTO_INCTABLEtest t09NULLNULL
77E:80677EAUTO_INC TABLEtest t09NULLNULL
77D:80677DAUTO_INC TABLEtest t09NULLNULL
77B:80677BAUTO_INC TABLEtest t09NULLNULL
77B:733:12:177BX RECORDtest t09PRIMARYsupremum pseudo-record
77A:733:12:177AX RECORDtest t09PRIMARYsupremum pseudo-record
E56:743:6:2E56S RECORDtest t2PRIMARY0, 0
E55:743:6:2E55X RECORDtest t2PRIMARY0, 0
E55:743:38:2E55S RECORDtest t2PRIMARY1922, 1922
19C:743:38:219CX RECORDtest t2PRIMARY1922, 1922

16.14.2.2. Информация о блокировках InnoDB

Этот раздел описывает информацию о блокировке как выставлено таблицами Performance Schema data_locks и data_lock_waits, которые заменяют supersede the INFORMATION_SCHEMA INNODB_LOCKS и INNODB_LOCK_WAITS в MySQL 8.0.

Когда транзакция обновляет строку в таблице или блокирует ее с SELECT FOR UPDATE, InnoDB составляет список или очередь блокировок этой строки. Точно так же InnoDB поддерживает список для блокировок на уровне таблицы. Если вторая транзакция хочет обновить строку или заблокировать таблицу, уже заблокированную предшествующей транзакцией в несовместимом режиме, InnoDB добавляет запрос блокировки строки в соответствующую очередь. Для блокировки, которая будет приобретена транзакцией, все несовместимые запросы блокировки ранее вступившие в очередь блокировки для той строки или таблицы, должны быть удалены.

У транзакции может быть любое число запросов блокировки о различных строках или таблицах. В любой момент времени, транзакция может просить блокировку, которая проводится другой транзакцией, тогда это заблокировано той другой транзакцией. Если транзакция не ждет блокировки, она находится в в состоянии RUNNING. Если транзакция ждет блокировки, это находится в состоянии LOCK WAIT. INFORMATION_SCHEMA INNODB_TRX показывает значения статуса транзакций.

Performance Schema data_locks содержит одну или более строк для каждой транзакции LOCK WAIT, указывая на любые запросы блокировки, которые предотвращают ее продвижение. Эта таблица также содержит одну строку, описывающую каждую блокировку в очереди блокировок, ожидающих для данной строки или таблицы. Performance Schema data_lock_waits показывает, которые блокировки, уже проводимые транзакцией, блокируют блокировки, которые требуют другие транзакции.

16.14.2.3. Постоянство и последовательность информации о транзакции и блокировке InnoDB

Этот раздел описывает информацию о блокировке как выставлено Performance Schema data_locks и data_lock_waits, которые заменяют INFORMATION_SCHEMA INNODB_LOCKS и INNODB_LOCK_WAITS в MySQL 8.0.

Данные, выставленные транзакцией и таблицами блокировки (INFORMATION_SCHEMA INNODB_TRX, Performance Schema data_locks и data_lock_waits) представляют быстро изменяющиеся данные. Это не походит на пользовательские таблицы, где данные изменяются только, когда происходят обновления в приложении. Основные данные это внутренние управляемые системой данные, они могут измениться очень быстро:

16.14.3. Системные таблицы InnoDB INFORMATION_SCHEMA

Вы можете извлечь метаданные об объектах схемы, которыми управляет InnoDB, используя системные таблицы InnoDB INFORMATION_SCHEMA. Эта информация прибывает из внутренних системных таблиц InnoDB (словарь данных), который не может быть запрошен непосредственно, как обычные таблицы. Традиционно Вы получили бы этот тип информации, используя методы из раздела 16.16, настраивая мониторинг и парсинг вывода SHOW ENGINE INNODB STATUS. Таблицы INFORMATION_SCHEMA позволяют Вам запрашивать эти данные, используя SQL.

За исключением INNODB_SYS_TABLESTATS, для которого нет никакой соответствующей внутренней системной таблицы, системные таблицы INFORMATION_SCHEMA заполнены чтением данных непосредственно от внутренних системных таблиц, а не от метаданных, которые кэшируются в памяти.

Системные таблицы INFORMATION_SCHEMA включают упомянутые ниже таблицы. INNODB_SYS_DATAFILES и INNODB_SYS_TABLESPACES были включены с введением поддержки параметра DATA DIRECTORY='directory' в CREATE TABLE, который позволяет создавать табличные пространства file-per-table (файлы .ibd) вне каталога данных MySQL.

mysql> SHOW TABLES FROM INFORMATION_SCHEMA LIKE 'INNODB_SYS%';
+--------------------------------------------+
| Tables_in_information_schema (INNODB_SYS%) |
+--------------------------------------------+
| INNODB_SYS_DATAFILES                       |
| INNODB_SYS_TABLESTATS                      |
| INNODB_SYS_FOREIGN                         |
| INNODB_SYS_COLUMNS                         |
| INNODB_SYS_INDEXES                         |
| INNODB_SYS_FIELDS                          |
| INNODB_SYS_TABLESPACES                     |
| INNODB_SYS_FOREIGN_COLS                    |
| INNODB_SYS_TABLES                          |
+--------------------------------------------+

Имена таблиц показательны из типа обеспеченных данных:

Системные таблицы InnoDB INFORMATION_SCHEMA могут быть объединены через такие поля, как TABLE_ID, INDEX_ID и SPACE, позволяя Вам легко получить все доступные данные для объекта.

Пример 16.11. Системные таблицы InnoDB INFORMATION_SCHEMA

Этот пример использует простую таблицу (t1) с одним индексом (i1), чтобы продемонстрировать тип метаданных, найденных в системных таблицах INFORMATION_SCHEMA.

  1. Создайте испытательную базу данных и таблицу t1:

    mysql> CREATE DATABASE test;
    mysql> USE test;
    mysql> CREATE TABLE t1 (col1 INT, col2 CHAR(10), col3 VARCHAR(10))
                     ENGINE = InnoDB;
    mysql> CREATE INDEX i1 ON t1(col1);
    
  2. После составления таблицы t1, запросите INNODB_SYS_TABLES , чтобы определить местонахождение метаданных для test/t1:
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
                       WHERE NAME='test/t1' \G
    *************************** 1. row ***************************
     TABLE_ID: 71
     NAME: test/t1
     FLAG: 1
       N_COLS: 6
    SPACE: 57
       ROW_FORMAT: Compact
    ZIP_PAGE_SIZE: 0
    ...
    

    Таблица t1 имеет TABLE_ID 71. Поле FLAG предоставляет информацию о характеристиках хранения и формате таблицы. Есть шесть столбцов, три из которых являются скрытыми столбцами, создаваемыми InnoDB (DB_ROW_ID, DB_TRX_ID и DB_ROLL_PTR). ID таблицы SPACE 57 (0 указало бы, что таблица находится в системном табличном пространстве). ROW_FORMAT Compact. ZIP_PAGE_SIZE относится только к таблицам с форматом строки Compressed.

  3. Используя TABLE_ID information из INNODB_SYS_TABLES , запросите INNODB_SYS_COLUMNS для информации о столбцах таблицы.
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS
                     where TABLE_ID = 71 \G
    *************************** 1. row ***************************
    TABLE_ID: 71
    NAME: col1
     POS: 0
       MTYPE: 6
      PRTYPE: 1027
     LEN: 4
    *************************** 2. row ***************************
    TABLE_ID: 71
    NAME: col2
     POS: 1
       MTYPE: 2
      PRTYPE: 524542
     LEN: 10
    *************************** 3. row ***************************
    TABLE_ID: 71
    NAME: col3
     POS: 2
       MTYPE: 1
      PRTYPE: 524303
     LEN: 10
    

    В дополнение к TABLE_ID и столбцу NAME INNODB_SYS_COLUMNS обеспечивает порядковую позицию (POS) каждого столбца (с 0 и постепенно увеличивающуюся последовательно), MTYPE или main type столбца (6 = INT, 2 = CHAR, 1 = VARCHAR), PRTYPE или precise type (двоичное значение с битами, которые представляют тип данных MySQL, код набора символов и null) и длину столбца (LEN).

  4. Используя TABLE_ID из INNODB_SYS_TABLES еще раз, запросите INNODB_SYS_INDEXES для информации об индексе, связанном с таблицей t1.
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES
                     WHERE TABLE_ID = 71 \G
    *************************** 1. row ***************************
       INDEX_ID: 111
     NAME: GEN_CLUST_INDEX
       TABLE_ID: 71
     TYPE: 1
       N_FIELDS: 0
    PAGE_NO: 3
    SPACE: 57
    MERGE_THRESHOLD: 50
    *************************** 2. row ***************************
       INDEX_ID: 112
     NAME: i1
       TABLE_ID: 71
     TYPE: 0
       N_FIELDS: 1
    PAGE_NO: 4
    SPACE: 57
    MERGE_THRESHOLD: 50
    

    INNODB_SYS_INDEXES возвращает данные о двух индексах. Первый индекс GEN_CLUST_INDEX, который является кластеризируемым, создается InnoDB, если у таблицы нет определяемого пользователем кластеризуемого индекса. Второй индекс (i1) это определяемый пользователем вторичный индекс.

    INDEX_ID идентификатор для индекса, который уникален для всех баз данных сервера. TABLE_ID идентифицирует таблицу, с которой связан индекс. Значение индекса TYPE указывает тип индекса (1 = Кластеризируемый, 0 = Вторичный). N_FILEDS число полей, которые включает индекс. PAGE_NO номер страницы корня индекса B-tree, SPACE ID табличного пространства, где индекс находится. Ненулевое значение указывает, что индекс не находится в системном табличном пространстве. MERGE_THRESHOLD определяет пороговое значение процента для объема данных в индексной странице. Если объем данных в индексной странице падает ниже этого значения (по умолчанию составляет 50%), когда строка удалена или когда строка сокращена работой обновления, InnoDB пытается слить индексную страницу с соседней индексной страницей.

  5. Используя INDEX_ID из INNODB_SYS_INDEXES , запросите INNODB_SYS_FIELDS для информации о полях индекса i1.
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FIELDS
                     where INDEX_ID = 112 \G
    *************************** 1. row ***************************
    INDEX_ID: 112
    NAME: col1
     POS: 0
    

    INNODB_SYS_FIELDS обеспечивает NAME из индексированной области и ее порядковую позицию в пределах индекса. Если индекс (i1) был определен на несукольких полях, INNODB_SYS_FIELDS обеспечил бы метаданные для каждой из индексированных областей.

  6. Используя SPACE из INNODB_SYS_TABLES , запросите INNODB_SYS_TABLESPACES для информации о табличном пространстве таблицы.
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES
                     WHERE SPACE = 57 \G
    *************************** 1. row ***************************
    SPACE: 57
     NAME: test/t1
     FLAG: 0
       ROW_FORMAT: Compact or Redundant
    PAGE_SIZE: 16384
    ZIP_PAGE_SIZE: 0
    

    В дополнение к SPACE ID табличного пространства и NAME из связанной таблицы, INNODB_SYS_TABLESPACES обеспечивает данные FLAG табличного пространства, которые являются разрядной информацией о формате табличного пространства и характеристиках хранения. Также обеспечены параметры табличного пространства ROW_FORMAT, PAGE_SIZE и ZIP_PAGE_SIZE (ZIP_PAGE_SIZE применим к табличным пространствам с форматом строки Compressed).

  7. Используя SPACE из INNODB_SYS_TABLES , запросите INNODB_SYS_DATAFILES для местоположения файла с данными табличного пространства.
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_DATAFILES
                     WHERE SPACE = 57 \G
    *************************** 1. row ***************************
    SPACE: 57
     PATH: ./test/t1.ibd
    

    Файл данных расположен в подкаталоге test каталога MySQL data. Если табличное пространство file-per-table создавалось в местоположении вне каталога данных MySQL, используя DATA DIRECTORY в CREATE TABLE, PATH был бы полным путем к каталогу.

  8. Как заключительный шаг, вставьте строку в таблицу t1 (TABLE_ID = 71) и рассмотрите данные в INNODB_SYS_TABLESTATS . Данные в этой таблице используются оптимизатором, чтобы вычислить, который индекс использовать, запрашивая таблицу.
    mysql> INSERT INTO t1 VALUES(5, 'abc', 'def');
    Query OK, 1 row affected (0.06 sec)
    
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS
                     where TABLE_ID = 71 \G
    *************************** 1. row ***************************
     TABLE_ID: 71
       NAME: test/t1
    STATS_INITIALIZED: Initialized
     NUM_ROWS: 1
     CLUST_INDEX_SIZE: 1
     OTHER_INDEX_SIZE: 0
     MODIFIED_COUNTER: 1
    AUTOINC: 0
    REF_COUNT: 1
    

    Поле STATS_INITIALIZED указывает, были ли статистические данные собраны для таблицы. NUM_ROWS текущее число строк в таблице. Поля CLUST_INDEX_SIZE и OTHER_INDEX_SIZE сообщают о числе страниц на диске, которые хранят кластеризируемый и вторичный индексы для таблицы, соответственно. MODIFIED_COUNTER показывает число строк, измененных операциями DML и каскадными операциями от внешних ключей. AUTOINC следующее число, которое будет выпущено для любой основанной на автоинкременте работы. Нет никаких столбцов автоприращения, определенных в таблице t1, так что это всегда 0. REF_COUNT счетчик. Когда счетчик достигает 0, он показывает, что табличные метаданные могут быть вычеркнуты из табличного кэша.

Пример 16.12. Системные таблицы Foreign Key INFORMATION_SCHEMA

INNODB_SYS_FOREIGN и INNODB_SYS_FOREIGN_COLS обеспечивают данные об отношениях внешнего ключа. Этот пример использует родительскую таблицу и дочернюю таблицу с отношениями внешнего ключа, чтобы продемонстрировать данные, найденные в INNODB_SYS_FOREIGN и INNODB_SYS_FOREIGN_COLS.

  1. Создайте испытательную базу данных с родительскими и дочерними таблицами:

    mysql> CREATE DATABASE test;
    mysql> USE test;
    mysql> CREATE TABLE parent (id INT NOT NULL,
        ->        PRIMARY KEY (id)) ENGINE=INNODB;
    mysql> CREATE TABLE child (id INT, parent_id INT,
        ->        INDEX par_ind (parent_id), CONSTRAINT fk1
        ->        FOREIGN KEY (parent_id) REFERENCES parent(id)
        ->        ON DELETE CASCADE) ENGINE=INNODB;
    
  2. После того, как родительские и дочерние таблицы составлены, запросите INNODB_SYS_FOREIGN и определите местонахождение данных о внешнем ключе для test/child и test/parent:
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN \G
    *************************** 1. row ***************************
      ID: test/fk1
    FOR_NAME: test/child
    REF_NAME: test/parent
      N_COLS: 1
    TYPE: 1
    

    Метаданные включают внешний ключ ID (fk1), который назван по имени CONSTRAINT, был определен на дочерней таблице. FOR_NAME название дочерней таблицы, где внешний ключ определен. REF_NAME название родительской таблицы (referenced таблица). N_COLS число столбцов во внешнем ключе индекса. TYPE численное значение, представляющее разрядные флаги, которые обеспечивают дополнительную информацию о столбце внешнего ключа. В этом случае TYPE = 1, который указывает, что опция ON DELETE CASCADE была определена для внешнего ключа. См. опередение таблицы INNODB_SYS_FOREIGN для получения дополнительной информации о TYPE.

  3. Используя внешний ключ ID, запросите INNODB_SYS_FOREIGN_COLS, чтобы просмотреть данные о столбцах внешнего ключа.
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS
                       WHERE ID = 'test/fk1' \G
    *************************** 1. row ***************************
    ID: test/fk1
    FOR_COL_NAME: parent_id
    REF_COL_NAME: id
     POS: 0
    

    FOR_COL_NAME название столбца внешнего ключа в дочерней таблице, а REF_COL_NAME название столбца, на который ссылаются, в родительской таблице. POS порядковая позиция поля ключа в пределах индекса внешнего ключа, начиная с 0.

Пример 16.13. Объединение системных таблиц INFORMATION_SCHEMA

Этот пример демонстрирует присоединение трех системных таблиц InnoDB INFORMATION_SCHEMA (INNODB_SYS_TABLES , INNODB_SYS_TABLESPACES и INNODB_SYS_TABLESTATS ), чтобы собрать формат файла, формат строки, размер страницы и информацию о размере индекса о таблицах в базе данных.

Следующие псевдонимы имени таблицы используются, чтобы сократить строку запроса:

IF() используется, чтобы составлять сжатые таблицы. Если таблица сжата, размер индекса вычислен, используя ZIP_PAGE_SIZE вместо PAGE_SIZE. CLUST_INDEX_SIZE и OTHER_INDEX_SIZE, о которых сообщают в байтах, разделены на 1024*1024 чтобы обеспечить размеры индекса в мегабайтах (MB). Значения MB округлены, используя функцию ROUND().

mysql> SELECT a.NAME, a.ROW_FORMAT,
  @page_size := IF (a.ROW_FORMAT='Compressed',
                    b.ZIP_PAGE_SIZE, b.PAGE_SIZE) AS page_size,
  ROUND((@page_size * c.CLUST_INDEX_SIZE) /(1024*1024)) AS pk_mb,
  ROUND((@page_size * c.OTHER_INDEX_SIZE) /(1024*1024)) AS secidx_mb
  FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES a
  INNER JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES b on a.NAME = b.NAME
  INNER JOIN INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS c on b.NAME = c.NAME
  WHERE a.NAME LIKE 'employees/%' ORDER BY a.NAME DESC;
+------------------------+------------+-----------+-------+-----------+
| NAME                   | ROW_FORMAT | page_size | pk_mb | secidx_mb |
+------------------------+------------+-----------+-------+-----------+
| employees/titles       | Dynamic    | 16384     | 20    |    11     |
| employees/salaries     | Dynamic    | 16384     | 93    |    34     |
| employees/employees    | Dynamic    | 16384     | 15    |     0     |
| employees/dept_manager | Dynamic    | 16384     |  0    |     0     |
| employees/dept_emp     | Dynamic    | 16384     | 12    |    10     |
| employees/departments  | Dynamic    | 16384     |  0    |     0     |
+------------------------+------------+-----------+-------+-----------+

16.14.4. Таблицы индекса InnoDB INFORMATION_SCHEMA FULLTEXT

Следующие таблицы хранят метаданные для FULLTEXT:

mysql> SHOW TABLES FROM INFORMATION_SCHEMA LIKE 'INNODB_FT%';
+-------------------------------------------+
| Tables_in_INFORMATION_SCHEMA (INNODB_FT%) |
+-------------------------------------------+
| INNODB_FT_CONFIG                          |
| INNODB_FT_BEING_DELETED                   |
| INNODB_FT_DELETED                         |
| INNODB_FT_DEFAULT_STOPWORD                |
| INNODB_FT_INDEX_TABLE                     |
| INNODB_FT_INDEX_CACHE                     |
+-------------------------------------------+

Краткий обзор таблиц

За исключением INNODB_FT_DEFAULT_STOPWORD, Вы должны установить параметр innodb_ft_aux_table к названию таблицы (database_name/table_name), которая содержит индекс FULLTEXT. Иначе таблицы INFORMATION_SCHEMA для индекса FULLTEXT окажутся пустыми.

Пример 16.14. InnoDB Таблицы INFORMATION_SCHEMA FULLTEXT

Этот пример использует таблицу с FULLTEXT, чтобы продемонстрировать данные, содержавшиеся в таблицах INFORMATION_SCHEMA FULLTEXT.

  1. Составьте таблицу с FULLTEXT и вставьте некоторые данные:

    mysql> CREATE TABLE articles (
      id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
      title VARCHAR(200), body TEXT,
      FULLTEXT (title,body)) ENGINE=InnoDB;
    
    INSERT INTO articles (title,body) VALUES
      ('MySQL Tutorial','DBMS stands for DataBase ...'),
      ('How To Use MySQL Well','After you went through a ...'),
      ('Optimizing MySQL','In this tutorial we will show ...'),
      ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
      ('MySQL vs. YourSQL','In the following database comparison ...'),
      ('MySQL Security','When configured properly, MySQL ...');
    
  2. Установите innodb_ft_aux_table к названию таблицы с FULLTEXT. Если эта переменная не установлена, INFORMATION_SCHEMA FULLTEXT таблицы окажутся пустыми, за исключением INNODB_FT_DEFAULT_STOPWORD.
    SET GLOBAL innodb_ft_aux_table = 'test/articles';
    
  3. Запросите INNODB_FT_INDEX_CACHE, которая показывает информацию о недавно вставленных строках в FULLTEXT. Чтобы избежать дорогой перестройки индекса во время операций DML, данные для недавно вставленных строк остаются в кэше FULLTEXT до выполнения OPTIMIZE TABLE, перезапуска сервера или пока кэш не закончится.
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE LIMIT 5;
    +------------+--------------+-------------+-----------+--------+----------+
    | WORD       | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID | POSITION |
    +------------+--------------+-------------+-----------+--------+----------+
    | 1001       |  5           | 5           | 1         |  5     | 0        |
    | after      |  3           | 3           | 1         |  3     | 22       |
    | comparison |  6           | 6           | 1         |  6     | 44       |
    | configured |  7           | 7           | 1         |  7     | 20       |
    | database   |  2           | 6           | 2         |  2     | 31       |
    +------------+--------------+-------------+-----------+--------+----------+
    
  4. Включите innodb_optimize_fulltext_only и выполните OPTIMIZE TABLE на таблице, которая содержит FULLTEXT. Эта работа сбрасывает кэш FULLTEXT в индекс FULLTEXT. innodb_optimize_fulltext_only изменяет логику действий OPTIMIZE TABLE и предназначены, чтобы быть включенным временно, во время операций обслуживания таблиц с FULLTEXT.
    mysql> SET GLOBAL innodb_optimize_fulltext_only=ON;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> OPTIMIZE TABLE articles;
    +---------------+----------+----------+----------+
    | Table         | Op       | Msg_type | Msg_text |
    +---------------+----------+----------+----------+
    | test.articles | optimize | status   | OK       |
    +---------------+----------+----------+----------+
    
  5. Запросите INNODB_FT_INDEX_TABLE, чтобы рассмотреть информацию о данных в основном индексе FULLTEXT, включая информацию о данных, которые только поступили от кэша.
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE LIMIT 5;
    +------------+--------------+-------------+-----------+--------+----------+
    | WORD       | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID | POSITION |
    +------------+--------------+-------------+-----------+--------+----------+
    | 1001       |  5           | 5           | 1         |  5     |        0 |
    | after      |  3           | 3           | 1         |  3     |       22 |
    | comparison |  6           | 6           | 1         |  6     |       44 |
    | configured |  7           | 7           | 1         |  7     |       20 |
    | database   |  2           | 6           | 2         |  2     |       31 |
    +------------+--------------+-------------+-----------+--------+----------+
    

    Таблица INNODB_FT_INDEX_CACHE теперь пуста, начиная с выполнения OPTIMIZE TABLE.

    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE LIMIT 5;
    Empty set (0.00 sec)
    
  6. Удалите некоторые записи из test/articles.
    mysql> DELETE FROM test.articles WHERE id < 4;
    Query OK, 3 rows affected (0.11 sec)
    
  7. Запросите INNODB_FT_DELETED. Эта таблица делает запись строк, которые удалены из FULLTEXT. Чтобы избежать дорогой перестройки индекса во время операций DML, информация о недавно удаленных записях хранится отдельно, фильтруется из результатов поиска, когда Вы делаете текстовый поиск и удалена из основного индекса, когда Вы выполняете OPTIMIZE TABLE.
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DELETED;
    +--------+
    | DOC_ID |
    +--------+
    |  2     |
    |  3     |
    |  4     |
    +--------+
    
  8. Выполните OPTIMIZE TABLE , чтобы дкйствительно удалить удаленные запись.
    mysql> OPTIMIZE TABLE articles;
    +---------------+----------+----------+----------+
    | Table         | Op       | Msg_type | Msg_text |
    +---------------+----------+----------+----------+
    | test.articles | optimize | status   | OK       |
    +---------------+----------+----------+----------+
    

    Таблица INNODB_FT_DELETED должна теперь быть пустой.

    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DELETED;
    Empty set (0.00 sec)
    
  9. Запросите INNODB_FT_CONFIG. Эта таблица содержит метаданные об индексе FULLTEXT и связанной обработке:

    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_CONFIG;
    +---------------------------+-------+
    | KEY                       | VALUE |
    +---------------------------+-------+
    | optimize_checkpoint_limit | 180   |
    | synced_doc_id             |  8    |
    | stopword_table_name       |       |
    | use_stopword              |  1    |
    +---------------------------+-------+
    

16.14.5. Таблицы буферного пула InnoDB INFORMATION_SCHEMA

Таблицы буферного пула обеспечивают информацию о статусе и метаданные о страницах в пределах буферного пула InnoDB.

Таблицы буферного пула включают:

mysql> SHOW TABLES FROM INFORMATION_SCHEMA LIKE 'INNODB_BUFFER%';
+-----------------------------------------------+
| Tables_in_INFORMATION_SCHEMA (INNODB_BUFFER%) |
+-----------------------------------------------+
| INNODB_BUFFER_PAGE_LRU                        |
| INNODB_BUFFER_PAGE                            |
| INNODB_BUFFER_POOL_STATS                      |
+-----------------------------------------------+

Краткий обзор таблиц

Запросы INNODB_BUFFER_PAGE или INNODB_BUFFER_PAGE_LRU могут ввести существенную нагрузку. Не запрашивайте эти таблицы на производственной системе, если Вы не знаете об исполнительном влиянии, которое Ваш запрос может оказать. Чтобы избежать воздействовать на работу, воспроизведите проблему, которую Вы хотите исследовать, на испытательном случае.

Пример 16.15. Запрос системных данных в таблице INNODB_BUFFER_PAGE

Этот запрос предоставляет приблизительное количество страниц, которые содержат системные данные, за исключением страниц, где TABLE_NAME NULL или включает наклонную черту / или точку . в имени таблицы, которое указывает на определяемую пользователем таблицу.

SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
       WHERE TABLE_NAME IS NULL OR (INSTR(TABLE_NAME, '/') = 0 AND
       INSTR(TABLE_NAME, '.') = 0);
+----------+
| COUNT(*) |
+----------+
| 1516     |
+----------+

Этот запрос возвращает приблизительное количество страниц, которые содержат системные данные, общее количество страниц буферного пула и приблизительный процент страниц, которые содержат системные данные.

SELECT (SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
        WHERE TABLE_NAME IS NULL OR (INSTR(TABLE_NAME, '/') = 0 AND
              INSTR(TABLE_NAME, '.') = 0)) AS system_pages,
       (SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE) AS
               total_pages,
       (SELECT ROUND((system_pages/total_pages) * 100)) AS
               system_page_percentage;
+--------------+-------------+------------------------+
| system_pages | total_pages | system_page_percentage |
+--------------+-------------+------------------------+
| 295          | 8192        | 4                      |
+--------------+-------------+------------------------+

Тип системных данных в буферном пуле может быть определен, запрашивая PAGE_TYPE. Например, следующий запрос возвращает восемь отличных PAGE_TYPE среди страниц, которые содержат системные данные:

mysql> SELECT DISTINCT PAGE_TYPE
                 FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
                 WHERE TABLE_NAME IS NULL OR (INSTR(TABLE_NAME, '/') = 0 AND
                 INSTR(TABLE_NAME, '.') = 0);
+-------------------+
| PAGE_TYPE         |
+-------------------+
| SYSTEM            |
| IBUF_BITMAP       |
| UNKNOWN           |
| FILE_SPACE_HEADER |
| INODE             |
| UNDO_LOG          |
| ALLOCATED         |
+-------------------+

Пример 16.16. Запрос пользовательских данных в таблице INNODB_BUFFER_PAGE

Этот запрос предоставляет приблизительное количество страниц, содержащих пользовательские данные, считая страницы, где TABLE_NAME NOT NULL и NOT LIKE '%INNODB_SYS_TABLES%'.

mysql> SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
                 WHERE TABLE_NAME IS NOT NULL AND TABLE_NAME NOT
                 LIKE '%INNODB_SYS_TABLES%';
+----------+
| COUNT(*) |
+----------+
| 7897     |
+----------+

Этот запрос возвращает приблизительное количество страниц, которые содержат пользовательские данные, общее количество страниц буферного пула и приблизительный процент страниц, которые содержат пользовательские данные.

mysql> SELECT (SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
                  WHERE TABLE_NAME IS NOT NULL AND
                  (INSTR(TABLE_NAME, '/') > 0 OR
                  INSTR(TABLE_NAME, '.') > 0)) AS user_pages,
                 (SELECT COUNT(*) FROM information_schema.INNODB_BUFFER_PAGE)
                  AS total_pages,
                 (SELECT ROUND((user_pages/total_pages) * 100)) AS
                  user_page_percentage;
+------------+-------------+----------------------+
| user_pages | total_pages | user_page_percentage |
+------------+-------------+----------------------+
|   7897     | 8192        | 96                   |
+------------+-------------+----------------------+

Этот запрос идентифицирует определяемые пользователем таблицы со страницами в буферном пуле:

mysql> SELECT DISTINCT TABLE_NAME
                 FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
                 WHERE TABLE_NAME IS NOT NULL AND
                 (INSTR(TABLE_NAME, '/') > 0 OR
                 INSTR(TABLE_NAME, '.') > 0) AND
                 TABLE_NAME NOT LIKE '`mysql`.`innodb_%';
+-------------------------+
| TABLE_NAME              |
+-------------------------+
| `employees`.`salaries`  |
| `employees`.`employees` |
+-------------------------+

Пример 16.17. Запрос индексных данных в таблице INNODB_BUFFER_PAGE

Для информации об индексных страницах запросите столбец INDEX_NAME , используя название индекса. Например, следующий запрос возвращает число страниц и полный размер данных страниц для индекса emp_no, который определен на таблице employees.salaries:

mysql> SELECT INDEX_NAME, COUNT(*) AS Pages,
                 ROUND(SUM(IF(COMPRESSED_SIZE = 0, @@global.innodb_page_size,
                       COMPRESSED_SIZE))/1024/1024) AS 'Total Data (MB)'
                 FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
                 WHERE INDEX_NAME='emp_no' AND
                 TABLE_NAME = '`employees`.`salaries`';
+------------+-------+-----------------+
| INDEX_NAME | Pages | Total Data (MB) |
+------------+-------+-----------------+
| emp_no     |  1609 | 25              |
+------------+-------+-----------------+

Этот запрос возвращает число страниц и полный размер данных страниц для всех индексов, определенных в таблице employees.salaries:

mysql> SELECT INDEX_NAME, COUNT(*) AS Pages,
                 ROUND(SUM(IF(COMPRESSED_SIZE = 0, @@global.innodb_page_size,
                 COMPRESSED_SIZE))/1024/1024) AS 'Total Data (MB)'
                 FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
                 WHERE TABLE_NAME = '`employees`.`salaries`'
                 GROUP BY INDEX_NAME;
+------------+-------+-----------------+
| INDEX_NAME | Pages | Total Data (MB) |
+------------+-------+-----------------+
| emp_no     |  1608 | 25              |
| PRIMARY    |  6086 | 95              |
+------------+-------+-----------------+

Пример 16.18. Запрос данных LRU_POSITION в INNODB_BUFFER_PAGE_LRU

INNODB_BUFFER_PAGE_LRU содержит информацию о страницах в буферном пуле, в особенности как он упорядочивается, что определяет, какие страницы вычеркнуть из буферного пула, когда это становится полным. Определение для этой страницы то же самое, как и INNODB_BUFFER_PAGE, но эта таблица имеет столбец LRU_POSITION вместо BLOCK_ID.

Этот запрос считает число позиций в определенном местоположении в списке LRU занятых страницами employees.employees.

mysql> SELECT COUNT(LRU_POSITION)
                 FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU
                 WHERE TABLE_NAME='`employees`.`employees`' AND
                 LRU_POSITION < 3072;
+---------------------+
| COUNT(LRU_POSITION) |
+---------------------+
|   548               |
+---------------------+

Пример 16.19. Запрос INNODB_BUFFER_POOL_STATS

INNODB_BUFFER_POOL_STATS предоставляет информацию, подобную SHOW ENGINE INNODB STATUS и переменным состояния.

mysql> SELECT * FROM information_schema.INNODB_BUFFER_POOL_STATS \G
*************************** 1. row ***************************
 POOL_ID: 0
   POOL_SIZE: 8192
FREE_BUFFERS: 1
DATABASE_PAGES: 8173
OLD_DATABASE_PAGES: 3014
 MODIFIED_DATABASE_PAGES: 0
PENDING_DECOMPRESS: 0
 PENDING_READS: 0
 PENDING_FLUSH_LRU: 0
PENDING_FLUSH_LIST: 0
  PAGES_MADE_YOUNG: 15907
  PAGES_NOT_MADE_YOUNG: 3803101
 PAGES_MADE_YOUNG_RATE: 0
   PAGES_MADE_NOT_YOUNG_RATE: 0
 NUMBER_PAGES_READ: 3270
  NUMBER_PAGES_CREATED: 13176
  NUMBER_PAGES_WRITTEN: 15109
   PAGES_READ_RATE: 0
 PAGES_CREATE_RATE: 0
PAGES_WRITTEN_RATE: 0
  NUMBER_PAGES_GET: 33069332
HIT_RATE: 0
YOUNG_MAKE_PER_THOUSAND_GETS: 0
NOT_YOUNG_MAKE_PER_THOUSAND_GETS: 0
 NUMBER_PAGES_READ_AHEAD: 2713
   NUMBER_READ_AHEAD_EVICTED: 0
   READ_AHEAD_RATE: 0
 READ_AHEAD_EVICTED_RATE: 0
LRU_IO_TOTAL: 0
LRU_IO_CURRENT: 0
  UNCOMPRESS_TOTAL: 0
UNCOMPRESS_CURRENT: 0

Для сравнения SHOW ENGINE INNODB STATUS и переменные состояния показаны ниже, основанные на том же самом наборе данных.

См. раздел 16.16.3.

mysql> SHOW ENGINE INNODB STATUS \G
...
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 137428992
Dictionary memory allocated 579084
Buffer pool size   8192
Free buffers   1
Database pages 8173
Old database pages 3014
Modified db pages  0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 15907, not young 3803101
0.00 youngs/s, 0.00 non-youngs/s
Pages read 3270, created 13176, written 15109
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s,
Random read ahead 0.00/s
LRU len: 8173, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
...

См. раздел 6.1.7.

mysql> SHOW STATUS LIKE 'Innodb_buffer%';
+---------------------------------------+-------------+
| Variable_name                         | Value       |
+---------------------------------------+-------------+
| Innodb_buffer_pool_dump_status        | not started |
| Innodb_buffer_pool_load_status        | not started |
| Innodb_buffer_pool_resize_status      | not started |
| Innodb_buffer_pool_pages_data         | 8173        |
| Innodb_buffer_pool_bytes_data         | 133906432   |
| Innodb_buffer_pool_pages_dirty        | 0           |
| Innodb_buffer_pool_bytes_dirty        | 0           |
| Innodb_buffer_pool_pages_flushed      | 15109       |
| Innodb_buffer_pool_pages_free         | 1           |
| Innodb_buffer_pool_pages_misc         | 18          |
| Innodb_buffer_pool_pages_total        | 8192        |
| Innodb_buffer_pool_read_ahead_rnd     | 0           |
| Innodb_buffer_pool_read_ahead         | 2713        |
| Innodb_buffer_pool_read_ahead_evicted | 0           |
| Innodb_buffer_pool_read_requests      | 33069332    |
| Innodb_buffer_pool_reads              | 558         |
| Innodb_buffer_pool_wait_free          | 0           |
| Innodb_buffer_pool_write_requests     | 11985961    |
+---------------------------------------+-------------+

16.14.6. Таблица метрик InnoDB INFORMATION_SCHEMA

INNODB_METRICS хранит данные производительности и связанных с ресурсом счетчиков:

Столбцы INNODB_METRICS показаны в следующем примере. Для описания каждого столбца см. раздел 22.30.16.

mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS
                   WHERE NAME="dml_inserts" \G
*************************** 1. row ***************************
 NAME: dml_inserts
  SUBSYSTEM: dml
COUNT: 46273
  MAX_COUNT: 46273
  MIN_COUNT: NULL
  AVG_COUNT: 492.2659574468085
COUNT_RESET: 46273
MAX_COUNT_RESET: 46273
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: NULL
   TIME_ENABLED: 2014-11-28 16:07:53
  TIME_DISABLED: NULL
   TIME_ELAPSED: 94
 TIME_RESET: NULL
 STATUS: enabled
 TYPE: status_counter
COMMENT: Number of rows inserted

Управление счетчиками

Вы можете включить, отключить и сбросить счетчики, используя следующие параметры конфигурации:

Вы можете также включить счетчик при запуске, используя конфигурационный файл сервера MySQL. Например, чтобы включить модуль log и счетчики metadata_table_handles_opened и metadata_table_handles_closed, введите следующую строку в раздел [mysqld] конфигурационного файла my.cnf.

[mysqld]
innodb_monitor_enable = module_recovery,metadata_table_handles_opened,metadata_table_handles_closed

Включая много счетчиков в Вашем конфигурационном файле, Вы должны определить innodb_monitor_enable, сопровождаемый счетчиком, отделенными запятой, как показано в примере выше. Только innodb_monitor_enable может использоваться в Вашем конфигурационном файле. Выключение и сброс поддержаны только в командной строке.

Поскольку каждый счетчик налагает определенную степень времени выполнения на сервере, как правило, Вы включаете большое количество счетчиков на сервере теста и развития во время экспериментирования и сопоставительного анализа, и позволяете счетчикам на производственных серверах только диагностировать известные проблемы или аспекты, которые, вероятно, будут узкими местами для особого сервера и рабочей нагрузки.

Счетчики

Счетчики, представленные в INNODB_METRICS подвержены изменениям, таким образом, для самого современного списка, запросите рабочий сервер MySQL. Список ниже перечисляет счетчики, которые доступны с MySQL 8.0.

Счетчики, которые включены по умолчанию, соответствуют используемым SHOW ENGINE INNODB STATUS. Счетчики, используемые SHOW ENGINE INNODB STATUS, всегда on на системном уровне, но Вы можете отключить эти счетчики для INNODB_METRICS, как требуется. Кроме того, состояние не является постоянным. Если не определено иное, счетчики возвращаются к своему значению по умолчанию, когда сервер перезапущен.

Если бы Вы выполняете программы, которые были бы затронуты дополнениями или изменяют INNODB_METRICS , рекомендуется, чтобы Вы рассмотрели примечания выпусков и запросили INNODB_METRICS для нового выпуска до обновления.

mysql> SELECT name, subsystem, status
                 FROM INFORMATION_SCHEMA.INNODB_METRICS ORDER BY NAME;
+------------------------------------------+---------------------+----------+
| name                                     | subsystem           | status   |
+------------------------------------------+---------------------+----------+
| adaptive_hash_pages_added                | adaptive_hash_index | disabled |
| adaptive_hash_pages_removed              | adaptive_hash_index | disabled |
| adaptive_hash_rows_added                 | adaptive_hash_index | disabled |
| adaptive_hash_rows_deleted_no_hash_entry | adaptive_hash_index | disabled |
| adaptive_hash_rows_removed               | adaptive_hash_index | disabled |
| adaptive_hash_rows_updated               | adaptive_hash_index | disabled |
| adaptive_hash_searches                   | adaptive_hash_index | enabled  |
| adaptive_hash_searches_btree             | adaptive_hash_index | enabled  |
| buffer_data_reads                        | buffer              | enabled  |
| buffer_data_written                      | buffer              | enabled  |
| buffer_flush_adaptive                    | buffer              | disabled |
| buffer_flush_adaptive_avg_pass           | buffer              | disabled |
| buffer_flush_adaptive_avg_time_est       | buffer              | disabled |
| buffer_flush_adaptive_avg_time_slot      | buffer              | disabled |
| buffer_flush_adaptive_avg_time_thread    | buffer              | disabled |
| buffer_flush_adaptive_pages              | buffer              | disabled |
| buffer_flush_adaptive_total_pages        | buffer              | disabled |
| buffer_flush_avg_page_rate               | buffer              | disabled |
| buffer_flush_avg_pass                    | buffer              | disabled |
| buffer_flush_avg_time                    | buffer              | disabled |
| buffer_flush_background                  | buffer              | disabled |
| buffer_flush_background_pages            | buffer              | disabled |
| buffer_flush_background_total_pages      | buffer              | disabled |
| buffer_flush_batches                     | buffer              | disabled |
| buffer_flush_batch_num_scan              | buffer              | disabled |
| buffer_flush_batch_pages                 | buffer              | disabled |
| buffer_flush_batch_scanned               | buffer              | disabled |
| buffer_flush_batch_scanned_per_call      | buffer              | disabled |
| buffer_flush_batch_total_pages           | buffer              | disabled |
| buffer_flush_lsn_avg_rate                | buffer              | disabled |
| buffer_flush_neighbor                    | buffer              | disabled |
| buffer_flush_neighbor_pages              | buffer              | disabled |
| buffer_flush_neighbor_total_pages        | buffer              | disabled |
| buffer_flush_n_to_flush_by_age           | buffer              | disabled |
| buffer_flush_n_to_flush_requested        | buffer              | disabled |
| buffer_flush_pct_for_dirty               | buffer              | disabled |
| buffer_flush_pct_for_lsn                 | buffer              | disabled |
| buffer_flush_sync                        | buffer              | disabled |
| buffer_flush_sync_pages                  | buffer              | disabled |
| buffer_flush_sync_total_pages            | buffer              | disabled |
| buffer_flush_sync_waits                  | buffer              | disabled |
| buffer_LRU_batches_evict                 | buffer              | disabled |
| buffer_LRU_batches_flush                 | buffer              | disabled |
| buffer_LRU_batch_evict_pages             | buffer              | disabled |
| buffer_LRU_batch_evict_total_pages       | buffer              | disabled |
| buffer_LRU_batch_flush_avg_pass          | buffer              | disabled |
| buffer_LRU_batch_flush_avg_time_est      | buffer              | disabled |
| buffer_LRU_batch_flush_avg_time_slot     | buffer              | disabled |
| buffer_LRU_batch_flush_avg_time_thread   | buffer              | disabled |
| buffer_LRU_batch_flush_pages             | buffer              | disabled |
| buffer_LRU_batch_flush_total_pages       | buffer              | disabled |
| buffer_LRU_batch_num_scan                | buffer              | disabled |
| buffer_LRU_batch_scanned                 | buffer              | disabled |
| buffer_LRU_batch_scanned_per_call        | buffer              | disabled |
| buffer_LRU_get_free_loops                | buffer              | disabled |
| buffer_LRU_get_free_search               | Buffer              | disabled |
| buffer_LRU_get_free_waits                | buffer              | disabled |
| buffer_LRU_search_num_scan               | buffer              | disabled |
| buffer_LRU_search_scanned                | buffer              | disabled |
| buffer_LRU_search_scanned_per_call       | buffer              | disabled |
| buffer_LRU_single_flush_failure_count    | Buffer              | disabled |
| buffer_LRU_single_flush_num_scan         | buffer              | disabled |
| buffer_LRU_single_flush_scanned          | buffer              | disabled |
| buffer_LRU_single_flush_scanned_per_call | buffer              | disabled |
| buffer_LRU_unzip_search_num_scan         | buffer              | disabled |
| buffer_LRU_unzip_search_scanned          | buffer              | disabled |
| buffer_LRU_unzip_search_scanned_per_call | buffer              | disabled |
| buffer_pages_created                     | buffer              | enabled  |
| buffer_pages_read                        | buffer              | enabled  |
| buffer_pages_written                     | buffer              | enabled  |
| buffer_page_read_blob                    | buffer_page_io      | disabled |
| buffer_page_read_fsp_hdr                 | buffer_page_io      | disabled |
| buffer_page_read_ibuf_bitmap             | buffer_page_io      | disabled |
| buffer_page_read_ibuf_free_list          | buffer_page_io      | disabled |
| buffer_page_read_index_ibuf_leaf         | buffer_page_io      | disabled |
| buffer_page_read_index_ibuf_non_leaf     | buffer_page_io      | disabled |
| buffer_page_read_index_inode             | buffer_page_io      | disabled |
| buffer_page_read_index_leaf              | buffer_page_io      | disabled |
| buffer_page_read_index_non_leaf          | buffer_page_io      | disabled |
| buffer_page_read_other                   | buffer_page_io      | disabled |
| buffer_page_read_system_page             | buffer_page_io      | disabled |
| buffer_page_read_trx_system              | buffer_page_io      | disabled |
| buffer_page_read_undo_log                | buffer_page_io      | disabled |
| buffer_page_read_xdes                    | buffer_page_io      | disabled |
| buffer_page_read_zblob                   | buffer_page_io      | disabled |
| buffer_page_read_zblob2                  | buffer_page_io      | disabled |
| buffer_page_written_blob                 | buffer_page_io      | disabled |
| buffer_page_written_fsp_hdr              | buffer_page_io      | disabled |
| buffer_page_written_ibuf_bitmap          | buffer_page_io      | disabled |
| buffer_page_written_ibuf_free_list       | buffer_page_io      | disabled |
| buffer_page_written_index_ibuf_leaf      | buffer_page_io      | disabled |
| buffer_page_written_index_ibuf_non_leaf  | buffer_page_io      | disabled |
| buffer_page_written_index_inode          | buffer_page_io      | disabled |
| buffer_page_written_index_leaf           | buffer_page_io      | disabled |
| buffer_page_written_index_non_leaf       | buffer_page_io      | disabled |
| buffer_page_written_other                | buffer_page_io      | disabled |
| buffer_page_written_system_page          | buffer_page_io      | disabled |
| buffer_page_written_trx_system           | buffer_page_io      | disabled |
| buffer_page_written_undo_log             | buffer_page_io      | disabled |
| buffer_page_written_xdes                 | buffer_page_io      | disabled |
| buffer_page_written_zblob                | buffer_page_io      | disabled |
| buffer_page_written_zblob2               | buffer_page_io      | disabled |
| buffer_pool_bytes_data                   | buffer              | enabled  |
| buffer_pool_bytes_dirty                  | buffer              | enabled  |
| buffer_pool_pages_data                   | buffer              | enabled  |
| buffer_pool_pages_dirty                  | buffer              | enabled  |
| buffer_pool_pages_free                   | buffer              | enabled  |
| buffer_pool_pages_misc                   | buffer              | enabled  |
| buffer_pool_pages_total                  | buffer              | enabled  |
| buffer_pool_reads                        | buffer              | enabled  |
| buffer_pool_read_ahead                   | buffer              | enabled  |
| buffer_pool_read_ahead_evicted           | buffer              | enabled  |
| buffer_pool_read_requests                | buffer              | enabled  |
| buffer_pool_size                         | server              | enabled  |
| buffer_pool_wait_free                    | buffer              | enabled  |
| buffer_pool_write_requests               | buffer              | enabled  |
| compression_pad_decrements               | compression         | disabled |
| compression_pad_increments               | compression         | disabled |
| compress_pages_compressed                | compression         | disabled |
| compress_pages_decompressed              | compression         | disabled |
| ddl_background_drop_indexes              | ddl                 | disabled |
| ddl_background_drop_tables               | ddl                 | disabled |
| ddl_log_file_alter_table                 | ddl                 | disabled |
| ddl_online_create_index                  | ddl                 | disabled |
| ddl_pending_alter_table                  | ddl                 | disabled |
| ddl_sort_file_alter_table                | ddl                 | disabled |
| dml_deletes                              | dml                 | enabled  |
| dml_inserts                              | dml                 | enabled  |
| dml_reads                                | dml                 | disabled |
| dml_updates                              | dml                 | enabled  |
| file_num_open_files                      | file_system         | enabled  |
| ibuf_merges                              | change_buffer       | enabled  |
| ibuf_merges_delete                       | change_buffer       | enabled  |
| ibuf_merges_delete_mark                  | change_buffer       | enabled  |
| ibuf_merges_discard_delete               | change_buffer       | enabled  |
| ibuf_merges_discard_delete_mark          | change_buffer       | enabled  |
| ibuf_merges_discard_insert               | change_buffer       | enabled  |
| ibuf_merges_insert                       | change_buffer       | enabled  |
| ibuf_size                                | change_buffer       | enabled  |
| icp_attempts                             | icp                 | disabled |
| icp_match                                | icp                 | disabled |
| icp_no_match                             | icp                 | disabled |
| icp_out_of_range                         | icp                 | disabled |
| index_page_discards                      | index               | disabled |
| index_page_merge_attempts                | index               | disabled |
| index_page_merge_successful              | index               | disabled |
| index_page_reorg_attempts                | index               | disabled |
| index_page_reorg_successful              | index               | disabled |
| index_page_splits                        | index               | disabled |
| innodb_activity_count                    | server              | enabled  |
| innodb_background_drop_table_usec        | server              | disabled |
| innodb_checkpoint_usec                   | server              | disabled |
| innodb_dblwr_pages_written               | server              | enabled  |
| innodb_dblwr_writes                      | server              | enabled  |
| innodb_dict_lru_count                    | server              | disabled |
| innodb_dict_lru_usec                     | server              | disabled |
| innodb_ibuf_merge_usec                   | server              | disabled |
| innodb_log_flush_usec                    | server              | disabled |
| innodb_master_active_loops               | server              | disabled |
| innodb_master_idle_loops                 | server              | disabled |
| innodb_master_purge_usec                 | server              | disabled |
| innodb_master_thread_sleeps              | server              | disabled |
| innodb_mem_validate_usec                 | server              | disabled |
| innodb_page_size                         | server              | enabled  |
| innodb_rwlock_sx_os_waits                | server              | enabled  |
| innodb_rwlock_sx_spin_rounds             | server              | enabled  |
| innodb_rwlock_sx_spin_waits              | server              | enabled  |
| innodb_rwlock_s_os_waits                 | server              | enabled  |
| innodb_rwlock_s_spin_rounds              | server              | enabled  |
| innodb_rwlock_s_spin_waits               | server              | enabled  |
| innodb_rwlock_x_os_waits                 | server              | enabled  |
| innodb_rwlock_x_spin_rounds              | server              | enabled  |
| innodb_rwlock_x_spin_waits               | server              | enabled  |
| lock_deadlocks                           | lock                | enabled  |
| lock_rec_locks                           | lock                | disabled |
| lock_rec_lock_created                    | lock                | disabled |
| lock_rec_lock_removed                    | lock                | disabled |
| lock_rec_lock_requests                   | lock                | disabled |
| lock_rec_lock_waits                      | lock                | disabled |
| lock_row_lock_current_waits              | lock                | enabled  |
| lock_row_lock_time                       | lock                | enabled  |
| lock_row_lock_time_avg                   | lock                | enabled  |
| lock_row_lock_time_max                   | lock                | enabled  |
| lock_row_lock_waits                      | lock                | enabled  |
| lock_table_locks                         | lock                | disabled |
| lock_table_lock_created                  | lock                | disabled |
| lock_table_lock_removed                  | lock                | disabled |
| lock_table_lock_waits                    | lock                | disabled |
| lock_timeouts                            | lock                | enabled  |
| log_checkpoints                          | recovery            | disabled |
| log_lsn_buf_pool_oldest                  | recovery            | disabled |
| log_lsn_checkpoint_age                   | recovery            | disabled |
| log_lsn_current                          | recovery            | disabled |
| log_lsn_last_checkpoint                  | recovery            | disabled |
| log_lsn_last_flush                       | recovery            | disabled |
| log_max_modified_age_async               | recovery            | disabled |
| log_max_modified_age_sync                | recovery            | disabled |
| log_num_log_io                           | recovery            | disabled |
| log_padded                               | recovery            | enabled  |
| log_pending_checkpoint_writes            | recovery            | disabled |
| log_pending_log_flushes                  | recovery            | disabled |
| log_waits                                | recovery            | enabled  |
| log_writes                               | recovery            | enabled  |
| log_write_requests                       | recovery            | enabled  |
| metadata_table_handles_closed            | metadata            | disabled |
| metadata_table_handles_opened            | metadata            | disabled |
| metadata_table_reference_count           | metadata            | disabled |
| os_data_fsyncs                           | os                  | enabled  |
| os_data_reads                            | os                  | enabled  |
| os_data_writes                           | os                  | enabled  |
| os_log_bytes_written                     | os                  | enabled  |
| os_log_fsyncs                            | os                  | enabled  |
| os_log_pending_fsyncs                    | os                  | enabled  |
| os_log_pending_writes                    | os                  | enabled  |
| os_pending_reads                         | os                  | disabled |
| os_pending_writes                        | os                  | disabled |
| purge_del_mark_records                   | purge               | disabled |
| purge_dml_delay_usec                     | purge               | disabled |
| purge_invoked                            | purge               | disabled |
| purge_resume_count                       | purge               | disabled |
| purge_stop_count                         | purge               | disabled |
| purge_undo_log_pages                     | purge               | disabled |
| purge_upd_exist_or_extern_records        | purge               | disabled |
| trx_active_transactions                  | transaction         | disabled |
| trx_commits_insert_update                | transaction         | disabled |
| trx_nl_ro_commits                        | transaction         | disabled |
| trx_rollbacks                            | transaction         | disabled |
| trx_rollbacks_savepoint                  | transaction         | disabled |
| trx_rollback_active                      | transaction         | disabled |
| trx_ro_commits                           | transaction         | disabled |
| trx_rseg_current_size                    | transaction         | disabled |
| trx_rseg_history_len                     | transaction         | enabled  |
| trx_rw_commits                           | transaction         | disabled |
| trx_undo_slots_cached                    | transaction         | disabled |
| trx_undo_slots_used                      | transaction         | disabled |
+------------------------------------------+---------------------+----------+
235 rows in set (0.01 sec)

Модули счетчиков

Имена модуля соответствуют, но не идентичны, значениям столбца SUBSYSTEM таблицы INNODB_METRICS. Вместо включения, отключения или сброса счетчиков индивидуально, Вы можете использовать имена модуля, чтобы быстро включить, отключить или сбросить все счетчики для особой подсистемы. Например, использовать module_dml, чтобы включить все счетчики, связанные с подсистемой dml.

mysql> SET GLOBAL innodb_monitor_enable = module_dml;
mysql> SELECT name, subsystem, status
                 FROM INFORMATION_SCHEMA.INNODB_METRICS
                 WHERE subsystem ='dml';
+-------------+-----------+---------+
| name        | subsystem | status  |
+-------------+-----------+---------+
| dml_reads   | dml       | enabled |
| dml_inserts | dml       | enabled |
| dml_deletes | dml       | enabled |
| dml_updates | dml       | enabled |
+-------------+-----------+---------+

Вот значения, для которых Вы можете использовать module_name с опцией innodb_monitor_enable и связанные параметры конфигурации, наряду с передачей имен SUBSYSTEM:

Пример 16.20. Работа с табличными счетчиками INNODB_METRICS

Этот пример демонстрирует включение, отключение, сброс счетчика и запрос данных счетчика в таблице INNODB_METRICS.

  1. Создайте простую таблицу:

    mysql> USE test;
    Database changed
    
    mysql> CREATE TABLE t1 (c1 INT) ENGINE=INNODB;
    Query OK, 0 rows affected (0.02 sec)
    
  2. Включите счетчик dml_inserts.
    mysql> SET GLOBAL innodb_monitor_enable = dml_inserts;
    Query OK, 0 rows affected (0.01 sec)
    

    Описание dml_inserts может быть найдено в столбце COMMENT таблицы INNODB_METRICS:

    mysql> SELECT NAME, COMMENT FROM INFORMATION_SCHEMA.INNODB_METRICS
                     WHERE NAME="dml_inserts";
    +-------------+-------------------------+
    | NAME        | COMMENT                 |
    +-------------+-------------------------+
    | dml_inserts | Number of rows inserted |
    +-------------+-------------------------+
    
  3. Запросите INNODB_METRICS для данных счетчика dml_inserts. Поскольку никакие операции DML не были выполнены, значения ноль или NULL. TIME_ENABLED и TIME_ELAPSED указывают, когда счетчик был последний раз включен и сколько секунд прошло с этого времени.
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS
                       WHERE NAME="dml_inserts" \G
    *************************** 1. row ***************************
     NAME: dml_inserts
      SUBSYSTEM: dml
    COUNT: 0
      MAX_COUNT: 0
      MIN_COUNT: NULL
      AVG_COUNT: 0
    COUNT_RESET: 0
    MAX_COUNT_RESET: 0
    MIN_COUNT_RESET: NULL
    AVG_COUNT_RESET: NULL
       TIME_ENABLED: 2014-12-04 14:18:28
      TIME_DISABLED: NULL
       TIME_ELAPSED: 28
     TIME_RESET: NULL
     STATUS: enabled
     TYPE: status_counter
    COMMENT: Number of rows inserted
    
  4. Вставьте три строки данных в таблицу.
    mysql> INSERT INTO t1 values(1);
    Query OK, 1 row affected (0.00 sec)
    
    mysql> INSERT INTO t1 values(2);
    Query OK, 1 row affected (0.00 sec)
    
    mysql> INSERT INTO t1 values(3);
    Query OK, 1 row affected (0.00 sec)
    
  5. Запросите INNODB_METRICS снова для данных счетчика dml_inserts. Много значений теперь постепенно увеличились, включая COUNT, MAX_COUNT, AVG_COUNT и COUNT_RESET. Обратитесь к определению таблицы INNODB_METRICS для описаний этих значений.
    mysql>  SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS
                        WHERE NAME="dml_inserts"\G
    *************************** 1. row ***************************
     NAME: dml_inserts
      SUBSYSTEM: dml
    COUNT: 3
      MAX_COUNT: 3
      MIN_COUNT: NULL
      AVG_COUNT: 0.046153846153846156
    COUNT_RESET: 3
    MAX_COUNT_RESET: 3
    MIN_COUNT_RESET: NULL
    AVG_COUNT_RESET: NULL
       TIME_ENABLED: 2014-12-04 14:18:28
      TIME_DISABLED: NULL
       TIME_ELAPSED: 65
     TIME_RESET: NULL
     STATUS: enabled
     TYPE: status_counter
    COMMENT: Number of rows inserted
    
  6. Сбросьте счетчик dml_inserts и запросите INNODB_METRICS для данных счетчика dml_inserts. Значения %_RESET, о которых сообщили ранее, COUNT_RESET и MAX_RESET, сброшены к нолю. Значения COUNT, MAX_COUNT и AVG_COUNT, которые кумулятивно собирают данные со времени включения счетчика, сбросом не затронуты.
    mysql> SET GLOBAL innodb_monitor_reset = dml_inserts;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS
                       WHERE NAME="dml_inserts"\G
    *************************** 1. row ***************************
     NAME: dml_inserts
      SUBSYSTEM: dml
    COUNT: 3
      MAX_COUNT: 3
      MIN_COUNT: NULL
      AVG_COUNT: 0.03529411764705882
    COUNT_RESET: 0
    MAX_COUNT_RESET: 0
    MIN_COUNT_RESET: NULL
    AVG_COUNT_RESET: 0
       TIME_ENABLED: 2014-12-04 14:18:28
      TIME_DISABLED: NULL
       TIME_ELAPSED: 85
     TIME_RESET: 2014-12-04 14:19:44
     STATUS: enabled
     TYPE: status_counter
    COMMENT: Number of rows inserted
    
  7. Чтобы сбросить все значения, Вы должны сначала отключить счетчик. Отключение счетчика устанавливает значение STATUS в disbaled.
    mysql> SET GLOBAL innodb_monitor_disable = dml_inserts;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS
                       WHERE NAME="dml_inserts"\G
    *************************** 1. row ***************************
     NAME: dml_inserts
      SUBSYSTEM: dml
    COUNT: 3
      MAX_COUNT: 3
      MIN_COUNT: NULL
      AVG_COUNT: 0.030612244897959183
    COUNT_RESET: 0
    MAX_COUNT_RESET: 0
    MIN_COUNT_RESET: NULL
    AVG_COUNT_RESET: 0
       TIME_ENABLED: 2014-12-04 14:18:28
      TIME_DISABLED: 2014-12-04 14:20:06
       TIME_ELAPSED: 98
     TIME_RESET: NULL
     STATUS: disabled
     TYPE: status_counter
    COMMENT: Number of rows inserted
    

    Подстановочное соответствие поддержано для счетчика и имен модуля. Например, вместо того, чтобы определить полное имя dml_inserts, Вы можете определить dml_i%. Вы можете также включить, отключить или сбросить много счетчиков или модулей, используя подстановочное соответствие. Например, определите dml_% для всех счетчиков, имена которых начинаются на dml_.

  8. После того, как счетчик отключен, Вы можете сбросить все значения, используя innodb_monitor_reset_all. Все значения установлены в ноль или NULL.

    mysql> SET GLOBAL innodb_monitor_reset_all = dml_inserts;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS
                       WHERE NAME="dml_inserts"\G
    *************************** 1. row ***************************
     NAME: dml_inserts
      SUBSYSTEM: dml
    COUNT: 0
      MAX_COUNT: NULL
      MIN_COUNT: NULL
      AVG_COUNT: NULL
    COUNT_RESET: 0
    MAX_COUNT_RESET: NULL
    MIN_COUNT_RESET: NULL
    AVG_COUNT_RESET: NULL
       TIME_ENABLED: NULL
      TIME_DISABLED: NULL
       TIME_ELAPSED: NULL
     TIME_RESET: NULL
     STATUS: disabled
     TYPE: status_counter
    COMMENT: Number of rows inserted
    

16.14.7. Информация о временных таблицах в InnoDB INFORMATION_SCHEMA

INNODB_TEMP_TABLE_INFO предоставляет пользователям снимок активных временные таблицы. Таблица содержит метаданные обо всех создаваемых пользователями и системой временных таблицах, которые являются активными в пределах InnoDB.

mysql> SHOW TABLES FROM INFORMATION_SCHEMA LIKE 'INNODB_TEMP%';
+---------------------------------------------+
| Tables_in_INFORMATION_SCHEMA (INNODB_TEMP%) |
+---------------------------------------------+
| INNODB_TEMP_TABLE_INFO                      |
+---------------------------------------------+

См. раздел 22.30.27.

Пример 16.21. INNODB_TEMP_TABLE_INFO

Этот пример демонстрирует характеристики INNODB_TEMP_TABLE_INFO table.

  1. Создайте простую временную таблицу с единственным столбцом:

    mysql> CREATE TEMPORARY TABLE t1 (c1 INT PRIMARY KEY) ENGINE=INNODB;
    Query OK, 0 rows affected (0.00 sec)
    
  2. Запросите INNODB_TEMP_TABLE_INFO, чтобы рассмотреть метаданные временной таблицы.
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO\G
    *************************** 1. row ***************************
      TABLE_ID: 194
      NAME: #sql7a79_1_0
    N_COLS: 4
     SPACE: 182
    

    TABLE_ID уникальный идентификатор для временной таблицы. NAME выводит на экран произведенное системой название временной таблицы с префиксом #sql. Число столбцов (N_COLS) 4 вместо 1, потому что InnoDB всегда создает три скрытых столбца таблицы (DB_ROW_ID, DB_TRX_ID и DB_ROLL_PTR).

  3. Перезапустите MySQL и запросите INNODB_TEMP_TABLE_INFO.
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO\G
    Empty set (0.00 sec)
    

    Пустой набор возвращен потому, что таблица INNODB_TEMP_TABLE_INFO и данные в пределах нее не сохранены на диск при завершении работы сервера.

  4. Составьте новую временную таблицу.
    mysql> CREATE TEMPORARY TABLE t1 (c1 INT PRIMARY KEY) ENGINE=INNODB;
    Query OK, 0 rows affected (0.00 sec)
    
  5. Запросите INNODB_TEMP_TABLE_INFO, чтобы рассмотреть метаданные временной таблицы.
    mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO\G
    *************************** 1. row ***************************
      TABLE_ID: 196
      NAME: #sql7b0e_1_0
    N_COLS: 4
     SPACE: 184
    

    ID SPACE новый, потому что динамически произведен при перезапуске сервера.

16.14.8. Получение метаданных о табличном пространстве из INFORMATION_SCHEMA.FILES

INFORMATION_SCHEMA.FILES обеспечивает метаданные обо всех типах табличного пространства, включая file-per-table, общие табличные пространства , системное табличное пространство, временные табличные пространства и табличные пространства отмены (если есть).

The INNODB_SYS_TABLESPACES и INNODB_SYS_DATAFILES также обеспечивают метаданные о табличных пространствах, но данные ограничены file-per-table и общими табличными пространствами.

Этот запрос получает метаданные о системном табличном пространстве от полей INFORMATION_SCHEMA.FILES , которые являются подходящими для табличных пространств. Поля INFORMATION_SCHEMA.FILES, которые не подходят, всегда возвращают NULL и исключены из запроса.

mysql> SELECT FILE_ID, FILE_NAME, FILE_TYPE, TABLESPACE_NAME, FREE_EXTENTS,
                 TOTAL_EXTENTS, EXTENT_SIZE, INITIAL_SIZE, MAXIMUM_SIZE,
                 AUTOEXTEND_SIZE, DATA_FREE, STATUS ENGINE
                 FROM INFORMATION_SCHEMA.FILES WHERE TABLESPACE_NAME
                 LIKE 'innodb_system' \G
*************************** 1. row ***************************
FILE_ID: 0
  FILE_NAME: ./ibdata1
  FILE_TYPE: TABLESPACE
TABLESPACE_NAME: innodb_system
   FREE_EXTENTS: 0
  TOTAL_EXTENTS: 12
EXTENT_SIZE: 1048576
   INITIAL_SIZE: 12582912
   MAXIMUM_SIZE: NULL
AUTOEXTEND_SIZE: 67108864
  DATA_FREE: 4194304
 ENGINE: NORMAL

Этот запрос получает FILE_ID (эквивалентный ID пространства) и FILE_NAME (который включает информацию о пути) для file-per-table и общих табличных пространств. У File-per-table и общих табличных пространств есть расширение файла .ibd.

mysql> SELECT FILE_ID, FILE_NAME FROM INFORMATION_SCHEMA.FILES
                 WHERE FILE_NAME LIKE '%.ibd%' ORDER BY FILE_ID;
+---------+---------------------------------------+
| FILE_ID | FILE_NAME                             |
+---------+---------------------------------------+
|   2     | ./mysql/plugin.ibd                    |
|   3     | ./mysql/servers.ibd                   |
|   4     | ./mysql/help_topic.ibd                |
|   5     | ./mysql/help_category.ibd             |
|   6     | ./mysql/help_relation.ibd             |
|   7     | ./mysql/help_keyword.ibd              |
|   8     | ./mysql/time_zone_name.ibd            |
|   9     | ./mysql/time_zone.ibd                 |
|  10     | ./mysql/time_zone_transition.ibd      |
|  11     | ./mysql/time_zone_transition_type.ibd |
|  12     | ./mysql/time_zone_leap_second.ibd     |
|  13     | ./mysql/innodb_table_stats.ibd        |
|  14     | ./mysql/innodb_index_stats.ibd        |
|  15     | ./mysql/slave_relay_log_info.ibd      |
|  16     | ./mysql/slave_master_info.ibd         |
|  17     | ./mysql/slave_worker_info.ibd         |
|  18     | ./mysql/gtid_executed.ibd             |
|  19     | ./mysql/server_cost.ibd               |
|  20     | ./mysql/engine_cost.ibd               |
|  21     | ./sys/sys_config.ibd                  |
|  23     | ./test/t1.ibd                         |
|  26     | /home/user/test/test/t2.ibd           |
+---------+---------------------------------------+

Этот запрос получает FILE_ID и FILE_NAME для временных табличных пространств. Временные имена файла табличного пространства имеют префикс ibtmp.

mysql> SELECT FILE_ID, FILE_NAME FROM INFORMATION_SCHEMA.FILES
                 WHERE FILE_NAME LIKE '%ibtmp%';
+---------+-----------+
| FILE_ID | FILE_NAME |
+---------+-----------+
|  22     | ./ibtmp1  |
+---------+-----------+

Точно так же имена файла табличного пространства отмены имеют префикс undo. Следующий запрос возвращает FILE_ID и FILE_NAME для табличных пространств отмены, если отдельные табличные пространства отмены сконфигурированы.

mysql> SELECT FILE_ID, FILE_NAME FROM INFORMATION_SCHEMA.FILES
                 WHERE FILE_NAME LIKE '%undo%';

16.15. Интеграция с MySQL Performance Schema

Этот раздел обеспечивает краткое введение в интеграцию с Performance Schema. См. главу 23.

Вы можете профилировать внутренние операции, использующие MySQL Performance Schema. Этот тип настройки прежде всего для опытных пользователей, которые оценивают стратегии оптимизации, чтобы преодолеть исполнительные узкие места. DBA может также использовать эту функцию для планирования мощностей, чтобы видеть, сталкивается ли их типичная рабочая нагрузка с какими-либо исполнительными узкими местами с особой комбинацией центрального процессора, RAM и дискового хранения, и если так, чтобы судить, может ли работа быть улучшена, увеличивая параметры некоторой части системы.

Используйте эту функцию, чтобы исследовать:

16.15.1. Контроль ALTER TABLE для таблиц InnoDB, используя Performance Schema

Вы можете контролировать продвижение ALTER TABLE для таблиц InnoDB, используя Performance Schema.

Есть семь событий этапа, которые представляют различные фазы ALTER TABLE. Каждый случай этапа сообщает о рабочем общем количестве WORK_COMPLETED и WORK_ESTIMATED для полного ALTER TABLE, поскольку это прогрессирует через свои различные фазы. WORK_ESTIMATED вычислен, используя формулу, которая принимает во внимание всю работу ALTER TABLE, и может быть пересмотрен во время ALTER TABLE. WORK_COMPLETED и WORK_ESTIMATED абстрактное представление всей работы, выполненной ALTER TABLE.

В порядке возникновения ALTER TABLE события этапа включают:

События этапа ALTER TABLE в настоящее время не составляют добавление пространственных индексов.

Пример мониторинга ALTER TABLE, используя Performance Schema

Следующий пример демонстрирует, как включить инструменты этапа событий stage/innodb/alter table% и связанные потребительские таблицы, чтобы контролировать ход ALTER TABLE . Для информации об исполнительных инструментах этапа Performance Schema см. раздел 23.9.5 .

  1. Включите инструменты stage/innodb/alter%:

    mysql> UPDATE setup_instruments SET ENABLED = 'YES'
                     WHERE NAME LIKE 'stage/innodb/alter%';
    Query OK, 7 rows affected (0.00 sec)
    Rows matched: 7  Changed: 7  Warnings: 0
    
  2. Включите потребительским таблицам этапа событий, которые включают events_stages_current , events_stages_history и events_stages_history_long.
    mysql> UPDATE setup_consumers SET ENABLED = 'YES'
                     WHERE NAME LIKE '%stages%';
    Query OK, 3 rows affected (0.00 sec)
    Rows matched: 3  Changed: 3  Warnings: 0
    
  3. Запустите ALTER TABLE. В этом примере столбец middle_name добавлен к таблице базы данных образца.
    mysql> ALTER TABLE employees.employees
                    ADD COLUMN middle_name varchar(14)
                    AFTER first_name;
    Query OK, 0 rows affected (9.27 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
  4. Проверьте продвижение ALTER TABLE, запросив Performance Schema events_stages_current . Показанный случай этапа отличается в зависимости от текущей фазы ALTER TABLE. Столбец WORK_COMPLETED показывает завершенную работу. WORK_ESTIMATED обеспечивает оценку остающейся работы.
    mysql> SELECT EVENT_NAME, WORK_COMPLETED, WORK_ESTIMATED
                     FROM events_stages_current;
    +------------------------------------------------------+----------------+----------------+
    | EVENT_NAME                                           | WORK_COMPLETED | WORK_ESTIMATED |
    +------------------------------------------------------+----------------+----------------+
    | stage/innodb/alter table (read PK and internal sort) |  280           | 1245           |
    +------------------------------------------------------+----------------+----------------+
    1 row in set (0.01 sec)
    

    events_stages_current возвращает пустой набор, если ALTER TABLE завершилась. В этом случае Вы можете проверить events_stages_history , чтобы смотреть данные событий для завершенной работы. Например:

    mysql> SELECT EVENT_NAME, WORK_COMPLETED, WORK_ESTIMATED
                     FROM events_stages_history;
    +------------------------------------------------------+----------------+----------------+
    | EVENT_NAME                                           | WORK_COMPLETED | WORK_ESTIMATED |
    +------------------------------------------------------+----------------+----------------+
    | stage/innodb/alter table (read PK and internal sort) |  886           | 1213           |
    | stage/innodb/alter table (flush)                     | 1213           | 1213           |
    | stage/innodb/alter table (log apply table)           | 1597           | 1597           |
    | stage/innodb/alter table (end)                       | 1597           | 1597           |
    | stage/innodb/alter table (log apply table)           | 1981           | 1981           |
    +------------------------------------------------------+----------------+----------------+
    5 rows in set (0.00 sec)
    

    Как показано выше, WORK_ESTIMATED было пересмотрено во время ALTER TABLE. Предполагаемая работа после завершения начальной стадии 1213. Когда обработка ALTER TABLE завершалась, WORK_ESTIMATED был установлен в фактическое значение, которое является 1981.

16.15.2. Мониторинг InnoDB Mutex Waits с Performance Schema

mutex это механизм синхронизации, используемый в коде, чтобы провести в жизнь правило, что только один поток в установленный срок может иметь доступ к общему ресурсу. Когда два или больше потоков в сервере должны получить доступ к тому же самому ресурсу, потоки конкурируют друг против друга. Первый поток, который получит блокировку на mutex, заставляет другие потоки ждать, пока блокировка не выпущена.

Для InnoDB mutexes, которые инструментованы, mutex waits может быть проверен, используя Performance Schema. Данные событий ожидания, собранные в Performance Schema, могут помочь идентифицировать mutexes с наибольшим ожиданием или самое большое общее количество времени ожидания.

Следующий пример демонстрирует, как включить инструменты mutex wait, как включить связанных потребителей и запросить данные событий.

  1. Чтобы видеть доступные инструменты mutex wait, запросите Performance Schema setup_instruments. Все инструменты mutex отключены по умолчанию.

    mysql> SELECT * FROM performance_schema.setup_instruments
        ->          WHERE NAME LIKE '%wait/synch/mutex/innodb%';
    +---------------------------------------------------------+---------+-------+
    | NAME                                                    | ENABLED | TIMED |
    +---------------------------------------------------------+---------+-------+
    | wait/synch/mutex/innodb/commit_cond_mutex               | NO      | NO    |
    | wait/synch/mutex/innodb/innobase_share_mutex            | NO      | NO    |
    | wait/synch/mutex/innodb/autoinc_mutex                   | NO      | NO    |
    | wait/synch/mutex/innodb/autoinc_persisted_mutex         | NO      | NO    |
    | wait/synch/mutex/innodb/buf_pool_flush_state_mutex      | NO      | NO    |
    | wait/synch/mutex/innodb/buf_pool_LRU_list_mutex         | NO      | NO    |
    | wait/synch/mutex/innodb/buf_pool_free_list_mutex        | NO      | NO    |
    | wait/synch/mutex/innodb/buf_pool_zip_free_mutex         | NO      | NO    |
    | wait/synch/mutex/innodb/buf_pool_zip_hash_mutex         | NO      | NO    |
    | wait/synch/mutex/innodb/buf_pool_zip_mutex              | NO      | NO    |
    | wait/synch/mutex/innodb/cache_last_read_mutex           | NO      | NO    |
    | wait/synch/mutex/innodb/dict_foreign_err_mutex          | NO      | NO    |
    | wait/synch/mutex/innodb/dict_persist_dirty_tables_mutex | NO      | NO    |
    | wait/synch/mutex/innodb/dict_sys_mutex                  | NO      | NO    |
    | wait/synch/mutex/innodb/recalc_pool_mutex               | NO      | NO    |
    | wait/synch/mutex/innodb/fil_system_mutex                | NO      | NO    |
    | wait/synch/mutex/innodb/flush_list_mutex                | NO      | NO    |
    | wait/synch/mutex/innodb/fts_bg_threads_mutex            | NO      | NO    |
    | wait/synch/mutex/innodb/fts_delete_mutex                | NO      | NO    |
    | wait/synch/mutex/innodb/fts_optimize_mutex              | NO      | NO    |
    | wait/synch/mutex/innodb/fts_doc_id_mutex                | NO      | NO    |
    | wait/synch/mutex/innodb/log_flush_order_mutex           | NO      | NO    |
    | wait/synch/mutex/innodb/hash_table_mutex                | NO      | NO    |
    | wait/synch/mutex/innodb/ibuf_bitmap_mutex               | NO      | NO    |
    | wait/synch/mutex/innodb/ibuf_mutex                      | NO      | NO    |
    | wait/synch/mutex/innodb/ibuf_pessimistic_insert_mutex   | NO      | NO    |
    | wait/synch/mutex/innodb/log_sys_mutex                   | NO      | NO    |
    | wait/synch/mutex/innodb/log_sys_write_mutex             | NO      | NO    |
    | wait/synch/mutex/innodb/mutex_list_mutex                | NO      | NO    |
    | wait/synch/mutex/innodb/page_zip_stat_per_index_mutex   | NO      | NO    |
    | wait/synch/mutex/innodb/purge_sys_pq_mutex              | NO      | NO    |
    | wait/synch/mutex/innodb/recv_sys_mutex                  | NO      | NO    |
    | wait/synch/mutex/innodb/recv_writer_mutex               | NO      | NO    |
    | wait/synch/mutex/innodb/redo_rseg_mutex                 | NO      | NO    |
    | wait/synch/mutex/innodb/noredo_rseg_mutex               | NO      | NO    |
    | wait/synch/mutex/innodb/rw_lock_list_mutex              | NO      | NO    |
    | wait/synch/mutex/innodb/rw_lock_mutex                   | NO      | NO    |
    | wait/synch/mutex/innodb/srv_dict_tmpfile_mutex          | NO      | NO    |
    | wait/synch/mutex/innodb/srv_innodb_monitor_mutex        | NO      | NO    |
    | wait/synch/mutex/innodb/srv_misc_tmpfile_mutex          | NO      | NO    |
    | wait/synch/mutex/innodb/srv_monitor_file_mutex          | NO      | NO    |
    | wait/synch/mutex/innodb/buf_dblwr_mutex                 | NO      | NO    |
    | wait/synch/mutex/innodb/trx_undo_mutex                  | NO      | NO    |
    | wait/synch/mutex/innodb/trx_pool_mutex                  | NO      | NO    |
    | wait/synch/mutex/innodb/trx_pool_manager_mutex          | NO      | NO    |
    | wait/synch/mutex/innodb/srv_sys_mutex                   | NO      | NO    |
    | wait/synch/mutex/innodb/lock_mutex                      | NO      | NO    |
    | wait/synch/mutex/innodb/lock_wait_mutex                 | NO      | NO    |
    | wait/synch/mutex/innodb/trx_mutex                       | NO      | NO    |
    | wait/synch/mutex/innodb/srv_threads_mutex               | NO      | NO    |
    | wait/synch/mutex/innodb/rtr_active_mutex                | NO      | NO    |
    | wait/synch/mutex/innodb/rtr_match_mutex                 | NO      | NO    |
    | wait/synch/mutex/innodb/rtr_path_mutex                  | NO      | NO    |
    | wait/synch/mutex/innodb/rtr_ssn_mutex                   | NO      | NO    |
    | wait/synch/mutex/innodb/trx_sys_mutex                   | NO      | NO    |
    | wait/synch/mutex/innodb/zip_pad_mutex                   | NO      | NO    |
    | wait/synch/mutex/innodb/master_key_id_mutex             | NO      | NO    |
    +---------------------------------------------------------+---------+-------+
    
  2. Некоторые mutex создаются при запуске сервера и инструментованы только, если связанный инструмент также включен при запуске сервера. Чтобы гарантировать, что все mutex инструментованы и включены, добавляют следующее правило performance-schema-instrument к конфигурационному файлу MySQL:
    performance-schema-instrument='wait/synch/mutex/innodb/%=ON'
    

    Если Вы не требуете событий для всех mutexes, Вы можете отключить определенные инструменты, добавляя дополнительные правила performance-schema-instrument к Вашему конфигурационному файлу MySQL. Например, чтобы отключить инструменты событий, связанные с полнотекстовым поиском, добавляют следующее правило:

    performance-schema-instrument='wait/synch/mutex/innodb/fts%=OFF'
    

    Правила с более длинным префиксом, например, wait/synch/mutex/innodb/fts% имеют приоритет перед правилами с более короткими префиксами, например, wait/synch/mutex/innodb/%.

    После добавления правил performance-schema-instrument перезапустите сервер. Все InnoDB mutexes включены, за исключением связанных с полнотекстовым поиском. Чтобы проверить, запросите setup_instruments . Столбцы ENABLED и TIMED должны быть установлены в YES для инструментов, которым Вы включали.

    mysql> SELECT * FROM performance_schema.setup_instruments
        ->          WHERE NAME LIKE '%wait/synch/mutex/innodb%';
    +-------------------------------------------------------+---------+-------+
    | NAME                                                  | ENABLED | TIMED |
    +-------------------------------------------------------+---------+-------+
    | wait/synch/mutex/innodb/commit_cond_mutex             | YES     | YES   |
    | wait/synch/mutex/innodb/innobase_share_mutex          | YES     | YES   |
    | wait/synch/mutex/innodb/autoinc_mutex                 | YES     | YES   |
    ...
    | wait/synch/mutex/innodb/master_key_id_mutex           | YES     | YES   |
    +-------------------------------------------------------+---------+-------+
    49 rows in set (0.00 sec)
    
  3. Включите потребители событий, обновляя setup_consumers. Потребители событий отключены по умолчанию.
    mysql> UPDATE performance_schema.setup_consumers SET enabled = 'YES'
        ->        WHERE name like 'events_waits%';
    Query OK, 3 rows affected (0.00 sec)
    Rows matched: 3  Changed: 3  Warnings: 0
    

    Вы можете проверить, что потребители событий включены, запрашивая setup_consumers. Потребителей events_waits_current, events_waits_history и events_waits_history_long нужно включить.

    mysql> SELECT * FROM performance_schema.setup_consumers;
    +----------------------------------+---------+
    | NAME                             | ENABLED |
    +----------------------------------+---------+
    | events_stages_current            | NO      |
    | events_stages_history            | NO      |
    | events_stages_history_long       | NO      |
    | events_statements_current        | YES     |
    | events_statements_history        | YES     |
    | events_statements_history_long   | NO      |
    | events_transactions_current      | YES     |
    | events_transactions_history      | YES     |
    | events_transactions_history_long | NO      |
    | events_waits_current             | YES     |
    | events_waits_history             | YES     |
    | events_waits_history_long        | YES     |
    | global_instrumentation           | YES     |
    | thread_instrumentation           | YES     |
    | statements_digest                | YES     |
    +----------------------------------+---------+
    15 rows in set (0.00 sec)
  4. Как только инструменты и потребители включены, выполните рабочую нагрузку, которую Вы хотите контролировать. В этом примере клиент mysqlslap эмулирует загрузки, чтобы смоделировать рабочую нагрузку.
    shell> ./mysqlslap --auto-generate-sql --concurrency=100 --iterations=10
        ->             --number-of-queries=1000 --number-char-cols=6
                          --number-int-cols=6;
    
  5. Запросите данные событий. В этом примере данные событий запрошены от events_waits_summary_global_by_event_name, которая агрегирует данные в таблицах events_waits_current, events_waits_history и events_waits_history_long. Данные получены в итоге именем событий (EVENT_NAME), которое является названием инструмента, который произвел случай. Полученные в итоге данные включают:

    Следующий запрос возвращает инструментальное имя (EVENT_NAME), число событий (COUNT_STAR) и общее время событий для этого инструмента (SUM_TIMER_WAIT). Поскольку время рассчитано в пикосекундах по умолчанию, времена разделены на 1000000000, чтобы показать времена в миллисекундах. Данные представлены в порядке убывания числа полученных событий (COUNT_STAR). Вы можете корректировать ORDER BY, чтобы упорядочить данные общим количеством времени ожидания.

    mysql> SELECT EVENT_NAME, COUNT_STAR,
                     SUM_TIMER_WAIT/1000000000 SUM_TIMER_WAIT_MS
        ->        FROM performance_schema.events_waits_summary_global_by_event_name
        ->        WHERE SUM_TIMER_WAIT > 0 AND EVENT_NAME
        ->        LIKE 'wait/synch/mutex/innodb/%' ORDER BY COUNT_STAR DESC;
    +---------------------------------------------------------+------------+-------------------+
    | EVENT_NAME                                              | COUNT_STAR | SUM_TIMER_WAIT_MS |
    +---------------------------------------------------------+------------+-------------------+
    | wait/synch/mutex/innodb/trx_mutex                       | 201111     | 23.4719           |
    | wait/synch/mutex/innodb/fil_system_mutex                |  62244     |  9.6426           |
    | wait/synch/mutex/innodb/redo_rseg_mutex                 |  48238     |  3.1135           |
    | wait/synch/mutex/innodb/log_sys_mutex                   |  46113     |  2.0434           |
    | wait/synch/mutex/innodb/trx_sys_mutex                   |  35134     | 1068.1588         |
    | wait/synch/mutex/innodb/lock_mutex                      |  34872     | 1039.2589         |
    | wait/synch/mutex/innodb/log_sys_write_mutex             |  17805     | 1526.0490         |
    | wait/synch/mutex/innodb/dict_sys_mutex                  |  14912     | 1606.7348         |
    | wait/synch/mutex/innodb/trx_undo_mutex                  |  10634     |  1.1424           |
    | wait/synch/mutex/innodb/rw_lock_list_mutex              |   8538     |  0.1960           |
    | wait/synch/mutex/innodb/buf_pool_free_list_mutex        |   5961     |  0.6473           |
    | wait/synch/mutex/innodb/trx_pool_mutex                  |   4885     | 8821.7496         |
    | wait/synch/mutex/innodb/buf_pool_LRU_list_mutex         |   4364     |  0.2077           |
    | wait/synch/mutex/innodb/innobase_share_mutex            |   3212     |  0.2650           |
    | wait/synch/mutex/innodb/flush_list_mutex                |   3178     |  0.2349           |
    | wait/synch/mutex/innodb/trx_pool_manager_mutex          |   2495     |  0.1310           |
    | wait/synch/mutex/innodb/buf_pool_flush_state_mutex      |   1318     |  0.2161           |
    | wait/synch/mutex/innodb/log_flush_order_mutex           |   1250     |  0.0893           |
    | wait/synch/mutex/innodb/buf_dblwr_mutex                 | 951        |  0.0918           |
    | wait/synch/mutex/innodb/recalc_pool_mutex               | 670        |  0.0942           |
    | wait/synch/mutex/innodb/dict_persist_dirty_tables_mutex | 345        |  0.0414           |
    | wait/synch/mutex/innodb/lock_wait_mutex                 | 303        |  0.1565           |
    | wait/synch/mutex/innodb/autoinc_mutex                   | 196        |  0.0213           |
    | wait/synch/mutex/innodb/autoinc_persisted_mutex         | 196        |  0.0175           |
    | wait/synch/mutex/innodb/purge_sys_pq_mutex              | 117        |  0.0308           |
    | wait/synch/mutex/innodb/srv_sys_mutex                   | 94         |  0.0077           |
    | wait/synch/mutex/innodb/ibuf_mutex                      | 22         |  0.0086           |
    | wait/synch/mutex/innodb/recv_sys_mutex                  | 12         |  0.0008           |
    | wait/synch/mutex/innodb/srv_innodb_monitor_mutex        | 4          |        0.0009     |
    | wait/synch/mutex/innodb/recv_writer_mutex               |   1        |  0.0005           |
    +---------------------------------------------------------+------------+-------------------+
    

    Предыдущий набор результатов включает данные событий, произведенные во время процесса запуска. Чтобы исключить эти данные, Вы можете усечь events_waits_summary_global_by_event_name немедленно после запуска прежде, чем выполнить Вашу рабочую нагрузку. Однако, само усекание может произвести незначительное количество данных событий.

    mysql> TRUNCATE performance_schema.events_waits_summary_global_by_event_name;
    

16.16. Мониторы InnoDB

Мониторы InnoDB предоставляют информацию о внутреннем состоянии. Эта информация полезна для исполнительной настройки.

16.16.1. Типы мониторов InnoDB

Есть два типа мониторов InnoDB:

16.16.2. Включение мониторов InnoDB

Когда Вы включаете мониторы для периодического вывода, InnoDB пишет их вывод в вывод ошибок сервера mysqld (stderr). В этом случае, никакой вывод не посылают клиентам. Когда включены, мониторы InnoDB печатают данные о каждых 15 секундах. Вывод сервера обычно направляется к журналу ошибок (см. раздел 6.4.2). Эти данные полезны в исполнительной настройке. В Windows запустите сервер из командной строки в консоли с опцией --console , если Вы хотите направить вывод в окно, а не в журнал ошибок.

InnoDB посылает диагностический вывод в stderr или к файлам, а не к stdout или буферам памяти фиксированного размера, чтобы избежать потенциального переполнения. Как побочный эффект, вывод SHOW ENGINE INNODB STATUS написан в файл состояния в каталоге данных MySQL каждые пятнадцать секунд. Название файла innodb_status.pid, где pid ID процесса сервера. InnoDB удаляет этот файл при нормальном завершении работы. Если неправильные завершения работы произошли, экземпляры этих файлов состояния могут присутствовать и должны быть удалены вручную. Прежде, чем удалить их, Вы могли бы исследовать их, чтобы видеть, содержат ли они полезную информацию о причине неправильных завершений работы. Файл innodb_status.pid создается только, если включен параметр конфигурации innodb-status-file=1.

Мониторы InnoDB нужно включить только, когда Вы фактически хотите видеть информацию о мониторе, потому что вывод действительно приводит к некоторому снижению работоспособности. Кроме того, если Вы включаете вывод монитора, Ваш журнал ошибок может стать довольно большим, если Вы забываете отключить это позже.

Чтобы помочь с поиском неисправностей, InnoDB временно включает стандартный InnoDB Monitor определенных условиях. Для получения дополнительной информации см. раздел 16.20.

Вывод монитора InnoDB начинается с заголовка, содержащего метку времени и имя монитора. Например:

=====================================
2014-10-16 18:37:29 0x7fc2a95c1700 INNODB MONITOR OUTPUT
=====================================

Заголовок для стандартного InnoDB Monitor (INNODB MONITOR OUTPUT) также используется для монитора блокировки потому, что последний дает тот же самый вывод с добавлением дополнительной информации о блокировке.

Системные переменные innodb_status_output и innodb_status_output_locks используются, чтобы включить стандартный InnoDB Monitor и InnoDB Lock Monitor.

Чтобы включать и отключать мониторы InnoDB нужна привилегия PROCESS.

Включение стандартного монитора InnoDB

Включите стандартный InnoDB Monitor, устанавливая innodb_status_output в ON.

set GLOBAL innodb_status_output=ON;

Отключите стандартнычй InnoDB Monitor, устанавливая innodb_status_output в OFF.

Когда Вы закрываете сервер, innodb_status_output установлена в значение по умолчанию OFF.

Получение вывода стандартного InnoDB Monitor по требованию

Как альтернатива включению стандартного InnoDB Monitor для периодического вывода, Вы можете получить вывод стандартного InnoDB Monitor по требованию использованием SHOW ENGINE INNODB STATUS, который приносит вывод Вашей программе клиента. Если Вы используете mysql, вывод более читаем, если Вы заменяете обычный разделитель запроса, точку с запятой, на \G:

mysql> SHOW ENGINE INNODB STATUS\G

SHOW ENGINE INNODB STATUS также включает данные InnoDB Lock Monitor, если он включен.

Включение InnoDB Lock Monitor

Данные InnoDBLock Monitor напечатаны в вывод стандартного InnoDB Monitor. Оба монитора нужно включить.

Чтобы включить InnoDB Lock Monitor, установите innodb_status_output_locks в ON:

set GLOBAL innodb_status_output=ON;
set GLOBAL innodb_status_output_locks=ON;

Когда Вы закрываете сервер, переменные innodb_status_output и innodb_status_output_locks установлены в значение по умолчанию OFF.

Чтобы выключить InnoDB Lock Monitor, установите innodb_status_output_locks в OFF. Установите innodb_status_output в OFF, чтобы также отключить стандартный InnoDB Monitor.

Чтобы включить InnoDB Lock Monitor для SHOW ENGINE INNODB STATUS, Вы только включать обязаны innodb_status_output_locks.

16.16.3. Вывод InnoDB Standard Monitor и Lock Monitor

Lock Monitor то же самое, как Standard Monitor за исключением того, что он включает дополнительную информацию о блокировке. Включение любого монитора для периодического вывода включает тот же самый выходной поток, но поток включает дополнительную информацию, если включен Lock Monitor. Например, если Вы включаете Standard Monitor и Lock Monitor, это включает единственный выходной поток. Поток включает дополнительную информацию о блокировке, пока Вы не отключаете Lock Monitor.

Вывод Standard Monitor ограничен 1 МБ, когда произведен, используя SHOW ENGINE INNODB STATUS. Этот предел не применяется к выводу, написанному в вывод ошибок сервера.

Пример вывода Standard Monitor:

mysql> SHOW ENGINE INNODB STATUS\G
*************************** 1. row ***************************
  Type: InnoDB
  Name:
Status:
=====================================
2014-10-16 18:37:29 0x7fc2a95c1700 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 20 seconds
-----------------
BACKGROUND THREAD
-----------------
srv_master_thread loops: 38 srv_active, 0 srv_shutdown, 252 srv_idle
srv_master_thread log flush and writes: 290
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 119
OS WAIT ARRAY INFO: signal count 103
Mutex spin waits 0, rounds 0, OS waits 0
RW-shared spins 38, rounds 76, OS waits 38
RW-excl spins 2, rounds 9383715, OS waits 3
RW-sx spins 0, rounds 0, OS waits 0
Spin rounds per wait: 0.00 mutex, 2.00 RW-shared, 4691857.50 RW-excl,
0.00 RW-sx
------------------------
LATEST FOREIGN KEY ERROR
------------------------
2014-10-16 18:35:18 0x7fc2a95c1700 Transaction:
TRANSACTION 1814, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
4 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 3
MySQL thread id 2, OS thread handle 140474041767680, query id 74 localhost
root update
INSERT INTO child VALUES
(NULL, 1)
, (NULL, 2)
, (NULL, 3)
, (NULL, 4)
, (NULL, 5)
, (NULL, 6)
Foreign key constraint fails for table `mysql`.`child`:
,
  CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent`
  (`id`) ON DELETE CASCADE ON UPDATE CASCADE
Trying to add in child table, in index par_ind tuple:
DATA TUPLE: 2 fields;
 0: len 4; hex 80000003; asc ;;
 1: len 4; hex 80000003; asc ;;

But in parent table `mysql`.`parent`, in index PRIMARY,
the closest match we can find is record:
PHYSICAL RECORD: n_fields 3; compact format; info bits 0
 0: len 4; hex 80000004; asc ;;
 1: len 6; hex 00000000070a; asc   ;;
 2: len 7; hex aa0000011d0134; asc   4;;

------------------------
LATEST DETECTED DEADLOCK
------------------------
2014-10-16 18:36:30 0x7fc2a95c1700
*** (1) TRANSACTION:
TRANSACTION 1824, ACTIVE 9 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 3, OS thread handle 140474041501440, query id 80 localhost
root updating
DELETE FROM t WHERE i = 1
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 35 page no 3 n bits 72 index GEN_CLUST_INDEX of table
`mysql`.`t` trx id 1824 lock_mode X waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info
bits 0
 0: len 6; hex 000000000200; asc   ;;
 1: len 6; hex 00000000071f; asc   ;;
 2: len 7; hex b80000012b0110; asc +  ;;
 3: len 4; hex 80000001; asc ;;

*** (2) TRANSACTION:
TRANSACTION 1825, ACTIVE 29 sec starting index read
mysql tables in use 1, locked 1
4 lock struct(s), heap size 1136, 3 row lock(s)
MySQL thread id 2, OS thread handle 140474041767680, query id 81 localhost
root updating
DELETE FROM t WHERE i = 1
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 35 page no 3 n bits 72 index GEN_CLUST_INDEX of table
`mysql`.`t` trx id 1825 lock mode S
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info
bits 0
 0: len 8; hex 73757072656d756d; asc supremum;;

Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
 0: len 6; hex 000000000200; asc   ;;
 1: len 6; hex 00000000071f; asc   ;;
 2: len 7; hex b80000012b0110; asc +  ;;
 3: len 4; hex 80000001; asc ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 35 page no 3 n bits 72 index GEN_CLUST_INDEX of table
`mysql`.`t` trx id 1825 lock_mode X waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info
bits 0
 0: len 6; hex 000000000200; asc   ;;
 1: len 6; hex 00000000071f; asc   ;;
 2: len 7; hex b80000012b0110; asc +  ;;
 3: len 4; hex 80000001; asc ;;

*** WE ROLL BACK TRANSACTION (1)
------------
TRANSACTIONS
------------
Trx id counter 1950
Purge done for trx's n:o < 1933 undo n:o < 0 state: running but idle
History list length 23
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421949033065200, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421949033064280, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 1949, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
8 lock struct(s), heap size 1136, 1850 row lock(s), undo log entries 17415
MySQL thread id 4, OS thread handle 140474041235200, query id 176 localhost
root update
INSERT INTO `salaries` VALUES (55723,39746,'1997-02-25','1998-02-25'),
(55723,40758,'1998-02-25','1999-02-25'),(55723,44559,'1999-02-25','2000-02-25'),
(55723,44081,'2000-02-25','2001-02-24'),(55723,44112,'2001-02-24','2001-08-16'),
(55724,46461,'1996-12-06','1997-12-06'),(55724,48916,'1997-12-06','1998-12-06'),
(55724,51269,'1998-12-06','1999-12-06'),(55724,51932,'1999-12-06','2000-12-05'),
(55724,52617,'2000-12-05','2001-12-05'),(55724,56658,'2001-12-05','9999-01-01'),
(55725,40000,'1993-01-30','1994-01-30'),(55725,41472,'1994-01-30','1995-01-30'),
(55725,45293,'1995-01-30','1996-01-30'),(55725,473
--------
FILE I/O
--------
I/O thread 0 state: waiting for completed aio requests (insert buffer thread)
I/O thread 1 state: waiting for completed aio requests (log thread)
I/O thread 2 state: waiting for completed aio requests (read thread)
I/O thread 3 state: waiting for completed aio requests (read thread)
I/O thread 4 state: waiting for completed aio requests (read thread)
I/O thread 5 state: waiting for completed aio requests (read thread)
I/O thread 6 state: waiting for completed aio requests (write thread)
I/O thread 7 state: waiting for completed aio requests (write thread)
I/O thread 8 state: waiting for completed aio requests (write thread)
I/O thread 9 state: waiting for completed aio requests (write thread)
Pending normal aio reads: 0 [0, 0, 0, 0] , aio writes: 0 [0, 0, 0, 0] ,
 ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 0; buffer pool: 0
224 OS file reads, 5770 OS file writes, 803 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 264.84 writes/s, 23.05 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
 insert 0, delete mark 0, delete 0
discarded operations:
 insert 0, delete mark 0, delete 0
Hash table size 4425293, node heap has 444 buffer(s)
68015.25 hash searches/s, 106259.24 non-hash searches/s
---
LOG
---
Log sequence number 165913808
Log flushed up to   164814979
Pages flushed up to 141544038
Last checkpoint at  130503656
0 pending log flushes, 0 pending chkp writes
258 log i/o's done, 6.65 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 2198863872
Dictionary memory allocated 776332
Buffer pool size   131072
Free buffers   124908
Database pages 5720
Old database pages 2071
Modified db pages  910
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 4, not young 0
0.10 youngs/s, 0.00 non-youngs/s
Pages read 197, created 5523, written 5060
0.00 reads/s, 190.89 creates/s, 244.94 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not
0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read
ahead 0.00/s
LRU len: 5720, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
----------------------
INDIVIDUAL BUFFER POOL INFO
----------------------
---BUFFER POOL 0
Buffer pool size   65536
Free buffers   62412
Database pages 2899
Old database pages 1050
Modified db pages  449
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 3, not young 0
0.05 youngs/s, 0.00 non-youngs/s
Pages read 107, created 2792, written 2586
0.00 reads/s, 92.65 creates/s, 122.89 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead
0.00/s
LRU len: 2899, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
---BUFFER POOL 1
Buffer pool size   65536
Free buffers   62496
Database pages 2821
Old database pages 1021
Modified db pages  461
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 1, not young 0
0.05 youngs/s, 0.00 non-youngs/s
Pages read 90, created 2731, written 2474
0.00 reads/s, 98.25 creates/s, 122.04 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead
0.00/s
LRU len: 2821, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
--------------
ROW OPERATIONS
--------------
0 queries inside InnoDB, 0 queries in queue
0 read views open inside InnoDB
Process ID=35909, Main thread ID=140471692396288, state: sleeping
Number of rows inserted 1526363, updated 0, deleted 3, read 11
52671.72 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================

Разделы вывода Standard Monitor

Для описания каждой метрики, о которой сообщает Standard Monitor см. раздел Metrics в Oracle Enterprise Manager for MySQL Database User's Guide.

Status

Этот раздел показывает timestamp, имя монитора и число секунд, на котором основаны средние числа. Число секунд время, прошедшее между текущим временем и выводом монитора в прошлый раз.

BACKGROUND THREAD

Строки srv_master_thread показывают работу, сделанную основным фоновым потоком.

SEMAPHORES

Этот раздел сообщает о потоках, ждущих семафора, и статистику по тому, сколько раз потоки нуждались в mutex или rw-lock. Большое количество потоков, ждущих семафоров, может быть результатом дискового ввода/вывода или проблемами внутри InnoDB. Это может произойти из-за тяжелого параллелизма запросов или проблем в планировании потока операционной системы. Установка innodb_thread_concurrency меньше значения по умолчанию, могло бы помочь в таких ситуациях. Строка Spin rounds per wait показывает число спин-блокировки на ожидание OS mutex.

Метрики Mutex сообщает SHOW ENGINE INNODB MUTEX.

LATEST FOREIGN KEY ERROR

Этот раздел предоставляет информацию о новой ошибке ограничения внешнего ключа. Это не присутствует, если никакая такая ошибка не произошла. Содержание включает запрос, который потерпел неудачу, информацию об ограничении, которое потерпело неудачу и таблицах.

LATEST DETECTED DEADLOCK

Этот раздел предоставляет информацию о новом тупике. Это не присутствует, если никакой тупик не произошел. Показывает, какие транзакции вовлечены, запросы, которые каждая пыталась выполнить, блокировки, которые они имеют и нуждаются, и которая транзакция откатывается, чтобы найти выход из тупика. Режимы блокировки в этом разделе, объяснены в разделе 16.5.1.

TRANSACTIONS

Если этот раздел сообщает об ожидании блокировок, у Ваших приложений могло бы быть утверждение блокировки. Вывод может также помочь проследить причины операционных тупиков.

FILE I/O

Этот раздел предоставляет информацию о потоках, которые InnoDB использует, чтобы выполнить различные типы ввода/вывода. Первые из них посвящены общей обработке InnoDB. Содержание также выводит на экран информацию для операций ввода/вывода в ожидании и статистику для работы ввода/вывода.

Числом этих потоков управляют innodb_read_io_threads и innodb_write_io_threads. См. раздел 16.13.

INSERT BUFFER AND ADAPTIVE HASH INDEX

Этот раздел показывает состояние буфер вставки (также называемого буфером изменений) и адаптивный хеш индекса.

См. разделы 16.4.2 и 16.4.3.

LOG

Этот раздел выводит на экран информацию о журнале. Содержание включает текущий порядковый номер журнала, как давно журнал сброшен на диск и позицию, в которой InnoDB последний раз взял контрольную точку. См. раздел 16.11.3. Раздел также выводит на экран информацию об ожидании записи и исполнительную статистику записей.

BUFFER POOL AND MEMORY

Этот раздел дает Вам статистику по чтению и записи страниц. Вы можете вычислить от этих чисел, сколько операций ввода/вывода файла с данными Ваши запросы в настоящее время делают.

Для описаний статистики буферного пула см. раздел 16.6.3.9. Для дополнительной информации о работе буферного пула см. раздел 16.6.3.1.

ROW OPERATIONS

Этот раздел показывает то, что основной поток делает, включая число и исполнительный уровень для каждого типа работы строки.

16.17. Резервирование и восстановление InnoDB

Ключ к безопасному управлению базой данных это регулярные резервные копии. В зависимости от Вашего объема данных, числа серверов MySQL и рабочей нагрузки базы данных, Вы можете использовать эти методы, один или в комбинации: hot backup с MySQL Enterprise Backup; cold backup, копируя файлы в то время, как сервер MySQL закрыт, физическое резервное копирование для быстрой работы (специально для восстановления), логическое резервное копирование с mysqldump для малых объемов данных или чтобы сделать запись структуры объектов схемы.

Hot Backups

mysqlbackup, компонент MySQL Enterprise Backup, позволяет Вам поддерживать рабочий сервер MySQL, включая таблицы InnoDB и MyISAM, с минимальными проблемами, производя последовательный снимок базы данных. Когда mysqlbackup копирует таблицы InnoDB, чтения и записи таблиц InnoDB и MyISAM продолжаются. Во время копирования MyISAM чтения (но не записи) тех таблиц разрешены. Резервное копирование MySQL Enterprise может также создать сжатые резервные файлы и поддержать подмножества таблиц и баз данных. В соединении с двоичным журналом MySQL, пользователи могут выполнить восстановление момента времени. Резервное копирование MySQL Enterprise это часть подписки MySQL Enterprise. Для большего количества деталей см. раздел 27.2.

Cold Backups

Если Вы можете закрыть свой сервер MySQL, Вы можете сделать двоичное резервное копирование, которое состоит из всех файлов, используемых InnoDB. Используйте следующую процедуру:

  1. Сделайте медленное завершение работы сервера MySQL и удостоверьтесь, что он останавливается без ошибок.

  2. Скопируйте все файлы с данными InnoDB (ibdata и .ibd) в безопасное место.
  3. Скопируйте все файлы журналов InnoDB (ib_logfile).
  4. Скопируйте Ваш конфигурационный файл или файлы.

Альтернативные типы резервирования

В дополнение к созданию двоичных резервных копий как только что описано, регулярно делайте дампы своих таблиц с помощью mysqldump. Двоичный файл мог бы быть поврежден незаметно. Выведенные таблицы сохранены в текстовые файлы, которые удобочитаемы, так табличное повреждение становится легче найти. Кроме того, потому что формат более прост, шанс серьезного повреждения данных меньше. mysqldump также имеет опцию --single-transaction для того, чтобы сделать последовательный снимок без блокировки других клиентов. См. раздел 8.3.1.

Репликация работает с таблицами InnoDB , таким образом, Вы можете использовать способности репликации MySQL сохранить копию Вашей базы данных на серверах базы данных, требующих высокой доступности.

Выполнение восстановления

Чтобы вернуть базу данных к состоянию, в котором было сделано резервное копирование, Вы должны выполнить свой сервер MySQL с включенным двоичным журналированием прежде, чем взять резервное копирование. Чтобы достигнуть восстановления момента времени после восстановления резервного копирования, Вы можете применить изменения от двоичного журнала, которые произошли после того, как резервное копирование было сделано. См. раздел 8.5.

Чтобы оправиться от катастрофического отказа Вашего сервера MySQL, единственное требование это его перезапустить. InnoDB автоматически проверяет журналы и выполняет откат вперёд базы данных. InnoDB автоматически откатывает до прежнего уровня нейтральные транзакции, которые присутствовали во время катастрофического отказа. Во время восстановления mysqld выводит что-то вроде этого:

InnoDB: Database was not shut down normally.
InnoDB: Starting recovery from log files...
InnoDB: Starting log scan based on checkpoint at
InnoDB: log sequence number 0 13674004
InnoDB: Doing recovery: scanned up to log sequence number 0 13739520
InnoDB: Doing recovery: scanned up to log sequence number 0 13805056
InnoDB: Doing recovery: scanned up to log sequence number 0 13870592
InnoDB: Doing recovery: scanned up to log sequence number 0 13936128
...
InnoDB: Doing recovery: scanned up to log sequence number 0 20555264
InnoDB: Doing recovery: scanned up to log sequence number 0 20620800
InnoDB: Doing recovery: scanned up to log sequence number 0 20664692
InnoDB: 1 uncommitted transaction(s) which must be rolled back
InnoDB: Starting rollback of uncommitted transactions
InnoDB: Rolling back trx no 16745
InnoDB: Rolling back of trx no 16745 completed
InnoDB: Rollback of uncommitted transactions completed
InnoDB: Starting an apply batch of log records to the database...
InnoDB: Apply batch completed
InnoDB: Started
mysqld: ready for connections

Если Ваша база данных становится поврежденной, или дисковый отказ происходит, Вы должны выполнить восстановление, используя резервное копирование. В случае повреждения сначала найдите резервную копию, которая не повреждено. После восстановления основной копии сделайте восстановление момента времени после двоичных файлов системного журнала, используя mysqlbinlog и mysql , чтобы восстановить изменения, которые произошли после того, как резервное копирование было сделано.

В некоторых случаях повреждения базы данных достаточно только вывести, удалить и обновить одну или несколько поврежденных таблиц. Вы можете использовать CHECK TABLE, чтобы проверить, повреждена ли таблица, хотя CHECK TABLE не может обнаружить каждый возможный вид повреждения.

В некоторых случаях очевидное повреждение страницы базы данных происходит фактически из-за операционной системы, повреждающей ее собственный кэш файла, и данные на диске могут быть в норме. Лучше всего попытаться перезапустить Ваш компьютер. Это может устранить ошибки, которые, казалось, были повреждением страницы базы данных. Если MySQL все еще испытывает затруднения, запуска из-за проблемы последовательности InnoDB, см. раздел 16.20.2 для шагов, чтобы запустить случай в диагностическом режиме, где Вы можете вывести данные.

16.17.1. Процесс восстановления InnoDB

InnoDB восстановление катастрофического отказа состоит из нескольких шагов:

Шаги не зависят от журнала redo (кроме того, чтобы зарегистрировать запись) и выполнены параллельно с нормальной обработкой. Из них только отмена неполных транзакций является особенной. Буферное слияние вставки и чистка выполнены во время нормальной обработки.

После применения журнала redo InnoDB пытается принять соединения как можно раньше, уменьшить время простоя. Как часть восстановления катастрофического отказа, InnoDB откатывает любые транзакции, которые не были переданы или в статусе XA PREPARE, когда сервер отказал. Отмена выполнена фоновым потоком, выполненным параллельно с транзакциями от новых соединений. Пока работа отмены не завершена, новые соединения могут столкнуться с конфликтами блокировки с восстановленными транзакциями.

В большинстве ситуаций, даже если сервер MySQL был неожиданно уничтожен в середине тяжелой деятельности, процесс восстановления происходит автоматически, и никакое действие не требуется. Если отказ аппаратных средств или серьезная системная ошибка повредили данные InnoDB, MySQL мог бы отказаться запуститься. В этом случае см. раздел 16.20.2.

См. раздел 6.4.4.

16.17.2. Открытие табличного пространства во время восстановления катастрофического отказа

Если во время восстановления катастрофического отказа InnoDB находит журналы redo, записанные после последней контрольной точки, журналы должны быть применены к затронутым табличным пространствам. Процесс, который идентифицирует затронутые табличные пространства, упоминается как открытие табличного пространства.

Открытие табличного пространства идентифицирует затронутые табличные пространства, использующие на уровне файла записи MLOG_FILE_NAME журнала redo, которые написаны в журнал, когда страница табличного пространства изменена. MLOG_FILE_NAME содержит space_id табличного пространства и имя файла.

На запуске InnoDB открывает системное табличное пространство и журнал. Если в журнале redo есть записи, начиная с последней контрольной точки, затронутые файлы табличного пространства открыты и восстановлены, исходя из записей MLOG_FILE_NAME.

Записи MLOG_FILE_NAME внесены для всех постоянных типов табличного пространства, включая табличные пространства file-per-table, общее табличное пространство, системное табличное пространство и табличные пространства журнала отмены.

Если записи MLOG_FILE_NAME для системного табличного пространства не соответствуют конфигурации сервера, затрагивающей системные имена файла с данными табличного пространства, восстановление терпит неудачу с ошибкой прежде, чем журналы redo применены.

Во время восстановления журнал считан от последней контрольной точки до обнаруженного логического конца журнала. Если файлы табличного пространства, на которые ссылаются в просмотренной части журнала, отсутствуют, запуск не происходит.

16.18. InnoDB и репликация MySQL

Возможно использовать репликацию в случае, где механизм хранения на ведомом устройстве не тот же самый, как оригинальный механизм хранения на ведущем устройстве. Например, Вы можете копировать модификации таблиц InnoDB ведущего сервера в таблицы MyISAM на ведомом.

См. раздел 19.1.2.6 и 19.1.2.5.

Чтобы сделать новое ведомое устройство, не снимая ведущее устройство или существующее ведомое устройство, используйте MySQL Enterprise Backup.

Транзакции, которые терпят неудачу на ведущем устройстве, не затрагивают репликацию вообще. Репликация MySQL основана на двоичном журнале, где MySQL пишет запросы SQL, которые изменяют данные. Транзакция, которая терпит неудачу (например, из-за нарушения внешнего ключа или потому что она откатилась до прежнего уровня) не написана в двоичный журнал, таким образом, ее не посылают в ведомые устройства. См. раздел 14.3.1.

Репликация и CASCADE. Расположенные каскадом действий для InnoDB на ведущем устройстве копируются на ведомом устройстве только, если таблицы, совместно использующие отношение внешнего ключа, используют на ведущем и на ведомом устройствах. Это истина, используете ли Вы основанную на запросе или на строке репликацию. Предположите, что Вы запустили репликацию и затем составляете две таблицы на ведущем устройстве, используя следующий CREATE TABLE:

CREATE TABLE fc1 (i INT PRIMARY KEY, j INT) ENGINE = InnoDB;
CREATE TABLE fc2 (m INT PRIMARY KEY, n INT, FOREIGN KEY ni (n)
       REFERENCES fc1 (i) ON DELETE CASCADE) ENGINE = InnoDB;

Предположите, что ведомое устройство не имеет поддержки InnoDB. Если это верно, тогда таблицы на ведомом устройстве составлены, но они используют MyISAM, опция FOREIGN KEY проигнорирована. Теперь мы вставляем некоторые строки в таблицы на ведущем устройстве:

master> INSERT INTO fc1 VALUES (1, 1), (2, 2);
Query OK, 2 rows affected (0.09 sec)
Records: 2  Duplicates: 0  Warnings: 0

master> INSERT INTO fc2 VALUES (1, 1), (2, 2), (3, 1);
Query OK, 3 rows affected (0.19 sec)
Records: 3  Duplicates: 0  Warnings: 0

В этот момент на ведущем и ведомом устройствах таблица fc1 содержит 2 строки, а fc2 3:

master> SELECT * FROM fc1;
+---+---+
| i | j |
+---+---+
| 1 | 1 |
| 2 | 2 |
+---+---+
2 rows in set (0.00 sec)

master> SELECT * FROM fc2;
+---+---+
| m | n |
+---+---+
| 1 | 1 |
| 2 | 2 |
| 3 | 1 |
+---+---+
3 rows in set (0.00 sec)

slave> SELECT * FROM fc1;
+---+---+
| i | j |
+---+---+
| 1 | 1 |
| 2 | 2 |
+---+---+
2 rows in set (0.00 sec)

slave> SELECT * FROM fc2;
+---+---+
| m | n |
+---+---+
| 1 | 1 |
| 2 | 2 |
| 3 | 1 |
+---+---+
3 rows in set (0.00 sec)

Теперь предположите, что Вы выполняете следующий запрос DELETE на ведущем:

master> DELETE FROM fc1 WHERE i=1;
Query OK, 1 row affected (0.09 sec)

Из-за каскада таблица fc2 на ведущем устройстве теперь содержит только 1 строку:

master> SELECT * FROM fc2;
+---+---+
| m | n |
+---+---+
| 2 | 2 |
+---+---+
1 row in set (0.00 sec)

Однако, каскад не размножается на ведомом устройстве потому, что на ведомом устройстве DELETE для fc1 не удаляет строки из fc2. Копия ведомого устройства fc2 все еще содержит все строки, которые были первоначально вставлены:

slave> SELECT * FROM fc2;
+---+---+
| m | n |
+---+---+
| 1 | 1 |
| 3 | 1 |
| 2 | 2 |
+---+---+
3 rows in set (0.00 sec)

Это различие следствие того, что расположеные каскадом удаления обработаны внутренне InnoDB, что означает, что ни одно из изменений не зарегистрировано.

16.19. Плагин InnoDB memcached

Плагин InnoDB memcached (daemon_memcached) обеспечивает интегрированный демон memcached, который автоматически хранит и получает данные от InnoDB таблицы, превращая сервер MySQL в быстрое хранилище значений ключа. Вместо того, чтобы формулировать запросы в SQL, Вы можете использовать простые операции get, set и incr, которые избегают работы, связанной с парсингом SQL и построения плана оптимизации запроса. Вы можете также получить доступ к тем же самым таблицам InnoDB через SQL для удобства сложных запросов.

Этот NoSQL-стиль интерфейса использует memcached API, чтобы ускорить операции базы данных, позволяя InnoDB кэширование памяти дескриптора, используя буферный пул. Данные, изменные посредством команд memcached, таких как add, set и incr, сохранены на диск в таблицы InnoDB. Комбинация простоты memcached с надежностью и последовательностью InnoDB предоставляют пользователям лучший вариант, как объяснено в разделе 16.19.1. Для краткого архитектурного обзора см. раздел 16.19.2.

16.19.1. Выгода от плагина InnoDB memcached

Этот раздел способствует пониманию плагина daemon_memcached. Комбинация InnoDB таблиц и memcached предлагает значительные преимущества.

16.19.2. Архитектура InnoDB memcached

Плагин InnoDB memcached осуществляет memcached как плагин MySQL, к которому получает доступ механизм хранения InnoDB, обходя MySQL-уровень SQL.

Следующая диаграмма иллюстрирует данные о доступе приложения через плагин daemon_memcached по сравнению с SQL.

Architecture Diagram for MySQL Server with Integrated memcached Server

Особенности плагина daemon_memcached:

Разница между InnoDB memcached и обычным memcached

Вы можете уже быть знакомы с использованием memcached с MySQL, см. раздел 18.2. Этот раздел описывает как особенности интегрированного плагина InnoDB memcached отличаются от традиционного memcached.

16.19.3. Установка плагина InnoDB memcached

Этот раздел описывает, как настроить daemon_memcached на сервере MySQL. Поскольку memcached плотно объединен с сервером MySQL, чтобы избежать сетевого трафика и минимизировать время ожидания, Вы выполняете этот процесс на каждом сервере MySQL, который использует эту функцию.

Перед установкой плагина, изучите раздел 16.19.5, чтобы понять меры безопасности и предотвратить несанкционированный доступ.

Предпосылки

Установка и настройка плагина InnoDB memcached

  1. Сконфигурируйте плагин daemon_memcached таким образом, что это может взаимодействовать с таблицами InnoDB. Запустите скрипт innodb_memcached_config.sql в MYSQL_HOME/share. Скрипт установит базу жанных innodb_memcache с тремя необходимыми таблицами (cache_policies, config_options и containers). Это также устанавливает типовую таблицу demo_test в базу данных test.

    mysql> source MYSQL_HOME/share/innodb_memcached_config.sql
    

    Запуск скрипта innodb_memcached_config.sql это одноразовая работа. Таблицы остаются в указанном месте, если Вы позже удаляете и повторно устанавливаете плагин daemon_memcached.

    mysql> USE innodb_memcache;
    mysql> SHOW TABLES;
    +---------------------------+
    | Tables_in_innodb_memcache |
    +---------------------------+
    | cache_policies            |
    | config_options            |
    | containers                |
    +---------------------------+
    mysql> USE test;
    mysql> SHOW TABLES;
    +----------------+
    | Tables_in_test |
    +----------------+
    | demo_test      |
    +----------------+
    

    Из этих таблиц innodb_memcache.containers является самой важной. Записи в containers обеспечивают отображение на столбцы таблицы InnoDB. Каждая таблица InnoDB, используемая с daemon_memcached, требует записи в containers.

    Скрипт innodb_memcached_config.sql вставляет единственную запись в containers, которая обеспечивает отображение для таблицы demo_test. Это также вставляет единственную строку данных в demo_test. Эти данные позволяют Вам немедленно проверить установку после того, как она завершена.

    mysql> SELECT * FROM innodb_memcache.containers\G
    *************************** 1. row ***************************
    name: aaa
       db_schema: test
    db_table: demo_test
     key_columns: c1
     value_columns: c2
       flags: c3
      cas_column: c4
    expire_time_column: c5
    unique_idx_name_on_key: PRIMARY
    
    mysql> SELECT * FROM test.demo_test;
    +----+------------------+------+------+------+
    | c1 | c2               | c3   | c4   | c5   |
    +----+------------------+------+------+------+
    | AA | HELLO, HELLO     |   8  |  0   | 0    |
    +----+------------------+------+------+------+
    

    Подробнее про таблицы innodb_memcache и demo_test см. раздел 16.19.8.

  2. Активируйте плагин daemon_memcached командой INSTALL PLUGIN:
    mysql> INSTALL PLUGIN daemon_memcached soname "libmemcached.so";
    

    Как только плагин установлен, он автоматически активирован каждый раз, когда сервер MySQL перезапущен.

Проверка InnoDB и memcached

Чтобы проверить плагин daemon_memcached, используйте сеанс telnet, чтобы выпустить команды memcached. По умолчанию memcached слушает порт 11211.

  1. Получите данные от таблицы test.demo_test. Единственная строка данных в demo_test имеет ключ AA.

    telnet localhost 11211
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    get AA
    VALUE AA 8 12
    HELLO, HELLO
    END
    
  2. Вставьте данные, используя команду set.
    set BB 10 0 16
    GOODBYE, GOODBYE
    STORED
    

    здесь:

  3. Проверьте, что вставленные данные хранятся в MySQL, соединяясь с сервером MySQL и запрашивая таблицу test.demo_test.

    mysql> SELECT * FROM test.demo_test;
    +----+------------------+----+----+----+
    | c1 | c2               | c3 | c4 | c5 |
    +----+------------------+----+----+----+
    | AA | HELLO, HELLO     | 8  | 0  | 0  |
    | BB | GOODBYE, GOODBYE | 10 | 1  | 0  |
    +----+------------------+----+----+----+
    
  4. Возвратитесь к сеансу telnet и получите данные, которые Вы вставили раньше с ключом BB.
    get BB
    VALUE BB 10 16
    GOODBYE, GOODBYE
    END
    quit
    

Если Вы закроете сервер MySQL, который также отключает интегрированный сервер memcached, то дальнейшие попытки получить доступ к memcached потерпят неудачу с ошибкой соединения. Обычно данные memcached также исчезают, и Вы потребовали бы, чтобы логика приложения загрузила данные назад в память, когда memcached перезапущен. Однако, плагин memcached автоматизирует этот процесс для Вас.

Когда Вы перезапускаете MySQL, операции get возвращают пары ключа/значения, которые Вы сохранили ранее в сессии memcached. Когда ключ требуют, и связанное значение уже не находится в кэш-памяти, значение автоматически запрошено от MySQL-таблицы test.demo_test.

Составление нового таблицы и отображение столбца

Этот пример показывает как установить таблицу с плагином daemon_memcached.

  1. Создайте таблицу InnoDB. У таблицы должен быть ключевой столбец с уникальным индексом. Ключевой столбец таблицы city_id определен как первичный ключ. Таблица должна также включать столбцы для значений flags, cas и expiry. Могут быть один или более столбцов значений. Таблица city имеет три столбца значений (name, state, country).

    Нет никакого особого требования относительно имен столбцов, поскольку допустимое отображение добавлено к таблице innodb_memcache.containers.

    mysql> CREATE TABLE city (city_id VARCHAR(32), name VARCHAR(1024),
        ->        state VARCHAR(1024), country VARCHAR(1024),
        ->        flags INT, cas BIGINT UNSIGNED, expiry INT,
        ->        primary key(city_id)) ENGINE=InnoDB;
    
  2. Добавьте запись в innodb_memcache.containers, чтобы плагин daemon_memcached знал, как получить доступ к таблице InnoDB. Запись должна удовлетворить определению innodb_memcache.containers. Для описания каждого поля см. раздел 16.19.8.
    mysql> DESCRIBE innodb_memcache.containers;
    +------------------------+--------------+------+-----+---------+-------+
    | Field                  | Type         | Null | Key | Default | Extra |
    +------------------------+--------------+------+-----+---------+-------+
    | name                   | varchar(50)  | NO   | PRI | NULL    |       |
    | db_schema              | varchar(250) | NO   |     | NULL    |       |
    | db_table               | varchar(250) | NO   |     | NULL    |       |
    | key_columns            | varchar(250) | NO   |     | NULL    |       |
    | value_columns          | varchar(250) | YES  |     | NULL    |       |
    | flags                  | varchar(250) | NO   |     | 0       |       |
    | cas_column             | varchar(250) | YES  |     | NULL    |       |
    | expire_time_column     | varchar(250) | YES  |     | NULL    |       |
    | unique_idx_name_on_key | varchar(250) | NO   |     | NULL    |       |
    +------------------------+--------------+------+-----+---------+-------+
    

    Запись в таблице innodb_memcache.containers для таблицы определена как:

    mysql> INSERT INTO `innodb_memcache`.`containers` (
        ->    `name`, `db_schema`, `db_table`, `key_columns`, `value_columns`,
        ->    `flags`, `cas_column`, `expire_time_column`, `unique_idx_name_on_key`)
        -> VALUES ('default', 'test', 'city', 'city_id', 'name|state|country',
        ->    'flags','cas','expiry','PRIMARY');
    
  3. После обновления innodb_memcache.containers перезапустите daemon_memcache, чтобы применить изменения.

    mysql> UNINSTALL PLUGIN daemon_memcached;
    mysql> INSTALL PLUGIN daemon_memcached soname "libmemcached.so";
    
  4. Используя telnet, вставьте данные в таблицу city, используя команду set.
    telnet localhost 11211
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    set B 0 0 22
    BANGALORE|BANGALORE|IN
    STORED
    
  5. Используя MySQL, запросите test.city, чтобы проверить, что данные, которые Вы вставили, были сохранены.
    mysql> SELECT * FROM test.city;
    +---------+-----------+-----------+---------+-------+-----+--------+
    | city_id | name      | state     | country | flags | cas | expiry |
    +---------+-----------+-----------+---------+-------+-----+--------+
    | B       | BANGALORE | BANGALORE | IN      | 0     | 3   |  0     |
    +---------+-----------+-----------+---------+-------+-----+--------+
    
  6. Используя MySQL, вставьте дополнительные данные в test.city.
    mysql> INSERT INTO city VALUES ('C','CHENNAI','TAMIL NADU','IN', 0, 0 ,0);
    mysql> INSERT INTO city VALUES ('D','DELHI','DELHI','IN', 0, 0, 0);
    mysql> INSERT INTO city VALUES ('H','HYDERABAD','TELANGANA','IN', 0, 0, 0);
    mysql> INSERT INTO city VALUES ('M','MUMBAI','MAHARASHTRA','IN', 0, 0, 0);
    

    Рекомендуется, чтобы Вы определили значение 0 для полей flags, cas_column и expire_time_column, если они не использованы.

  7. Используя telnet, выполните команду memcached get, чтобы получить данные, которые Вы вставили с использованием MySQL.

    get H
    VALUE H 0 22
    HYDERABAD|TELANGANA|IN
    END
    

Настройка плагина InnoDB memcached

Традиционные параметры конфигурации memcached могут быть определены в конфигурационном файле MySQL или стартовой строке mysqld, закодированной в параметре daemon_memcached_option. Параметры конфигурации memcached вступают в силу, когда плагин загружен, что происходит каждый раз, когда сервер MySQL запущен.

Например, чтобы заставить memcached слушать на порту 11222 вместо порта значения по умолчанию 11211, определите -p11222 как параметр daemon_memcached_option:

mysqld .... --daemon_memcached_option="-p11222"

Другие опции memcached могут быть закодированы в daemon_memcached_option. Например, Вы можете определить опции, чтобы уменьшить максимальное количество одновременных соединений, изменить максимальный размер памяти для пары ключа/значения или включить отладочные сообщения для журнала ошибок.

Есть также параметры конфигурации, определенные для плагина daemon_memcached:

По умолчанию, Вы не должны изменить daemon_memcached_engine_lib_name или daemon_memcached_engine_lib_path. Вы могли бы сконфигурировать эти опции, если, например, Вы хотите использовать иной механизм хранения для memcached (например, NDB memcached).

Параметры плагина daemon_memcached могут быть определены в конфигурационном файле MySQL или в строке запуска mysqld. Они вступают в силу, когда Вы загружаете daemon_memcached.

Производя изменения в настройке daemon_memcached, перезагрузите плагин, чтобы применить изменения. Чтобы сделать так, сделайте следующие запросы:

mysql> UNINSTALL PLUGIN daemon_memcached;
mysql> INSTALL PLUGIN daemon_memcached soname "libmemcached.so";

Настройки конфигурации, требуемые таблицы и данные сохранены, когда плагин перезапущен.

Подробности о плагинах см. в разделе 6.6.2.

16.19.4. Поддержка запроса диапазона и множественные memcached get

С MySQL 8.0.0 плагин daemon_memcached поддерживает множественные операции get (забирающие многократные пары ключа/значения в единственном запросе memcached ) и запросах диапазона.

Множественные memcached get

Способность забрать многократные пары ключа/значения в единственном запросе memcached улучшает работу чтения, уменьшая коммуникационный трафик между клиентом и сервером. Для InnoDB это означает меньше транзакций и операций открытия таблицы.

Следующий пример демонстрирует это. Пример использует таблицу test.city, описанную выше.

mysql> USE test;
mysql> SELECT * FROM test.city;
+---------+-----------+-------------+---------+-------+-----+--------+
| city_id | name      | state       | country | flags | cas | expiry |
+---------+-----------+-------------+---------+-------+-----+--------+
| B       | BANGALORE | BANGALORE   | IN      | 0     | 1   |  0     |
| C       | CHENNAI   | TAMIL NADU  | IN      | 0     | 0   |  0     |
| D       | DELHI     | DELHI       | IN      | 0     | 0   |  0     |
| H       | HYDERABAD | TELANGANA   | IN      | 0     | 0   |  0     |
| M       | MUMBAI    | MAHARASHTRA | IN      | 0     | 0   |  0     |
+---------+-----------+-------------+---------+-------+-----+--------+

Выполните команду get, чтобы получить все значения от таблицы city. Результаты возвращены в последовательности пар ключа/значения.

telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
get B C D H M
VALUE B 0 22
BANGALORE|BANGALORE|IN
VALUE C 0 21
CHENNAI|TAMIL NADU|IN
VALUE D 0 14
DELHI|DELHI|IN
VALUE H 0 22
HYDERABAD|TELANGANA|IN
VALUE M 0 21
MUMBAI|MAHARASHTRA|IN
END

Получая многократные значения в одной команде get, Вы можете переключить таблицы (с использованием формата @@containers.name), чтобы получить значение для первого ключа, но Вы не можете переключить таблицы для последующих ключей. Например, табличный переключатель в этом примере допустим:

get @@aaa.AA BB
VALUE @@aaa.AA 8 12
HELLO, HELLO
VALUE BB 10 16
GOODBYE, GOODBYE
END

Попытка переключить таблицы снова в том же самом запросе get, чтобы получить значение ключа от другой таблицы не поддержана.

Запросы диапазона

Для запросов диапазона плагин daemon_memcached поддерживает следующие операторы сравнения: <, >, <=, >=. Оператор должен предваряться символом @. Когда запрос диапазона находит многократные соответствия пар ключа/значения, результаты возвращены в последовательности пар ключа/значения.

Следующие примеры демонстрируют поддержку запроса диапазона. Примеры используют описанную ранее таблицу test.city.

mysql> SELECT * FROM test.city;
+---------+-----------+-------------+---------+-------+-----+--------+
| city_id | name      | state       | country | flags | cas | expiry |
+---------+-----------+-------------+---------+-------+-----+--------+
| B       | BANGALORE | BANGALORE   | IN      | 0     | 1   |  0     |
| C       | CHENNAI   | TAMIL NADU  | IN      | 0     | 0   |  0     |
| D       | DELHI     | DELHI       | IN      | 0     | 0   |  0     |
| H       | HYDERABAD | TELANGANA   | IN      | 0     | 0   |  0     |
| M       | MUMBAI    | MAHARASHTRA | IN      | 0     | 0   |  0     |
+---------+-----------+-------------+---------+-------+-----+--------+

Откройте сессию telnet:

telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.

Получить все значения, больше B:

get @>B
VALUE C 0 21
CHENNAI|TAMIL NADU|IN
VALUE D 0 14
DELHI|DELHI|IN
VALUE H 0 22
HYDERABAD|TELANGANA|IN
VALUE M 0 21
MUMBAI|MAHARASHTRA|IN
END

Получить все значения меньше M:

get @<M
VALUE B 0 22
BANGALORE|BANGALORE|IN
VALUE C 0 21
CHENNAI|TAMIL NADU|IN
VALUE D 0 14
DELHI|DELHI|IN
VALUE H 0 22
HYDERABAD|TELANGANA|IN
END

Получить все значения меньше чем и включая M:

get @<=M
VALUE B 0 22
BANGALORE|BANGALORE|IN
VALUE C 0 21
CHENNAI|TAMIL NADU|IN
VALUE D 0 14
DELHI|DELHI|IN
VALUE H 0 22
HYDERABAD|TELANGANA|IN
VALUE M 0 21
MUMBAI|MAHARASHTRA|IN

Получить значения, больше чем B но меньше M:

get @>B@<M
VALUE C 0 21
CHENNAI|TAMIL NADU|IN
VALUE D 0 14
DELHI|DELHI|IN
VALUE H 0 22
HYDERABAD|TELANGANA|IN
END

Максимум двух операторов сравнения может быть разобран, один являющийся любым 'меньше чем' (@<) или 'меньше чем или равный' (@<=), другой являющийся любым 'больше чем' (@>) или или 'больше чем или равный' (@>=). Любые дополнительные операторы, как предполагается, являются частью ключа. Например, если выполняете get с тремя операторами, третий оператор (@>C) обработан как часть ключа, и get будет искать значения, меньшие чем M, но больше B@>C.

get @<M@>B@>C
VALUE C 0 21
CHENNAI|TAMIL NADU|IN
VALUE D 0 14
DELHI|DELHI|IN
VALUE H 0 22
HYDERABAD|TELANGANA|IN

16.19.5. Соображения безопасности для InnoDB memcached

Консультируйтесь с этим разделом прежде, чем развернуть daemon_memcached на производственном сервере или даже на тестовом сервере, если MySQL содержит уязвимые данные.

Поскольку memcached не использует механизм аутентификации по умолчанию, и дополнительная аутентификация SASL не столь же сильна, как традиционная безопасность системы управления базами данных, сохраните только несекретные данные в случае MySQL, который использует daemon_memcached, и отгородите любые серверы, которые используют эту конфигурацию, от потенциальных злоумышленников. Не позволяйте доступ к этим серверам из Интернета, позвольте доступ только изнутри интранет-сети, идеально от подсети, членство в которой Вы можете ограничить.

Защита паролем memcached с SASL

Поддержка SASL обеспечивает способность защитить Вашу базу данных MySQL от незаверенного доступа к memcached. Этот раздел объясняет, как включить SASL с daemon_memcached. Шаги почти идентичны включению SASL для традиционного memcached.

SASL это стандарт для того, чтобы добавить поддержку аутентификации основанным на соединении протоколам. memcached добавил поддержку SASL в версии 1.4.3.

Аутентификация SASL поддержана только с протоколом двоичной синхронной передачи данных.

Клиенты memcached в состоянии только получить доступ к таблицам, которые зарегистрированы в innodb_memcache.containers. Даже при том, что DBA может установить ограничения доступа для таких таблиц, доступом через memcached нельзя управлять. Поэтому поддержка SASL оказана, чтобы управлять доступом к таблицам, связанным с daemon_memcached.

Этот раздел показхывает, как создать, включить и проверить SASL daemon_memcached.

Создание и включение SASL в InnoDB memcached

По умолчанию SASL daemon_memcached не включен в пакеты выпуска MySQL. SASL-daemon_memcached требует сборки memcached с библиотеками SASL. Чтобы включить поддержку SASL, загрузите исходный текст MySQL и пересоздайте плагин daemon_memcached после загрузки библиотек SASL:

  1. Установите SASL и служебные библиотеки. Например, на Ubuntu используйте apt-get:

    sudo apt-get -f install libsasl2-2 sasl2-bin libsasl2-2 libsasl2-dev libsasl2-modules
    
  2. Соберите совместно используемые библиотеки с SASL, добавляя ENABLE_MEMCACHED_SASL=1 к опциям cmake. memcached также оказывает simple cleartext password support, которая облегчает тестирование. Чтобы включить простую поддержку пароля открытого текста, определите ENABLE_MEMCACHED_SASL_PWDB=1 в cmake.

    В резюме, добавьте следующие три опции cmake:

    cmake ... -DWITH_INNODB_MEMCACHED=1 \
              -DENABLE_MEMCACHED_SASL=1 \
              -DENABLE_MEMCACHED_SASL_PWDB=1
    
  3. Установите daemon_memcached согласно разделу 16.19.3.
  4. Сконфигурируйте файл пароля и имя пользователя. Этот пример использует поддержку memcached simple cleartext password.

    1. В файле создайте пользователя testname и определите пароль как testpasswd:

      echo "testname:testpasswd:::::::" >/home/jy/memcached-sasl-db
      
    2. Сконфигурируйте переменную MEMCACHED_SASL_PWDB, чтобы сообщить memcached имя файла пользователей и паролей:
      export MEMCACHED_SASL_PWDB=/home/jy/memcached-sasl-db
      
    3. Сообщите memcached, что используется пароль открытого текста:
      echo "mech_list: plain" > /home/jy/work2/msasl/clients/memcached.conf
      export SASL_CONF_PATH=/home/jy/work2/msasl/clients
      
  5. Включите SASL, перезапуская сервер MySQL с опцией memcached -S, закодированной в параметре конфигурации daemon_memcached_option:

    mysqld ... --daemon_memcached_option="-S"
    
  6. Чтобы проверить установку, используйте SASL-клиент, например, SASL-enabled libmemcached.
    memcp --servers=localhost:11211 --binary  --username=testname
          --password=testpasswd myfile.txt
    
    memcat --servers=localhost:11211 --binary --username=testname
           --password=testpasswd myfile.txt
    

    Если Вы определяете неправильное имя пользователя или пароль, работа отклонена с ошибкой memcache error AUTHENTICATION FAILURE. В этом случае исследуйте пароль открытого текста в файле memcached-sasl-db, чтобы проверить, что он правилен.

Есть другие методы, чтобы проверить аутентификацию SASL с memcached, но метод, описанный выше, является самым прямым.

16.19.6. Написание приложений для плагина InnoDB memcached

Написание приложений для плагина InnoDB memcached вовлекает определенную степень приспосабливания существующего кода, который использует MySQL или memcached API.

Следующие разделы исследуют эти пункты более подробно.

16.19.6.1. Приспосабливание существующей схемы MySQL для InnoDB memcached

Полагайте, что эти аспекты memcached, адаптируя существующую схему MySQL или приложение используют плагин daemon_memcached:

Пример 16.22. Использование Вашей собственной таблицы с InnoDB memcached

Этот пример показывает, как использовать Вашу собственную таблицу с типовым приложением на Python, которое использует memcached.

Пример предполагает что плагин daemon_memcached уставновлен в соответствии с разделом 16.19.3 . Это также предполагает, что Ваша система сконфигурирована, чтобы выполнить скрипт модуля python-memcache.

  1. Создайте таблицу multicol, которая хранит информацию страны включая население, область и данные о водительской стороне ('R' для правой и 'L' для левой).

    mysql> USE test;
    mysql> CREATE TABLE `multicol` (
        ->    `country` varchar(128) NOT NULL DEFAULT '',
        ->    `population` varchar(10) DEFAULT NULL,
        ->    `area_sq_km` varchar(9) DEFAULT NULL,
        ->    `drive_side` varchar(1) DEFAULT NULL,
        ->    `c3` int(11) DEFAULT NULL,
        ->    `c4` bigint(20) unsigned DEFAULT NULL,
        ->    `c5` int(11) DEFAULT NULL,
        ->    PRIMARY KEY (`country`)) ENGINE=InnoDB
        ->    DEFAULT CHARSET=latin1;
    
  2. Вставьте запись в innodb_memcache.containers так, чтобы плагин daemon_memcached мог получить доступ к multicol .
    mysql> INSERT INTO innodb_memcache.containers
        ->   (name,db_schema,db_table,key_columns,value_columns,flags,
        ->    cas_column,expire_time_column,unique_idx_name_on_key)
        -> VALUES
        ->   ('bbb','test','multicol','country',
        ->    'population,area_sq_km,drive_side','c3','c4','c5','PRIMARY');
    mysql> COMMIT;
    
  3. Скопируйте типовое приложение Питона в файл. В этом примере типовой скрипт скопирован к файлу multicol.py.

    Типовое приложение Питона вставляет данные в таблицу multicol и получает данные для всех ключей, демонстрируя, как получить доступ к таблице InnoDB через плагин daemon_memcached.

    import sys, os
    import memcache
    
    def connect_to_memcached():
      memc = memcache.Client(['127.0.0.1:11211'], debug=0);
      print "Connected to memcached."
      return memc
    
    def banner(message):
      print
      print "=" * len(message)
      print message
      print "=" * len(message)
    
    country_data = [("Canada","34820000","9984670","R"),
       ("USA","314242000","9826675","R"),
       ("Ireland","6399152","84421","L"),
       ("UK","62262000","243610","L"),
       ("Mexico","113910608","1972550","R"),
       ("Denmark","5543453","43094","R"),
       ("Norway","5002942","385252","R"),
       ("UAE","8264070","83600","R"),
       ("India","1210193422","3287263","L"),
       ("China","1347350000","9640821","R"),]
    
    def switch_table(memc,table):
      key = "@@" + table
      print "Switching default table to '" + table + "' by issuing GET for '" +
            key + "'."
      result = memc.get(key)
    
    def insert_country_data(memc):
      banner("Inserting initial data via memcached interface")
      for item in country_data:
    country = item[0]
    population = item[1]
    area = item[2]
    drive_side = item[3]
    
    key = country
    value = "|".join([population,area,drive_side])
    print "Key = " + key
    print "Value = " + value
    
    if memc.add(key,value):
       print "Added new key, value pair."
    else:
      print "Updating value for existing key."
      memc.set(key,value)
    
    def query_country_data(memc):
      banner("Retrieving data for all keys (country names)")
      for item in country_data:
    key = item[0]
    result = memc.get(key)
    print "Here is the result retrieved from the database for key " + key + ":"
    print result(m_population, m_area, m_drive_side) = result.split("|")
    print "Unpacked population value: " + m_population
    print "Unpacked area value  : " + m_area
    print "Unpacked drive side value: " + m_drive_side
    
    if __name__ == '__main__':
       memc = connect_to_memcached()
    switch_table(memc,"bbb")
    insert_country_data(memc)
    query_country_data(memc)
    sys.exit(0)
    

    Типовые указания по применению Питона:

  4. Запустите типовое приложение Питона.

    shell> python multicol.py
    

    В случае успеха пример приложения возвращает этот вывод:

    Connected to memcached.
    Switching default table to 'bbb' by issuing GET for '@@bbb'.
    ==============================================
    Inserting initial data via memcached interface
    ==============================================
    Key = Canada
    Value = 34820000|9984670|R
    Added new key, value pair.
    Key = USA
    Value = 314242000|9826675|R
    Added new key, value pair.
    Key = Ireland
    Value = 6399152|84421|L
    Added new key, value pair.
    Key = UK
    Value = 62262000|243610|L
    Added new key, value pair.
    Key = Mexico
    Value = 113910608|1972550|R
    Added new key, value pair.
    Key = Denmark
    Value = 5543453|43094|R
    Added new key, value pair.
    Key = Norway
    Value = 5002942|385252|R
    Added new key, value pair.
    Key = UAE
    Value = 8264070|83600|R
    Added new key, value pair.
    Key = India
    Value = 1210193422|3287263|L
    Added new key, value pair.
    Key = China
    Value = 1347350000|9640821|R
    Added new key, value pair.
    
    ============================================
    Retrieving data for all keys (country names)
    ============================================
    Here is the result retrieved from the database for key Canada:
    34820000|9984670|R
    Unpacked population value: 34820000
    Unpacked area value  : 9984670
    Unpacked drive side value: R
    Here is the result retrieved from the database for key USA:
    314242000|9826675|R
    Unpacked population value: 314242000
    Unpacked area value  : 9826675
    Unpacked drive side value: R
    Here is the result retrieved from the database for key Ireland:
    6399152|84421|L
    Unpacked population value: 6399152
    Unpacked area value  : 84421
    Unpacked drive side value: L
    Here is the result retrieved from the database for key UK:
    62262000|243610|L
    Unpacked population value: 62262000
    Unpacked area value  : 243610
    Unpacked drive side value: L
    Here is the result retrieved from the database for key Mexico:
    113910608|1972550|R
    Unpacked population value: 113910608
    Unpacked area value  : 1972550
    Unpacked drive side value: R
    Here is the result retrieved from the database for key Denmark:
    5543453|43094|R
    Unpacked population value: 5543453
    Unpacked area value  : 43094
    Unpacked drive side value: R
    Here is the result retrieved from the database for key Norway:
    5002942|385252|R
    Unpacked population value: 5002942
    Unpacked area value  : 385252
    Unpacked drive side value: R
    Here is the result retrieved from the database for key UAE:
    8264070|83600|R
    Unpacked population value: 8264070
    Unpacked area value  : 83600
    Unpacked drive side value: R
    Here is the result retrieved from the database for key India:
    1210193422|3287263|L
    Unpacked population value: 1210193422
    Unpacked area value  : 3287263
    Unpacked drive side value: L
    Here is the result retrieved from the database for key China:
    1347350000|9640821|R
    Unpacked population value: 1347350000
    Unpacked area value  : 9640821
    Unpacked drive side value: R
    dtprice@ubuntu:~$
    
  5. Запросите innodb_memcache.containers, чтобы рассмотреть запись, которую Вы вставили ранее для multicol. Первый отчет это типовая запись для таблицы demo_test, которая составлена во время начальной установки daemon_memcached. Второй отчет это запись, которую Вы вставили для multicol.
    mysql> SELECT * FROM innodb_memcache.containers\G
    *************************** 1. row ***************************
    name: aaa
       db_schema: test
    db_table: demo_test
     key_columns: c1
     value_columns: c2
       flags: c3
      cas_column: c4
    expire_time_column: c5
    unique_idx_name_on_key: PRIMARY
    *************************** 2. row ***************************
    name: bbb
       db_schema: test
    db_table: multicol
     key_columns: country
     value_columns: population,area_sq_km,drive_side
       flags: c3
      cas_column: c4
    expire_time_column: c5
    unique_idx_name_on_key: PRIMARY
    
  6. Запросите multicol, чтобы рассмотреть данные, вставленные типовым приложением Питона. Данные доступны для запроса MySQL, который демонстрирует, как к тем же самым данным можно получить доступ, используя SQL или через приложения (использующуя соответствующий MySQL Connector или API).
    mysql> SELECT * FROM test.multicol;
    +---------+------------+------------+------------+------+------+------+
    | country | population | area_sq_km | drive_side | c3   | c4   | c5   |
    +---------+------------+------------+------------+------+------+------+
    | Canada  | 34820000   | 9984670    | R          | 0    |   11 | 0    |
    | China   | 1347350000 | 9640821    | R          | 0    |   20 | 0    |
    | Denmark | 5543453    | 43094      | R          | 0    |   16 | 0    |
    | India   | 1210193422 | 3287263    | L          | 0    |   19 | 0    |
    | Ireland | 6399152    | 84421      | L          | 0    |   13 | 0    |
    | Mexico  | 113910608  | 1972550    | R          | 0    |   15 | 0    |
    | Norway  | 5002942    | 385252     | R          | 0    |   17 | 0    |
    | UAE     | 8264070    | 83600      | R          | 0    |   18 | 0    |
    | UK      | 62262000   | 243610     | L          | 0    |   14 | 0    |
    | USA     | 314242000  | 9826675    | R          | 0    |   12 | 0    |
    +---------+------------+------------+------------+------+------+------+
    

    Всегда используйте достаточный размер, чтобы держать необходимые цифры, десятичные запятые, символы знака, начальные нули и так далее, определяя длину для столбцов, которые обработаны как числа. Слишком длинные значения в строковом столбце, такие как VARCHAR, являются усеченными, удаляя некоторые символы, которые могли произвести бессмысленные числовые значения.

  7. Произвольно, выполненный тип отчета запрашивает из таблицы InnoDB, которая хранит данные memcached.

    Вы можете представить доклады через запросы SQL, выполняя вычисления и тесты через любые столбцы, не только country. Поскольку следующие примеры используют данные только из нескольких стран, числа только в целях иллюстрации. Следующие запросы возвращают среднее население стран, где люди управляют справа, и средний размер стран, имена которых начинаются на U:

    mysql> SELECT AVG(population) FROM multicol WHERE drive_side = 'R';
    +-------------------+
    | avg(population)   |
    +-------------------+
    | 261304724.7142857 |
    +-------------------+
    
    mysql> SELECT SUM(area_sq_km) FROM multicol WHERE country LIKE 'U%';
    +-----------------+
    | sum(area_sq_km) |
    +-----------------+
    |10153885 |
    +-----------------+
    

    Поскольку population и area_sq_km хранят символьные, а не числовые данные, функции AVG() и SUM() работают, преобразовывая каждое значение в число сначала. Этот подход не работает на операторах < или >, например, сравнивая символьно-ориентированные значения, 9 > 1000, которые не ожидаются от такого запроса, как ORDER BY population DESC. Для самого точного обращения типа, выполните запросы для представлений, которые приводят числовые столбцы к соответствующим типам. Этот метод позволяет Вам использовать простые запросы SELECT * от приложений базы данных, гарантируя, что фильтр и упорядочивание правильны. Следующий пример показывает представление, которое может быть запрошено, чтобы найти лучшие три страны в порядке убывания населения, с результатами, отражающими последние данные в multicol:

    mysql> CREATE VIEW populous_countries AS
        -> SELECT country, cast(population as unsigned integer) population,
        ->        cast(area_sq_km as unsigned integer) area_sq_km,
        ->        drive_side FROM multicol
        ->        ORDER BY CAST(population as unsigned integer) DESC LIMIT 3;
    
    mysql> SELECT * FROM populous_countries;
    +---------+------------+------------+------------+
    | country | population | area_sq_km | drive_side |
    +---------+------------+------------+------------+
    | China   | 1347350000 |9640821     | R          |
    | India   | 1210193422 |3287263     | L          |
    | USA     |  314242000 |9826675     | R          |
    +---------+------------+------------+------------+
    
    mysql> DESC populous_countries;
    +------------+---------------------+------+-----+---------+-------+
    | Field      | Type                | Null | Key | Default | Extra |
    +------------+---------------------+------+-----+---------+-------+
    | country    | varchar(128)        |  NO  |     |         |       |
    | population | bigint(10) unsigned | YES  |     | NULL    |       |
    | area_sq_km | int(9) unsigned     | YES  |     | NULL    |       |
    | drive_side | varchar(1)          | YES  |     | NULL    |       |
    +------------+---------------------+------+-----+---------+-------+
    

16.19.6.2. Приспосабливание приложения memcached для InnoDB memcached

Рассмотрите эти аспекты MySQL и таблиц InnoDB, адаптируя существующие приложения memcached, чтобы использовать плагин daemon_memcached:

16.19.6.3. Тюнинг InnoDB memcached

Поскольку использование InnoDB в комбинации с memcached вовлекает запись всех данных на диск немедленно или когда-то позже, сырая работа, как ожидают, будет несколько медленнее, чем использование memcached отдельно. Используя InnoDB плагин memcached, надо максимально ускорить операции memcached при достижении лучшей работы, чем эквивалентные операции SQL.

Точки отсчета предполагают, что запросы и операции DML (вставки, обновления и удаления), которые используют интерфейс memcached, быстрее чем традиционный SQL. Операции DML, как правило, видят большие усовершенствования. Поэтому полагайте, что приспосабливание приложений с интенсивной записью, чтобы использовать интерфейс memcached, лучше.

Приспосабливание запросов SQL

Типы запросов, которые больше всего подходят для простых GET это запросы с единственным условием или набором AND в WHERE:

SQL:
SELECT col FROM tbl WHERE key = 'key_value';

memcached:
GET key_value

SQL:
SELECT col FROM tbl WHERE col1 = val1 and col2 = val2 and col3 = val3;

memcached:
# Since you must always know these 3 values to look up the key,
# combine them into a unique string and use that as the key
# for all ADD, SET, and GET operations.
key_value = val1 + ":" + val2 + ":" + val3
GET key_value

SQL:
SELECT 'key exists!' FROM tbl
       WHERE EXISTS (SELECT col1 FROM tbl WHERE KEY = 'key_value') LIMIT 1;

memcached:
# Test for existence of key by asking for its value and checking if the call succeeds,
# ignoring the value itself. For existence checking, you typically only store a very
# short value such as "1".
GET key_value
Используя системную память

Для лучшей работы разверните плагин daemon_memcached на машинах, которые сконфигурированы как типичные серверы базы данных, где большинство системной RAM передано буферному пулу через опцию innodb_buffer_pool_size. Для систем с буферными пулами в несколько гигабайт рассмотрите подъем значения innodb_buffer_pool_instances для максимальной пропускной способности, когда большинство операций вовлекает данные, которые уже кэшируются в памяти.

Сокращение избыточного ввода/вывода

InnoDB имеет много настроек, которые позволяют Вам выбирать баланс между высокой надежностью, в случае катастрофического отказа и количеством издержек ввода/вывода во время высоких рабочих нагрузок записи. Например, рассмотрите установку innodb_doublewrite в 0 и innodb_flush_log_at_trx_commit в 2. Определите эксплуатационные качества с различными настройками innodb_flush_method .

Подробности в разделе 9.5.8.

Сокращение издержек транзакций

Значение по умолчанию 1 для daemon_memcached_r_batch_size и daemon_memcached_w_batch_size предназначено для максимальной надежности результатов и безопасности хранимых или обновленных данных.

В зависимости от типа приложения, Вы могли бы увеличить одну или обе из этих настроек, чтобы уменьшить издержки частых операций commit. На занятой системе Вы могли бы увеличить daemon_memcached_r_batch_size зная, что изменения данных, сделанные через SQL, возможно, не становится видимы memcached немедленно (то есть, пока обработано не больше N запросов get). Обрабатывая данные, где каждая запись должна быть достоверно сохранена, установите daemon_memcached_w_batch_size в 1. Увеличьте установку, обрабатывая большие количества обновлений, предназначенных только для статистического анализа, где потеря последних N обновлений при катастрофическом отказе является приемлемым риском.

Например, вообразите систему, которая контролирует трафик, пересекающий оживленный мост, делая запись данных приблизительно для 100000 транспортных средств каждый день. Если приложение считает различные типы транспортных средств, чтобы проанализировать образцы трафика, измените daemon_memcached_w_batch_size на 100, уменьшив ввод/вывод на 99%. В случае отключения электричества потеряно максимум 100 отчетов, что может быть приемлемым пределом погрешности. Если бы вместо этого приложение выполнило автоматизированный сбор данных для каждого автомобиля, то Вы установили бы daemon_memcached_w_batch_size в 1, чтобы гарантировать, что каждый отчет был немедленно сохранен на диск.

Из-за пути, которым InnoDB организует значения ключа на диске, если у Вас есть большое количество ключей, которые надо создать, может быть быстрее сортировать элементы данных значением ключа в приложении и затем add их в сортированном порядке, вместо того, чтобы создать ключи в произвольном порядке.

Команда memslap, часть дистрибутива memcached, не входит в плагин daemon_memcached, может быть полезна для сопоставительного анализа различных конфигураций. Это может также использоваться, чтобы произвести типовые пары ключа/значения, чтобы использовать в Ваших собственных точках отсчета. См. раздел 18.2.3.3.6.

16.19.6.4. Управление транзакционным поведением InnoDB memcached

В отличие от традиционного memcached, daemon_memcached позволяет Вам управлять длительностью значений данных, произведенных посредством add, set, incr и т.п. По умолчанию, данные, написанные через интерфейс memcached хранятся на диске, и get возвратит новое значение с диска. Хотя поведение по умолчанию не предлагает самую лучшую работу, это все еще быстро по сравнению с интерфейсом SQL для таблиц InnoDB.

Поскольку Вы приобретаете опыт, используя daemon_memcached, Вы можете рассмотреть настройки длительности для некритических классов данных, рискуя тем, чтобы терять некоторые обновленные значения в случае отключения электричества или возвратить данные, которые являются немного устаревшими.

Частота Commit

Важно понимать, как часто новые и измененные данные commit. Если данные важны, они должны быть немедленно переданы, чтобы это было безопасно в случае катастрофического отказа или отключения электричества. Если данные менее важные, такие как счетчики, которые сброшены после катастрофического отказа или данные о журналировании, которые Вы можете позволить себе потерять, Вы могли бы предпочесть более высокую пропускную способность, которая доступна с менее частыми сохранениями.

Когда memcached вставляет, обновляет или удаляет данные в основной таблице InnoDB, они меняются немедленно (если daemon_memcached_w_batch_size=1) или некоторое время спустя (если daemon_memcached_w_batch_size больше 1). В любом случае изменение не может быть откачено. Если Вы увеличиваете значение daemon_memcached_w_batch_size, чтобы избежать большого ввода/вывода в течение напряженного времени, передача может стать редкой, когда рабочая нагрузка уменьшается. Как мера по безопасности, фоновый поток автоматически передает изменения, произведенные через memcached API равномерно. Интервалом управляет опция innodb_api_bk_commit_interval, у которой есть настройка по умолчанию 5 секунд.

Когда memcached вставляет или обновляет данные в основной таблице InnoDB, измененные данные немедленно видимы другим запросам memcached, потому что новое значение остается в кэш-памяти, даже если это еще не передано на сторону MySQL.

Операционная изоляция

Когда memcached выполняет запрос get или incr или DML на основной таблице InnoDB, Вы можете управлять, видит ли работа самые последние данные, написанные в таблицу, только данные, которые были переданы, или другие изменения операционного уровня изоляции. Используйте опцию innodb_api_trx_level, чтобы управлять этой особенностью. Числовые значения, определенные для этой опции, соответствуют уровням изоляции, например, REPEATABLE READ .

Строгий уровень изоляции гарантирует, что данные, которые Вы получаете, не откачены или не изменились внезапно, чтобы заставлять последующие запросы возвратить различные значения. Однако, строгие уровни изоляции требуют больших издержек блокировки, что может вызвать ожидание. Для приложения NoSQL-стиля, которое не использует продолжительные транзакции, Вы можете, как правило, использовать уровень изоляции значения по умолчанию или переключаться на менее строгий уровень изоляции.

Отключение блокировок строки для memcached DML

Опция innodb_api_disable_rowlock может использоваться, чтобы отключить блокировки строки, когда memcached просит DML через daemon_memcached. По умолчанию innodb_api_disable_rowlock = OFF, что означает, что memcached просит блокировки строки для get и set. Когда innodb_api_disable_rowlock = ON, memcached просит табличную блокировку вместо блокировок строки.

Опция innodb_api_disable_rowlock не является динамичной. Это должно быть определено при запуске в командной строке mysqld или введено в конфигурационный файл MySQL.

Разрешение или запрет DDL

По умолчанию Вы можете выполнить операции DDL, например, ALTER TABLE на таблицах, используемых daemon_memcached. Чтобы избежать потенциального замедления, когда эти таблицы используются для приложений высокой пропускной способности, отключите операции DDL на этих таблицах, включая при запуске опцию innodb_api_enable_mdl . Эта опция является менее подходящей, если Вы получаете доступ к тем же самым таблицам через memcached и SQL, потому что это блокирует CREATE INDEX на таблицах, которые могли быть важными для выполнения запросов.

Хранить жанные на диске, в памяти или везде

Таблица innodb_memcache.cache_policies определяет, хранить ли данные, написанные через интерфейс memcached на диске (innodb_only, по умолчанию), только в памяти, как с традиционным memcached (cache-only) или в обоих местах (caching).

При значении caching, если memcached не может найти ключ в памяти, он ищет значение в таблице InnoDB. Значения из get при caching могут быть устаревшими, если значения были обновлены на диске в таблице InnoDB, но еще не выдохлись в кэш-памяти.

Кэширующая политика может быть установлена независимо для get, set (включая incr и decr), delete и flush.

Например, Вы могли бы позволить get и set, чтобы запросить или обновить таблицу и кэш-память memcached в то же самое время (используя caching), делая delete, flush или обе операции только на копии в памяти (используя cache_only). Этот путь, удаляя или сбрасывая элемент только вычеркивает элемент от кэша, и последнее значение возвращено из таблицы InnoDB в следующий раз, когда элемент требуют.

mysql> SELECT * FROM innodb_memcache.cache_policies;
+--------------+-------------+-------------+---------------+--------------+
| policy_name  | get_policy  | set_policy  | delete_policy | flush_policy |
+--------------+-------------+-------------+---------------+--------------+
| cache_policy | innodb_only | innodb_only | innodb_only   | innodb_only  |
+--------------+-------------+-------------+---------------+--------------+

mysql> UPDATE innodb_memcache.cache_policies SET set_policy = 'caching'
    ->        WHERE policy_name = 'cache_policy';

Значения innodb_memcache.cache_policies считаны только при запуске. После изменения значений в этой таблице, удалите и повторно установите плагин daemon_memcached, чтобы гарантировать, что изменения вступают в силу.

mysql> UNINSTALL PLUGIN daemon_memcached;
mysql> INSTALL PLUGIN daemon_memcached soname "libmemcached.so";

16.19.6.5. Приспосабливание запроса DML к memcached

Точки отсчета предполагают, что daemon_memcached ускоряет DML (вставки, обновения и удаления) больше, чем он ускоряет запросы.

Единственная строка запроса DML является самыми легким типом запросов, чтобы использовать операции memcached. INSERT вместо add, UPDATE вместо set, incr или decr, DELETE вместо delete. Эти операции, как гарантируют, затронут только одну строку, когда запущены через интерфейс memcached, потому что key уникален в пределах таблицы.

В следующих примерах SQL t1 обращается к таблице, используемой для операциях memcached, основанных на конфигурации в innodb_memcache.containers. key обращается к столбцу, перечисленному под key_columns, val обращается к столбцу, перечисленному как value_columns.

INSERT INTO t1 (key,val) VALUES (some_key,
                                 some_value);
SELECT val FROM t1 WHERE key = some_key;
UPDATE t1 SET val = new_value
          WHERE key = some_key;
UPDATE t1 SET val = val + x WHERE key = some_key;
DELETE FROM t1 WHERE key = some_key;

Следующие TRUNCATE TABLE и DELETE, которые удаляют все строки из таблицы, соответствуют flush_all, где t1 сконфигурирована как таблица для операций memcached, как в предыдущем примере.

TRUNCATE TABLE t1;
DELETE FROM t1;

16.19.6.6. Выполнение DML и запроса DDL об основной таблице InnoDB

Вы можете получить доступ к основной таблице InnoDB (по умолчанию test.demo_test) через стандартные интерфейсы SQL. Однако, есть некоторые ограничения:

16.19.7. Репликация и плагин InnoDB memcached

Поскольку daemon_memcached поддерживает двоичный журнал MySQL, обновления, сделанные на главном сервере через интерфейс memcached могут копироваться для резервного копирования, балансируя интенсивные рабочие нагрузки чтения и высокую доступность. Все команды memcached поддержаны с двоичным журналированием.

Вы не должны настроить daemon_memcached на ведомых серверах. Основное преимущество этой конфигурации это увеличение пропускной способности на ведущем устройстве. Скорость механизма репликации не затронута.

Следующие разделы показывают, как использовать двоичный журнал, используя daemon_memcached с репликацией MySQL. Предполагается, что Вы завершили установку, описанную в разделе 16.19.3.

Включение двоичного журнала InnoDB memcached

  1. Чтобы использовать daemon_memcached с двоичным журналом, включите опцию innodb_api_enable_binlog на главном сервере. Эта опция может быть установленатолько при запуске сервера. Вы должны также включить двоичный журнал на главном сервере опцией --log-bin. Вы можете добавить эти опции к конфигурационному файлу MySQL или в командную строку mysqld .

    mysqld ... --log-bin -Б─⌠innodb_api_enable_binlog=1
    
  2. Сконфигурируйте основной и ведомый серверы, как описано в разделе 19.1.2.
  3. Используйте mysqldump , чтобы создать основной снимок данных и синхронизировать снимок с ведомым сервером.
    master shell> mysqldump --all-databases --lock-all-tables > dbdump.db
    slave shell> mysql < dbdump.db
    
  4. На главном сервере скомандуйте SHOW MASTER STATUS, чтобы получить координаты основного двоичного журнала.
    mysql> SHOW MASTER STATUS;
    
  5. На ведомом сервере используйте CHANGE MASTER TO, чтобы настроить ведомый сервер, используя координаты из основного двоичного журнала.
    mysql> CHANGE MASTER TO MASTER_HOST='localhost', MASTER_USER='root',
                               MASTER_PASSWORD='', MASTER_PORT = 13000,
                               MASTER_LOG_FILE='0.000001, MASTER_LOG_POS=114;
    
  6. Запустите ведомое устройство.
    mysql> START SLAVE;
    

    Если журнал ошибок выводит что-то, подобное следующему, ведомое устройство готово.

    2013-09-24T13:04:38.639684Z 49 [Note] Slave I/O thread: connected to
    master 'root@localhost:13000', replication started in log '0.000001'
    at position 114
    

Тестирование конфигурации репликации InnoDB memcached

Этот пример демонстрирует, как проверить конфигурацию InnoDB memcached, используя memcached и telnet, чтобы вставить, обновить и удалить данные. Клиент MySQL используется, чтобы проверить результаты на основном и ведомом серверах.

Пример использует таблицу demo_test, которая была составлена скриптом innodb_memcached_config.sql во время начальной установки daemon_memcached. Таблица demo_test содержит единственную запись в качестве примера.

  1. Используйте команду set, чтобы вставить запись с ключом test1, значение флага 10, значение истечения 0, значение cas 1 и значение t1.

    telnet 127.0.0.1 11211
    Trying 127.0.0.1...
    Connected to 127.0.0.1.
    Escape character is '^]'.
    set test1 10 0 1
    t1
    STORED
    
  2. На главном сервере проверьте, что запись была вставлена в demo_test. Учитывая, что demo_test не была ранее изменена, должно быть две записи. Запись в качестве примера с ключом AA и запись, которую Вы только что вставили, с ключом test1. Столбец c1 отображается на ключ, c2 значение, c3 флаг, c4 cas и c5 ко времени истечения срока. Время истечения срока было установлено в 0, так как это не использовано.
    mysql> SELECT * FROM test.demo_test;
    +-------+--------------+----+----+----+
    | c1    | c2           | c3 | c4 | c5 |
    +-------+--------------+----+----+----+
    | AA    | HELLO, HELLO | 8  | 0  | 0  |
    | test1 | t1           | 10 | 1  | 0  |
    +-------+--------------+----+----+----+
    
  3. Проверьте, что та же самая запись копировалась к ведомому серверу.
    mysql> SELECT * FROM test.demo_test;
    +-------+--------------+----+----+----+
    | c1    | c2           | c3 | c4 | c5 |
    +-------+--------------+----+----+----+
    | AA    | HELLO, HELLO | 8  | 0  | 0  |
    | test1 | t1           | 10 | 1  | 0  |
    +-------+--------------+----+----+----+
    
  4. Используйте set, чтобы обновить ключ к значению new.
    telnet 127.0.0.1 11211
    Trying 127.0.0.1...
    Connected to 127.0.0.1.
    Escape character is '^]'.
    set test1 10 0 2
    new
    STORED
    

    Обновление копируется к ведомому серверу (заметьте, что cas также обновлено).

    mysql> SELECT * FROM test.demo_test;
    +-------+--------------+----+----+----+
    | c1    | c2           | c3 | c4 | c5 |
    +-------+--------------+----+----+----+
    | AA    | HELLO, HELLO |  8 | 0  | 0  |
    | test1 | new          | 10 | 2  | 0  |
    +-------+--------------+----+----+----+
    
  5. Удалите запись test1 командой delete.
    telnet 127.0.0.1 11211
    Trying 127.0.0.1...
    Connected to 127.0.0.1.
    Escape character is '^]'.
    delete test1
    DELETED
    

    Когда delete копируется к ведомому устройству, запись test1 на ведомом устройстве также удалена.

    mysql> SELECT * FROM test.demo_test;
    +----+--------------+----+----+----+
    | c1 | c2           | c3 | c4 | c5 |
    +----+--------------+----+----+----+
    | AA | HELLO, HELLO | 8  | 0  | 0  |
    +----+--------------+----+----+----+
    
  6. Удалите все строки из таблицы, используя flush_all.
    telnet 127.0.0.1 11211
    Trying 127.0.0.1...
    Connected to 127.0.0.1.
    Escape character is '^]'.
    flush_all
    OK
    
    mysql> SELECT * FROM test.demo_test;
    Empty set (0.00 sec)
    
  7. Подключитесь к главному серверу и введите две новых записи.
    telnet 127.0.0.1 11211
    Trying 127.0.0.1...
    Connected to 127.0.0.1.
    Escape character is '^]'
    set test2 10 0 4
    again
    STORED
    set test3 10 0 5
    again1
    STORED
    
  8. Подтвердите, что две записи копировались к ведомому серверу.
    mysql> SELECT * FROM test.demo_test;
    +-------+--------+----+----+----+
    | c1    | c2     | c3 | c4 | c5 |
    +-------+--------+----+----+----+
    | test2 | again  | 10 | 4  | 0  |
    | test3 | again1 | 10 | 5  | 0  |
    +-------+--------+----+----+----+
    
  9. Удалите все строки из таблицы, используя flush_all.
    telnet 127.0.0.1 11211
    Trying 127.0.0.1...
    Connected to 127.0.0.1.
    Escape character is '^]'.
    flush_all
    OK
    
  10. Проверьте, что flush_all скопировалась на ведомом сервере.
    mysql> SELECT * FROM test.demo_test;
    Empty set (0.00 sec)
    

Примечания о двоичном журнале и InnoDB memcached

Формат двоичного журнала:

Транзакции:

16.19.8. Внутренности плагина InnoDB memcached

InnoDB API для InnoDB memcached

InnoDB memcached обращается к InnoDB через InnoDB API, большинство которых непосредственно принято от встроенного InnoDB. Функции API передаются механизму InnoDB memcached как callback. Функции InnoDB API получают доступ к таблицам InnoDB непосредственно и являются главным образом операциями DML, за исключением TRUNCATE TABLE .

Команды memcached осуществлены через InnoDB memcached API. Следующая таблица обрисовывает в общих чертах, как команды memcached отображены на DML или операции DDL.

Таблица 16.13. Команды memcached и связанные операции DML или DDL

Команда memcachedDML или DDL
getКоманда чтения
setПоиск, сопровождаемый INSERT или UPDATE (в зависимости от того, существует ли ключ)
addПоиск, сопровождаемый INSERT или UPDATE
replaceПоиск, сопровождаемый UPDATE
appendПоиск, сопровождаемый UPDATE (добавляет данные к результату прежде UPDATE)
prependПоиск, сопровождаемый UPDATE (добавляет данные к результату прежде UPDATE)
incrПоиск, сопровождаемый UPDATE
decrПоиск, сопровождаемый UPDATE
deleteПоиск, сопровождаемый DELETE
flush_allTRUNCATE TABLE (DDL)

Таблицы конфигурации InnoDB memcached

Этот раздел описывает таблицы конфигурации, используемые daemon_memcached. Таблицы cache_policies, config_options и containers составлены скриптом innodb_memcached_config.sql в базе данных innodb_memcache.

mysql> USE innodb_memcache;
Database changed
mysql> SHOW TABLES;
+---------------------------+
| Tables_in_innodb_memcache |
+---------------------------+
| cache_policies            |
| config_options            |
| containers                |
+---------------------------+

Таблица cache_policies

Таблица cache_policies определяет политику кэша для InnoDB memcached. Вы можете определить отдельную политику для get, set, delete и flush в пределах единственной политики кэша. Настройка по умолчанию для всех операций innodb_only.

Таблица 16.14. Столбцы cache_policies

СтолбецОписание
policy_name Название политики кэша. Значение по умолчанию cache_policy.
get_policyПолитика кэша для операции get. Допустимые значения innodb_only, cache-only, caching или disabled. Значение по умолчанию innodb_only.
set_policy Политика кэша для операции set. Допустимые значения innodb_only, cache-only, caching или disabled. Значение по умолчанию innodb_only.
delete_policy Политика кэша для операции delete. Допустимые значения innodb_only, cache-only, caching или disabled. Значение по умолчанию innodb_only.
flush_policy Политика кэша для операции flush. Допустимые значения innodb_only, cache-only, caching или disabled. Значение по умолчанию innodb_only.

Таблица config_options

Таблица config_options хранит настройки memcached, которые могут быть изменены во время выполнения, используя SQL. Поддержанные параметры конфигурации separator и table_map_delimiter.

Таблица 16.15. Столбцы config_options

СтолбецОписание
Name Название опции memcached. Следующие параметры конфигурации поддержаны в таблице config_options:
  • separator: Используется, чтобы разделить значения длинной строки на отдельные значения, когда там много значений value_columns. По умолчанию separator символ |. Например, если Вы определяете col1, col2 как столбцы значений, и Вы определяете | как разделитель, Вы можете выпустить следующую команду memcached, чтобы вставить значения в col1 и col2:

    set keyx 10 0 19
    valuecolx|valuecoly
    

    valuecol1x сохранен в col1, а valuecoly сохранен в col2.

  • table_map_delimiter: Символ, отделяющий имя схемы и имя таблицы, когда Вы используете формат @@, чтобы получить доступ к ключу в определенной таблице. Например, @@t1.some_key и @@t2.some_key имеют то же самое значение ключа, но сохранены в различных таблицах.

Value Значение опции memcached.

Таблица containers

Таблица containers является самой важной из трех таблиц конфигурации. Каждая таблица InnoDB, которая используется, чтобы сохранить значения memcached должна иметь запись в таблице containers. Запись обеспечивает отображение между столбцом таблицы InnoDB и столбцами таблицы container, которые требуются для работы memcached с InnoDB.

Таблица containers содержит запись по умолчанию для test.demo_test, которая составлена скриптом innodb_memcached_config.sql. Чтобы использовать плагин daemon_memcached с Вашей собственной таблицей InnoDB, Вы должны создать запись в containers.

Таблица 16.16. Столбцы containers

СтолбецОписание
name Имя, данное контейнеру. Если таблица InnoDB не требуется по имени, используя форму @@, плагин daemon_memcached применяет таблицу InnoDB с containers.name = default. Если нет такой записи, применяется первая запись в containers, упорядоченная в алфавитном порядке по name, определяющая таблицу InnoDB по умолчанию.
db_schemaНазвание базы данных, где находится таблица InnoDB. Это необходимое значение.
db_tableНазвание таблицы InnoDB, которая хранит значения memcached. Это необходимое значение.
key_columnsСтолбец в таблице InnoDB, которая содержит значения ключа поиска для memcached. Это необходимое значение.
value_columnsСтолбцы (один или больше) таблицы InnoDB для хранения данных memcached. Много столбцов может быть определено, используя символ разделителя, определенный в innodb_memcached.config_options. По умолчанию разделитель это символ канала (|). Чтобы определить много столбцов, отделите их определенным символом разделителя. Например: col1|col2|col3. Это необходимое значение.
flagsСтолбцы таблицы InnoDB, которые используются в качестве флагов (определяемое пользователем числовое значение, которое сохранено и получено наряду с основным значением) для memcached. Значение флага может использоваться в качестве спецификатора столбца для некоторых операций (таких, как incr, prepend), если значение memcached отображено на много столбцов, чтобы работа была выполнена на указанном столбце. Например, если Вы отобразили value_columns на три столбца InnoDB, и надо увеличить только один столбце, используют flags, чтобы определить столбец. Если Вы не используете flags, задайте значение 0, чтобы указать, что это не использовано.
cas_columnСтолбец таблицы, который хранит значение compare-and-swap (cas). cas_column связано с путем, которым memcached обращается к различным серверам и данным о кэшах в памяти. Поскольку memcached плотно объединен с единственным сервером memcached, механизм кэширования в памяти обработан MySQL и буферным пулом, этот столбец редко необходим. Если Вы не используете этот столбец, установите значение 0, чтобы указать, что это не использовано.
expire_time_columnСтолбец таблицы, который хранит значение истечения. expire_time_column связано с путем, которым memcached обращается к различным серверам и данным о кэшах в памяти. Поскольку memcached плотно объединен с единственным сервером memcached, механизм кэширования в памяти обработан MySQL и буферным пулом, этот столбец редко необходим. Если Вы не используете этот столбец, установите значение 0, чтобы указать, что это не использовано. Максимум определен как INT_MAX32 или 2147483647 секунд.
unique_idx_name_on_key Название индекса на ключевом столбце. Это должно быть уникальным индексом. Это может быть primary key или вторичным индексом. Предпочтительно используйте первичный ключ таблицы InnoDB. Использование первичного ключа избегает поиска, который выполнен, когда используется вторичный индекс. Вы не можете создать покрывающий индекс для поисков в memcached: InnoDB возвращает ошибку, если Вы пытаетесь определить композитный вторичный индекс по ключам и по столбцам значений.
Ограничения столбца таблицы containers

Предварительная проверка выполнена во время загрузки, чтобы провести в жизнь ограничения столбца. Если несоответствия будут найдены, то плагин не будет загружаться.

Отображение значений нескольких cтолбцов

Пример таблицы demo_test

Скрипт innodb_memcached_config.sql создает таблицу demo_test в базе данных test, которая может использоваться, чтобы проверить memcached немедленно после установки.

Скрипт innodb_memcached_config.sql также создает запись для таблицы demo_test в innodb_memcache.containers.

mysql> SELECT * FROM innodb_memcache.containers\G
*************************** 1. row ***************************
name: aaa
   db_schema: test
db_table: demo_test
 key_columns: c1
 value_columns: c2
   flags: c3
  cas_column: c4
expire_time_column: c5
unique_idx_name_on_key: PRIMARY

mysql> SELECT * FROM test.demo_test;
+----+--------------+----+----+----+
| c1 | c2           | c3 | c4 | c5 |
+----+--------------+----+----+----+
| AA | HELLO, HELLO | 8  | 0  | 0  |
+----+--------------+----+----+----+

16.19.9. Проблемы с InnoDB memcached

Этот раздел описывает проблемы, с которыми Вы можете столкнуться, используя InnoDB memcached.

16.20. Проблемы с InnoDB

Следующие общие руководящие принципы относятся к поиску неисправностей InnoDB:

16.20.1. Проблемы с InnoDB I/O

Поиск неисправностей для InnoDB I/O зависят от того, когда проблема происходит: во время запуска сервера MySQL или во время нормального функционирования, когда DML или запрос DDL терпят неудачу из-за проблем на уровне файловой системы.

Проблемы инициализации

Если что-то идет не так, как надо, когда InnoDB пытается инициализировать табличное пространство или файлы системного журнала, удалите все файлы, создаваемые InnoDB: все файлы ibdata и ib_logfile. Если Вы уже создали некоторые таблицы InnoDB, также удалите любые файлы .ibd из каталогов базы данных MySQL. Тогда попробуйте создание базы данных снова. Для самого легкого поиска неисправностей, запустите сервер MySQL из командной строки так, чтобы Вы видели то, что происходит.

Проблемы во время выполнения

Если InnoDB печатает ошибку операционной системы во время работы с файлом, обычно у проблемы есть одно из следующих решений:

16.20.2. Восстановление InnoDB

Чтобы исследовать повреждение страницы базы данных, Вы могли бы вывести свои таблицы из базы данных с помощью SELECT ... INTO OUTFILE. Обычно большинство данных, полученных таким образом, не повреждено. Серьезное повреждение могло бы вызвать SELECT * FROM tbl_name или фоновые процессы. В таких случаях Вы можете использовать опцию innodb_force_recovery , чтобы запустить механизм хранения, препятствуя фоновым работам, чтобы Вы могли вывести свои таблицы. Например, Вы можете добавить следующую строку к разделу [mysqld] Вашего файла опции прежде, чем перезапустить сервер:

[mysqld]
innodb_force_recovery = 1

Установите innodb_force_recovery к значению больше 0 только в чрезвычайной ситуации, чтобы Вы могли запустить InnoDB и вывести свои таблицы. Прежде чем сделать так, гарантируйте, что у Вас есть резервная копия Вашей базы данных в случае, если Вы должны обновить ее. Значения 4 или больше могут надолго повредить файлы с данными. Используйте innodb_force_recovery 4 или больше на производственном случае сервера только после того, как Вы успешно проверили установку на отдельной физической копии Вашей базы данных. Вызывая восстановление InnoDB, Вы должны всегда запускать с innodb_force_recovery=1 и увеличьте значение только по мере необходимости.

innodb_force_recovery = 0 по умолчанию (нормальный запуск без принудительного восстановления). Допустимые ненулевые значения для innodb_force_recovery от 1 до 6. Большее значение включает функциональность меньших значений. Например, значение 3 включает всю функциональность значений 1 и 2.

Если Вы в состоянии вывести свои таблицы с innodb_force_recovery = 3 или меньше, тогда Вы относительно защищены от того, что только некоторые данные на поврежденных отдельных страницах потеряны. Значение 4 или больше считают опасным, потому что файлы с данными могут быть надолго повреждены. Значение 6 считают решительным, потому что страницы базы данных оставляют в устаревшем состоянии, которое в свою очередь может ввести больше повреждений в B-trees и другие структуры базы данных.

Как мера по безопасности, InnoDB блокирует INSERT, UPDATE или DELETE, если innodb_force_recovery больше 0. innodb_force_recovery = 4 или выше запускает InnoDB в режиме только для чтения.

Вы можете SELECT из таблиц, чтобы вывести их. С innodb_force_recovery = 3 или меньше Вы можете выполнить для таблиц DROP или CREATE. DROP TABLE также поддержан с innodb_force_recovery больше 3.

Если Вы знаете, что данная таблица вызывает катастрофический отказ на отмене, Вы можете удалить это. Если Вы сталкиваетесь с безудержной отменой, вызванной отменом массового импорта или ALTER TABLE, Вы можете уничтожить процесс mysqld и установить innodb_force_recovery = 3, поднять базу данных без отмены, а затем DROP таблицу, которая вызывает безудержную отмену.

Если повреждение в пределах табличных данных препятствует тому, чтобы Вы вывели все табличное содержание, запрос c ORDER BY primary_key DESC может быть в состоянии вывести часть таблицы после поврежденной части.

Если верхний уровень innodb_force_recovery нужен для запуска InnoDB, могут быть поврежденные структуры данных, которые могли вызвать сбои сложных запросов (запросы, содержащие WHERE, ORDER BY или нечто подобное). В этом случае Вы можете быть в состоянии использовать только обычные запросы SELECT * FROM t.

16.20.3. Проблемы словаря данных InnoDB

Информация о табличных определениях хранится в словаре данных InnoDB. Если Вы перемещаете файлы с данными, или если катастрофический отказ сервера был в середине работы со словарем данных, данные словаря могут стать непоследовательными.

Если повреждение словаря данных или проблема последовательности препятствуют тому, чтобы Вы запустили InnoDB, см. раздел 16.20.2.

Не может открыть файл данных

При включении innodb_file_per_table (значение по умолчанию), следующие сообщения могут появиться при запуске если файл табличного пространства file-per-table (файл .ibd) отсутствует:

[ERROR] InnoDB: Operating system error number 2 in a file operation.
[ERROR] InnoDB: The error means the system cannot find the path specified.
[ERROR] InnoDB: Cannot open datafile for read-only: './test/t1.ibd' OS error: 71
[Warning] InnoDB: Ignoring tablespace `test/t1` because it could not be opened.

Используйте запрос DROP TABLE , чтобы удалить данные о недостающей таблице из словаря данных.

Восстановление висячей строки файлов File-Per-Table ibd

Эта процедура описывает, как восстановить висячие строки в файлах file-per-table .ibd к другому случаю MySQL. Вы могли бы использовать эту процедуру, если системное табличное пространство потеряно или неисправимо, и Вы хотите восстановить копию .idb на новом сервере MySQL.

Процедура не поддержана для файлов .ibd общего табличного пространства.

Процедура предполагает, что Вы имеете только резервные копии файла .ibd и восстанавливаете к той же самой версии MySQL, которая первоначально создала файлы. См. раздел 16.8.3 для информации о создании чистых резервных копий.

Ограничения копирования табличного пространства, обрисованные в общих чертах в разделе 16.7.6, применимы к этой процедуре.

  1. На новом случае MySQL, создайте таблицу в базе данных с тем же самым именем.

    mysql> CREATE DATABASE sakila;
    mysql> USE sakila;
    mysql> CREATE TABLE actor (
        ->        actor_id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
        ->        first_name VARCHAR(45) NOT NULL,
        ->        last_name VARCHAR(45) NOT NULL,
        ->        last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
        ->        ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (actor_id),
        ->        KEY idx_actor_last_name (last_name)) ENGINE=InnoDB
        ->        DEFAULT CHARSET=utf8;
    
  2. Откажитесь от табличного пространства недавно составленной таблицы.
    mysql> ALTER TABLE sakila.actor DISCARD TABLESPACE;
    
  3. Скопируйте файл .idb из Вашего резервного каталога в новый каталог базы данных.
    shell> cp /backup_directory/actor.ibd path/to/mysql-5.7/data/sakila/
    
  4. Гарантируйте, что у файла .ibd есть необходимые разрешения.
  5. Импортируйте файл .ibd. Предупреждение выпущено, указывая, что InnoDB попытается импортировать файл без проверки схемы.
    mysql> ALTER TABLE sakila.actor IMPORT TABLESPACE; SHOW WARNINGS;
    Query OK, 0 rows affected, 1 warning (0.15 sec)
    
    Warning | 1810 | InnoDB: IO Read error: (2, No such file or directory)
    Error opening './sakila/actor.cfg', will attempt to import
    without schema verification
    
  6. Запросите таблицу, чтобы проверить, что файл .ibd был успешно восстановлен.
    mysql> SELECT COUNT(*) FROM sakila.actor;
    +----------+
    | count(*) |
    +----------+
    |  200     |
    +----------+
    

16.20.4. Обработка ошибок InnoDB

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

Во время неявных отмен, так же как во время выполнения явного ROLLBACK, SHOW PROCESSLIST показывает Rolling back в столбце State для соответствующего соединения.