RussianLDP Рейтинг@Mail.ru
WebMoney: 
WMZ Z294115950220 
WMR R409981405661 
WME E134003968233 
Visa 
4274 3200 2453 6495 

7 Типы таблиц MySQL

Начиная с MySQL Version 3.23.6, Вы можете выбирать между тремя базисными форматами таблиц (ISAM, HEAP и MyISAM. Более новый MySQL может поддерживать дополнительные типы таблиц (BDB или InnoDB) в зависимости от того, как Вы его компилируете. Когда Вы создаете новую таблицу, Вы можете сообщать MySQL, какой именно тип таблиц он должен использовать для таблицы. MySQL будет всегда создавать файл .frm, чтобы сохранить определения столбцов и таблицы. В зависимости от типа таблицы, индекс и данные будут сохранены в других файлах.

Обратите внимание, что, чтобы использовать таблицы системы InnoDB, Вы должны использовать по крайней мере опцию запуска innodb_data_file_path. Подробности в разделе "7.6.2 Опции запуска InnoDB".

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

Вы можете преобразовывать таблицы между различными типами инструкцией ALTER TABLE.

Обратите внимание, что MySQL поддерживает два различных вида таблиц. Транзакционно-безопасные таблицы (BDB и InnoDB) и транзакционно-небезопасные таблицы (HEAP, ISAM, MERGE и MyISAM).

Преимущества транзакционно-безопасных таблиц (transaction-safe tables, TST):

  • Более безопасны. Даже если MySQL рухнул, или Вы получаете аппаратные проблемы, Вы можете получить Ваши данные обратно либо автоматическим восстановлением, либо из резервной копии+файл регистрации транзакции.
  • Вы можете объединять много инструкций и применять их все за один раз.
  • Вы можете выполнять ROLLBACK, чтобы игнорировать внесенные изменения (если Вы не работаете в режиме auto commit).
  • Если произошли сбои модификации, все Ваши изменения будут восстановлены.

Преимущества транзакционно-небезопасных таблиц (transaction-safe tables, NTST):

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

Вы можете объединять TST и NTST таблицы в одних и тех же инструкциях.

7.6 Таблицы InnoDB

7.6.1 Обзор таблиц InnoDB

Таблицы InnoDB включены в исходники MySQL, начиная с версии 3.23.34a, и активизированы в двоичной версии MySQL-max.

Если Вы загрузили двоичную версию MySQL, которая включает поддержку для InnoDB (mysqld-max), просто поставьте ее и все.

Чтобы откомпилировать MySQL с поддержкой InnoDB, загрузите MySQL-3.23.37 или более новую версию, и сконфигурируйте MySQL с опцией --with-innodb:

cd /path/to/source/of/mysql-3.23.37
./configure --with-innodb

Чтобы запустить InnoDB, Вы должны определить, где должны быть сохранены данные для таблиц InnoDB, определяя опцию innodb_data_file_path в командной строке или в файле опций MySQL. Подробности в разделе "7.6.2 Опции запуска InnoDB". Если Вы сконфигурировали MySQL для InnoDB, но не определили вышеупомянутую опцию, mysqld при старте сообщит:

Can't initialize InnoDB as 'innodb_data_file_path' is not set

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

Формат InnoDB был разработан для максимальной эффективности при обработке больших объемов данных.

Вы можете найти последнюю информацию относительно InnoDB на http://www.innodb.com. Наиболее современная версия руководства по InnoDB помещается там, и Вы можете также купить коммерческую поддержку для таблиц InnoDB.

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

InnoDB распространяется под GNU GPL License Version 2 (June 1991). В дистрибутиве исходных текстов MySQL, InnoDB появляется как подкаталог.

7.6.2 Опции запуска InnoDB

Начиная с MySQL-3.23.37, префикс параметров изменен с innobase_... на innodb_....

Чтобы использовать InnoDB, Вы ДОЛЖНЫ определить параметры конфигурации MySQL в секции [mysqld] файла конфигурации my.cnf. Подробности в разделе " 4.1.2 Файл опций my.cnf".

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

Предположим, что Вы имеете машину под Windows NT с 128 MB RAM и одним жестким диском на 10 GB. Ниже приведен пример возможных параметров конфигурации в my.cnf для InnoDB:

innodb_data_file_path = ibdata1:2000M;ibdata2:2000M
innodb_data_home_dir = c:\ibdata
set-variable = innodb_mirrored_log_groups=1
innodb_log_group_home_dir = c:\iblogs
set-variable = innodb_log_files_in_group=3
set-variable = innodb_log_file_size=30M
set-variable = innodb_log_buffer_size=8M
innodb_flush_log_at_trx_commit=1
innodb_log_arch_dir = c:\iblogs
innodb_log_archive=0
set-variable = innodb_buffer_pool_size=80M
set-variable = innodb_additional_mem_pool_size=10M
set-variable = innodb_file_io_threads=4
set-variable = innodb_lock_wait_timeout=50

Обратите внимание, что файлы данных должны быть < 4G и < 2G на некоторых файловых системах! Полный размер файлов данных должен быть >=10 MB. InnoDB не создает каталоги, Вы должны создать их непосредственно.

Предположим, что Вы имеете Linux-машину с 512 MB RAM и тремя жесткими дисками по 20 GB (смонтированы как каталоги /, /dr2 и /dr3). Ниже приведен пример возможных параметров конфигурации в my.cnf для InnoDB:

innodb_data_file_path = ibdata/ibdata1:2000M;dr2/ibdata/ibdata2:2000M
innodb_data_home_dir = /
set-variable = innodb_mirrored_log_groups=1
innodb_log_group_home_dir = /dr3
set-variable = innodb_log_files_in_group=3
set-variable = innodb_log_file_size=50M
set-variable = innodb_log_buffer_size=8M
innodb_flush_log_at_trx_commit=1
innodb_log_arch_dir = /dr3/iblogs
innodb_log_archive=0
set-variable = innodb_buffer_pool_size=400M
set-variable = innodb_additional_mem_pool_size=20M
set-variable = innodb_file_io_threads=4
set-variable = innodb_lock_wait_timeout=50

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

Значения параметров конфигурации следующие:

innodb_data_home_dirОбщая часть пути каталога для всех файлов данных InnoDB.
innodb_data_file_pathПути к индивидуальным файлам данных и их размеры. Полный путь каталога к каждому файлу данных строится, связывая innodb_data_home_dir с путями, определенными здесь. Размеры файлов определены в мегабайтах, следовательно, M после спецификации размера выше подразумевается. Не устанавливайте размер файла больше, чем 4000M, а на большинстве операционных систем не больше, чем 2000M. InnoDB также понимает сокращение 'G', 1G означает 1024M. Сумма размеров файлов должна быть по крайней мере 10 MB.
innodb_mirrored_log_groupsЧисло идентичных копий файла регистрации групп, которые мы храним для базы данных. В настоящее время это должно быть установлено в 1.
innodb_log_group_home_dirПуть к журналам InnoDB.
innodb_log_files_in_groupЧисло журналов в группе файла регистрации.. InnoDB обеспечивает ротацию журналов. Рекомендуется использовать значение 3.
innodb_log_file_sizeРазмер каждого журнала в файле регистрации групп в мегабайтах. Разумные значения располагаются от 1M до размера буферного пула, определенного ниже. Чем больше значение, тем меньше будет число контрольных точек сброса данных в буферном пуле, что уменьшит медленный дисковый ввод-вывод. Но большие журналы также означают, что восстановление будет медленнее в случае аварийного отказа. Ограничение размера файла такое же, что и у файла данных.
innodb_log_buffer_sizeРазмер буфера, который InnoDB использует, чтобы писать файлы регистрации на диск. Разумные значения располагаются от 1M до половины объединенного размера журналов. Большой буфер файлов регистрации позволяет большим транзакциям выполняться без необходимости писать файл регистрации на диск, пока транзакция не закончится. Таким образом, если Вы имеете большие транзакции, увеличение буфера файла регистрации уменьшит медленный дисковый ввод-вывод.
innodb_flush_log_at_trx_commitОбычно это установлено в 1, означая, что при выполнении транзакции файл регистрации будет сброшен на диск, модификации, сделанные транзакцией, станут постоянными, что позволит им благополучно пережить аварийный отказ базы данных. Если Вы желаете отменить это ограничение, и Вы управляете маленькими транзакциями, Вы можете устанавливать это значение в 0, чтобы уменьшить медленный дисковый ввод-вывод файлов регистрации, но это опасно.
innodb_log_arch_dirКаталог, где будут находиться архивы журналов протоколирования, если Вы использовали архивирование файла регистрации. Значение этого параметра должно в настоящее время быть установлено так же, как и innodb_log_group_home_dir.
innodb_log_archiveЭто значение должно быть в настоящее время установлено в 0. Поскольку восстановление из копии выполняется MySQL с использованием собственных журналов, в настоящее время не имеется никакой потребности архивировать журналы InnoDB.
innodb_buffer_pool_sizeРазмер памяти для буфера InnoDB, используемого, чтобы кэшировать данные и индексы таблиц. Увеличение буфера снижает медленные дисковые операции, необходимые, чтобы обратиться к данным в таблицах. На специализированном сервере базы данных Вы можете поднять этот параметр до 90% от физического размера памяти компьютера. Но не увлекайтесь этим, чтобы не вызывать своп памяти на диск. Он уж точно замедлит все работы сервера!
innodb_additional_mem_pool_sizeРазмер памяти, используемой InnoDB, чтобы сохранить информацию словаря данных и другие внутренние структуры данных. Разумное значение для этого могло бы быть 2M, но чем больше таблиц используется, тем больше должен быть этот буфер. Если InnoDB исчерпает память в этом буфере, он начнет распределять память из операционной системы и будет писать предупреждающие сообщения в файл регистрации ошибок MySQL.
innodb_file_io_threadsЧисло потоков ввода-вывода для файлов в InnoDB. Обычно это должно быть 4, но на Windows NT стоит увеличить значение.
innodb_lock_wait_timeoutВремя ожидания в секундах, которое транзакция InnoDB может ждать блокировку прежде, чем выполнить возврат. InnoDB автоматически обнаруживает тупики транзакции в собственной таблице блокировки и прокручивает транзакцию назад. Если Вы используете команду LOCK TABLES или другие транзакционно-безопасные драйверы таблицы вместе с InnoDB в той же самой транзакции, то может возникнуть тупик, на который InnoDB не сможет обратить внимание. В таких случаях время ожидания может решить проблему.
innodb_flush_method (доступно с версии 3.23.40 и выше) Значение по умолчанию для этого: fdatasync. Другая опция: O_DSYNC.

7.6.3 Создание пространства таблиц InnoDB

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

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

~/mysqlm/sql > mysqld
InnoDB: The first specified data file /home/heikki/data/ibdata1 did not exist:
InnoDB: a new database to be created!
InnoDB: Setting file /home/heikki/data/ibdata1 size to 134217728
InnoDB: Database physically writes the file full: wait...
InnoDB: Data file /home/heikki/data/ibdata2 did not exist: new to be created
InnoDB: Setting file /home/heikki/data/ibdata2 size to 262144000
InnoDB: Database physically writes the file full: wait...
InnoDB: Log file /home/heikki/data/logs/ib_logfile0 did not exist: new to be c
reated
InnoDB: Setting log file /home/heikki/data/logs/ib_logfile0 size to 5242880
InnoDB: Log file /home/heikki/data/logs/ib_logfile1 did not exist: new to be c
reated
InnoDB: Setting log file /home/heikki/data/logs/ib_logfile1 size to 5242880
InnoDB: Log file /home/heikki/data/logs/ib_logfile2 did not exist: new to be c
reated
InnoDB: Setting log file /home/heikki/data/logs/ib_logfile2 size to 5242880
InnoDB: Started
mysqld: ready for connections

Новая база данных InnoDB теперь создана. Вы можете соединяться с сервером MySQL обычными программами=клиентами MySQL, например, mysql. Когда Вы завершаете сервер MySQL командой mysqladmin shutdown, InnoDB выведет примерно следующее:

010321 18:33:34  mysqld: Normal shutdown
010321 18:33:34  mysqld: Shutdown Complete
InnoDB: Starting shutdown...
InnoDB: Shutdown completed

Вы теперь можете рассматривать файлы данных и каталоги журналов, там Вы будете видеть созданные файлы. Каталог файлов регистрации будет также содержать маленький файл с именем ib_arch_log_0000000000. Этот файл результирует создание базы данных, после которого InnoDB прекратил архивирование файла регистрации. Когда MySQL снова будет запущен, вывод будет примерно таким:

~/mysqlm/sql > mysqld
InnoDB: Started
mysqld: ready for connections

7.6.3.1 Если что-то идет неправильно в создании базы данных

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

7.6.4 Создание таблиц InnoDB

Предположим, что Вы запустили клиента MySQL командой mysql test. Чтобы создать таблицу в формате InnoDB, Вы должны определить TYPE=InnoDB в команде создания таблицы SQL:

CREATE TABLE CUSTOMER (A INT, B CHAR (20), INDEX (A)) TYPE = InnoDB;

Эта команда SQL создаст таблицу и индекс в столбце A в пространстве таблиц InnoDB, состоящем из файлов данных, которые Вы определили в файле настроек my.cnf. Кроме того, MySQL создаст файл `CUSTOMER.frm' в каталоге баз данных MySQL test. Внутренне, InnoDB добавит к собственному словарю данных запись для таблицы 'test/CUSTOMER'. Таким образом, Вы можете создавать таблицу с тем же самым именем CUSTOMER в другой базе данных MySQL, и имена таблиц не будут сталкиваться внутри InnoDB.

Вы можете сделать запрос количества свободного пространства в пространстве таблиц InnoDB, выдавая команду состояния таблицы MySQL для любой таблицы, которую Вы создали с TYPE=InnoDB. Затем количество свободного места в пространстве таблиц появляется в разделе комментария таблицы в выводе SHOW. Конкретный пример:

SHOW TABLE STATUS FROM test LIKE 'CUSTOMER'

Обратите внимание, что статистика SHOW относительно InnoDB таблиц только приблизительна: она используется в оптимизации SQL. Но зарезервированные размеры таблицы и индекса в байтах точны.

ОБРАТИТЕ ВНИМАНИЕ: DROP DATABASE в настоящее время не работает для InnoDB таблиц! Вы должны удалить таблицы индивидуально. Также соблюдайте осторожность, чтобы не удалить или добавить файлы .frm к Вашей базе данных InnoDB вручную: используйте для этого команды CREATE TABLE и DROP TABLE. InnoDB имеет собственный внутренний словарь данных, и Вы получите проблемы, если MySQL-файлы .frm выйдут из синхронизации с внутренним словарем данных InnoDB.

7.6.4.1 Преобразование таблиц MyISAM в InnoDB

InnoDB не имеет специальной оптимизации для отдельного создания индексов. Самый быстрый способ изменять таблицу к InnoDB состоит в том, чтобы делать вставки непосредственно в таблицу InnoDB, то есть использовать команду ALTER TABLE ... TYPE=INNODB или создать пустую таблицу InnoDB с идентичными определениями и вставлять в нее строки с помощью команды INSERT INTO ... SELECT * FROM ....

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

INSERT INTO newtable SELECT * FROM oldtable WHERE yourkey > something AND
                                   yourkey <= somethingelse;

После того, как все данные были вставлены, Вы можете переименовать таблицы.

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

Удостоверьтесь, что Вы не исчерпаете пространство таблиц: InnoDB-базы берут намного больше места, чем таблицы MyISAM. Если ALTER TABLE исчерпает место, это запустит обратную перемотку, что может занять несколько часов при дисковых операциях! Во вставках InnoDB использует буфер вставок, чтобы объединить вторичные индексные записи на индексы в пакетах. Это экономит много операций дискового ввода-вывода. В обратной перемотке никакой такой механизм не используется, и она запросто может быть в 30 раз более длинной, чем вставка.

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

7.6.5 Добавление и удаление данных и журналов InnoDB

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

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

Если Вы хотите изменять число или размер журналов InnoDB, Вы должны закрыть MySQL и удостовериться, что все закрывается без ошибок. Затем скопируйте старые журналы в безопасное место, на всякий случай (если что-то пошло неправильно в закрытии системы, и Вы будете нуждаться в них, чтобы восстановить базу данных). Удалите старые журналы из каталога журналов, отредактируйте файл настроек my.cnf и запустите MySQL снова. InnoDB сообщит Вам при запуске, что создает новые журналы.

7.6.6 Резервирование и восстановление баз данных InnoDB

Для создания двоичной копии Вашей базы данных, Вы должны делать следующее:

  • Закройте Вашу базу данных MySQL и удостоверьтесь, что она закрывается без ошибок.
  • Скопируйте все Ваши файлы данных в безопасное место.
  • Скопируйте все Ваши журналы InnoDB в безопасное место.
  • Скопируйте Ваш файл конфигурации my.cnf в безопасное место (если файлов несколько, надо скопировать все).
  • Скопируйте все файлы `.frm' для таблиц InnoDB в безопасное место.

В настоящее время нет никакого интерактивного или инкрементного резервного инструмента, доступного для InnoDB, хотя они находятся в списке TODO.

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

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

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

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

~/mysqlm/sql > 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

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

7.6.6.1 Контрольные точки

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

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

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

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

7.6.7 Перемещение баз данных InnoDB на другую машину

Данные и журналы InnoDB двоично-совместимы на всех платформах, если формат чисел с плавающей запятой на машинах тот же самый. Вы можете перемещать базу данных InnoDB просто копируя все релевантные файлы, которые мы уже напечатали в предыдущем разделе по поддержке базы данных. Если форматы чисел с плавающей запятой на машинах различны, но Вы не использовали в Ваших таблицах типы данных FLOAT или DOUBLE, процедура такая же: только копируйте релевантные файлы. Если форматы различные, и Ваши таблицы содержат данные с плавающей запятой, Вы должны использовать mysqldump и mysqlimport, чтобы переместить эти таблицы.

7.6.8 Модель транзакций InnoDB

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

В InnoDB все действия пользователя выполняются внутри транзакции. Если в MySQL используется режим auto commit, то каждая инструкция SQL формирует одиночную транзакцию. Если этот режим выключен, то мы можем думать, что пользователь всегда имеет транзакцию открытой. Если он выдает SQL-инструкцию COMMIT или ROLLBACK, которая заканчивает текущую транзакцию, новая будет запущена. Обе инструкции выпустят все блокировки InnoDB, которые были установлены в течение текущей транзакции. COMMIT означает, что изменения, сделанные в текущей транзакции, стали постоянными и будут видимы другим пользователям. С другой стороны, ROLLBACK отменяет все модификации, сделанные текущей транзакцией.

7.6.8.1 Непротиворечивое чтение

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

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

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

7.6.8.2 Блокировка чтения

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

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

Решение состоит в том, чтобы выполнить SELECT в режиме блокировки, LOCK IN SHARE MODE.

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

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

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

В этом случае имеются два хороших способа выполнить чтение и приращение счетчика: (1) модифицировать счетчик сначала, увеличивая его на 1, и только после того, как он будет прочитан, или (2) читать счетчик сначала с режимом блокировки FOR UPDATE и обновлять после этого:

SELECT COUNTER_FIELD FROM CHILD_CODES FOR UPDATE;
UPDATE CHILD_CODES SET COUNTER_FIELD = COUNTER_FIELD + 1;

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

7.6.8.3 Блокировка со следующим ключом: уход от проблемы фантома

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

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

SELECT * FROM CHILD WHERE ID > 100 FOR UPDATE;

Предположим, что имеется индекс на таблице, CHILD на столбце ID. Мой запрос просмотрит тот индекс, начиная с первой записи, где ID больший, чем 100. Теперь, если бы набор блокировок на индексных записях не блокировал бы вставки, сделанные в промежутках, новая запись могла бы быть тем временем вставлена в таблицу. Если теперь я в моей транзакции выполняю запрос:

SELECT * FROM CHILD WHERE ID > 100 FOR UPDATE;

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

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

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

7.6.8.4 Блокировка наборов разных инструкций в InnoDB

  • SELECT ... FROM ...: непротиворечивое чтение, читает образ базы данных и не устанавливает никаких блокировок.
  • SELECT ... FROM ... LOCK IN SHARE MODE: устанавливает общедоступную блокировку следующего ключа на всех индексных записях.
  • SELECT ... FROM ... FOR UPDATE: устанавливает исключительные блокировки следующего ключа на всем индексе.
  • INSERT INTO ... VALUES (...): устанавливает исключительную блокировку на вставленной строке; обратите внимание, что эта блокировка не является блокировкой следующего ключа и дает другим пользователям делать вставки на промежутке перед вставленной строкой. Если происходит двойная ошибка ключа, устанавливает общедоступную блокировку на дублированной индексной записи.
  • INSERT INTO T SELECT ... FROM S WHERE ... устанавливает исключительную блокировку (non-next-key) на каждой строке, вставленной в T. Делает поиск на S как непротиворечивое чтение, но устанавливает общедоступные блокировки со следующим ключом на S, если включена регистрация MySQL. InnoDB должен в последнем случае установить блокировки потому, что при восстановлении из копии каждая инструкция SQL должна быть выполнена точно так же, как и в первый раз.
  • CREATE TABLE ... SELECT ... выполняет SELECT как непротиворечивое чтение или с общедоступными блокировками, как это показано в предыдущем элементе.
  • REPLACE будет выполнена подобно вставке, если не имеется никакой проверки на пересечение по уникальному ключу. Иначе, исключительная блокировка на следующем ключе будет применена к строке, которая должна модифицироваться.
  • UPDATE ... SET ... WHERE ...: устанавливает исключительную блокировку следующего ключа на каждой записи, с которой сталкивается поиск.
  • DELETE FROM ... WHERE ...: устанавливает исключительную блокировку следующего ключа на каждой записи, с которой сталкивается поиск.
  • LOCK TABLES ... : устанавливает блокировки таблицы. В реализации MySQL уровень кода устанавливает эти блокировки. Автоматическое обнаружение тупиков InnoDB не может обнаружить тупики, где включаются такие блокировки таблицы. С тех пор как MySQL знает относительно блокировок уровня строки, возможно, что Вы получаете блокировку таблицы на таблице, где другой пользователь в настоящее время имеет блокировки уровня строки. Но это не помещает целостности транзакции.

7.6.8.5 Обнаружение тупиков и обратная перемотка

InnoDB автоматически обнаруживает тупик транзакции и откатывает ту транзакцию, чей запрос блокировки был последним при формировании тупика, то есть цикл в графе ожидания транзакций. InnoDB не может обнаружить тупики, где набор блокировок включается MySQL-инструкцией LOCK TABLES, или если набор блокировок включается в другом драйвере таблицы. Вы должны решить эти ситуации, используя параметр innodb_lock_wait_timeout в my.cnf.

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

7.6.8.6 Пример того, как непротиворечивое чтение работает в InnoDB

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

Вы можете передвигать Ваш timepoint, завершая Вашу транзакцию и затем делая другой SELECT.

Это названо мультиверсионным управлением параллелизма.

               Пользователь A         Пользователь B

              set autocommit=0;      set autocommit=0;
Время
|             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   |
              ----------------------

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

Если Вы хотите видеть самое новое состояние базы данных, Вы должны использовать чтение блокировки:

SELECT * FROM t LOCK IN SHARE MODE;

7.6.9 Советы по настройке эффективности работы

1. Если Unix top или Windows Task Manager показывает, что процент использования CPU с Вашей рабочей нагрузкой меньше, чем 70%, нагрузка, вероятно, связана диском. Возможно, Вы делаете слишком много транзакций, или буфер слишком маленький. Увеличение буфера может помочь, но не устанавливайте его большим, чем 80% физической памяти машины.

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

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

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

5. Буфер файлов регистрации должен быть большой, хотя бы 8 MB.

6. (Применимо с версии 3.23.39 и выше) В некоторых версиях Linux и Unix, сброс файлов на диск вызовом Unix fdatasync и другими подобными методами происходит очень медленно. Заданный по умолчанию метод InnoDB: функция fdatasync. Если Вы не удовлетворены этим, можете попробовать устанавливать innodb_flush_method в файле my.cnf в значение O_DSYNC, хотя O_DSYNC медленнее на большинстве систем.

7. В импортировании данных в InnoDB удостоверьтесь, что MySQL не имеет настройки autocommit=1. Каждая вставка требует сброса протокола на диск. Так что установите перед импортируемыми данными в своем файле строку:

set autocommit=0;

а после них строку:

commit;

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

8. Остерегайтесь больших обратных перемоток массовых вставок: InnoDB использует буфер вставок, чтобы уменьшить медленный дисковый ввод-вывод во вставках, но в соответствующей обратной перемотке, такой механизм не используется. Связанная с диском обратная перемотка может занять в 30 раз больше времени, чем соответствующие вставки. Уничтожение процесса базы данных тут не будет помогать потому, что обратная перемотка начнется снова при запуске базы данных. Единственный способ избавиться от взбесившейся обратной перемотки состоит в том, чтобы увеличить буфер так, чтобы обратная перемотка стала ограничена только CPU и выполнилась быстро, или удалить целую базу данных InnoDB.

9. Остерегайтесь также других больших, связанных с диском, операций. Используйте DROP TABLE или TRUNCATE (в MySQL-4.0 и выше), чтобы освободить таблицу, а не DELETE FROM yourtable.

10. Используйте многострочный INSERT, чтобы уменьшить трафик между клиентом и сервером при вставке нескольких строк:

INSERT INTO yourtable VALUES (1, 2), (5, 5);

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

7.6.9.1 Монитор InnoDB

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

  • Блокировки записей и таблиц, задержанные каждой активной транзакцией,
  • Блокировки, ожидающие транзакций,
  • Семафоры, ожидающие потоков,
  • Ждущие обработки запросы ввода-вывода файлов,
  • Статистика по буферу

Вы можете запустить монитор InnoDB через следующую команду SQL:

CREATE TABLE innodb_monitor(a int) type = innodb;

И остановить его командой:

DROP TABLE innodb_monitor;

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

Типовой вывод монитора InnoDB:

================================
010809 18:45:06 INNODB MONITOR OUTPUT
================================
--------------------------
LOCKS HELD BY TRANSACTIONS
--------------------------
LOCK INFO:
Number of locks in the record hash table 1294
LOCKS FOR TRANSACTION ID 0 579342744
TABLE LOCK table test/mytable trx id 0 582333343 lock_mode IX

RECORD LOCKS space id 0 page no 12758 n bits 104 table test/mytable index
PRIMARY trx id 0 582333343 lock_mode X
Record lock, heap no 2 PHYSICAL RECORD: n_fields 74; 1-byte offs FALSE;
info bits 0
 0: len 4; hex 0001a801; asc ;; 1: len 6; hex 000022b5b39f; asc ";; 2: len 7;
hex 000002001e03ec; asc ;; 3: len 4; hex 00000001;
...
-----------------------------------------------
CURRENT SEMAPHORES RESERVED AND SEMAPHORE WAITS
-----------------------------------------------
SYNC INFO:
Sorry, cannot give mutex list info in non-debug version!
Sorry, cannot give rw-lock list info in non-debug version!
-----------------------------------------------------
SYNC ARRAY INFO: reservation count 6041054, signal count 2913432
4a239430 waited for by thread 49627477 op. S-LOCK file NOT KNOWN line 0
Mut ex 0 sp 5530989 r 62038708 sys 2155035; rws 0 8257574 8025336; rwx 0 1121090 1848344
-----------------------------------------------------
CURRENT PENDING FILE I/O'S
--------------------------
Pending normal aio reads:
Reserved slot, messages 40157658 4a4a40b8
Reserved slot, messages 40157658 4a477e28
...
Reserved slot, messages 40157658 4a4424a8
Reserved slot, messages 40157658 4a39ea38
Total of 36 reserved aio slots
Pending aio writes:
Total of 0 reserved aio slots
Pending insert buffer aio reads:
Total of 0 reserved aio slots
Pending log writes or reads:
Reserved slot, messages 40158c98 40157f98
Total of 1 reserved aio slots
Pending synchronous reads or writes:
Total of 0 reserved aio slots
-----------
BUFFER POOL
-----------
LRU list length 8034
Free list length 0
Flush list length 999
Buffer pool size in pages 8192
Pending reads 39
Pending writes: LRU 0, flush list 0, single page 0
Pages read 31383918, created 51310, written 2985115
----------------------------
END OF INNODB MONITOR OUTPUT
============================
010809 18:45:22 InnoDB starts purge
010809 18:45:22 InnoDB purged 0 pages

Некоторые замечания относительно этого вывода:

  • Если секция LOCKS HELD BY TRANSACTIONS сообщает о ждущих блокировках, то Ваша прикладная программа может иметь тупик блокировки. Вывод может также помочь прослеживать причины тупиков транзакции.
  • Секция SYNC INFO сообщит зарезервированные семафоры, если Вы компилируете InnoDB с UNIV_SYNC_DEBUG, определенном в univ.i.
  • Раздел SYNC ARRAY INFO сообщает о ждущих потоках и статистику о том, сколько времени потоки ждут на семафорах. Большое число потоков, ждущих на семафорах, может быть результатом дискового ввода-вывода или проблем внутри InnoDB. Эти проблемы могут происходить из-за тяжелого параллелизма запросов или трудностей в планировании потоков внутри операционной системы.
  • Раздел CURRENT PENDING FILE I/O'S перечисляет запросы, ждущие ввода-вывода файлов. Большое количество их указывает, что рабочая нагрузка представляет собой дисковый ввод-вывод.
  • Раздел BUFFER POOL дает Вам статистику о чтении и записи страниц. Вы можете вычислять из этих чисел, сколько файлового ввода-вывода в настоящее время делают Ваши запросы.

7.6.10 Поддержка мультиверсионной обработки

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

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

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

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

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

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

7.6.11 Структуры таблицы и индекса

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

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

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

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

7.6.11.1 Физическая структура индекса

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

Если индексные записи вставлены в последовательном (возрастающем или убывающем) порядке, возникающие в результате индексные страницы будут относительно полными (15/16). Если записи вставлены в произвольном порядке, то страницы будут заполнены на 1/2-15/16. Если уровень заполнения (fillfactor) индексных страниц ниже 1/2, InnoDB пробует перестроить индексное дерево, чтобы освободить страницу.

7.6.11.2 Буферизация вставки

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

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

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

Буфер вставок периодически объединяется с вторичными индексными деревьями в базе данных. Часто мы можем объединять несколько вставок на той же самой странице индексного дерева и, следовательно, экономить медленный дисковый ввод-вывод. Доказано на практике, что буфер вставок может ускорять вставки в таблицу до 15 раз.

7.6.11.3 Адаптивные хэшируемые индексы

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

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

7.6.11.4 Физическая структура записей

  • Каждая индексная запись в InnoDB содержит 6 байтов. Он используется, чтобы связать последовательные записи вместе, а также в блокировке уровня строки.
  • Записи в сгруппированном индексе содержат поля для всех определяемых пользователем столбцов. Кроме того, имеется поле с 6 байтами для идентификатора транзакции и поле с 7 байтами для указателя прокрутки.
  • Если пользователь не определил первичный ключ для таблицы, то каждая запись в сгруппированном индексе содержит также поле идентификатора строки с 6 байтами.
  • Каждая вторичная индексная запись также содержит все поля, определенные для сгруппированного индексного ключа.
  • Запись содержит также указатель на каждое поле записи. Если общая длина полей в записи < 128 байтов, то указатель равен 1 байту, иначе он будет всегда равен 2 байтам.

7.6.11.5 Как столбец с автоприращением работает в InnoDB

После запуска базы данных, когда пользователь делает вставку в таблицу T, где был определен столбец с автоприращением, и пользователь не задает явное значение для столбца, InnoDB выполняет SELECT MAX(auto-inc-column) FROM T и назначает полученное значение, увеличенное на один, столбцу и счетчику автоприращеня. Мы говорим, что счетчик для таблицы T с автоприращением был инициализирован.

Обратите внимание, что, если пользователь определяет во вставке значение 0 столбцу с автоприращением, то InnoDB обрабатывает строку так, как если бы значение не было определено вообще.

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

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

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

7.6.12 Управление файлами и диском

7.6.12.1 Дисковый ввод-вывод

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

В Windows NT InnoDB использует небуферизированный ввод-вывод. Это означает, что страницы, которые InnoDB читает или пишет, не будут буферизированы в кэше файлов операционной системы.

Начиная с версии 3.23.41, InnoDB использует новую методику сброса файлов, названную doublewrite. Это добавляет безопасности при сбоях, улучшает эффективность на большинстве разновидностей Unix и уменьшает потребность в операциях типа fsync.

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

Начиная с версии 3.23.41, Вы можете также использовать необработанный дисковый раздел как файл данных, хотя это пока не было проверено. Когда Вы создаете новый файл данных, Вы должны поместить ключевое слово newraw сразу после размера файла данных в innodb_data_file_path. Раздел должен быть >= того, что Вы определили как размер. Обратите внимание, что 1M в InnoDB честно равен 1024x1024 байт, в то время как в дисковых спецификациях 1М как правило означает всего лишь 1000000 байт.

innodb_data_file_path=hdd1:3Gnewraw;hdd2:2Gnewraw

Когда Вы запускаете базу данных снова, Вы ДОЛЖНЫ изменить ключевое слово на raw. Иначе InnoDB будет писать поверх Вашего раздела!

innodb_data_file_path=hdd1:3Graw;hdd2:2Graw

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

7.6.12.2 Управление местом в файлах

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

Пространство таблиц состоит из базы данных страниц, чей заданный по умолчанию размер равен 16 КБ. Страницы сгруппированы в юлоки по 64 страницы. Файлы внутри пространства таблиц названы сегментами в InnoDB. Имя сегмента обратной перемотки несколько вводит в заблуждение потому, что он фактически хранит много сегментов в пространстве таблиц.

Для каждого индекса в InnoDB мы распределяем два сегмента: первый для узлов листьев B-дерева, второй для безлистных узлов.

Когда сегмент растет внутри пространства таблиц, InnoDB распределяет первые 32 страницы для него индивидуально. После этого InnoDB начинает распределять целые сегменты. InnoDB может добавлять к большому сегменту до 4 блоков страниц одновременно, чтобы гарантировать хорошую последовательность всех данных в нем.

Когда Вы выдаете запрос SHOW TABLE STATUS FROM ... LIKE ..., чтобы спросить о доступном свободном месте в пространстве таблиц, InnoDB сообщит о месте, которое является пригодным для использования в полностью свободных сегментах пространства таблиц. InnoDB всегда резервирует некоторые сегменты для уборки и других внутренних целей, это зарезервированное место не будет включено в свободное пространство.

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

7.6.12.3 Дефрагментация таблицы

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

Можно ускорить индексные просмотры, если Вы периодически используете mysqldump для сброса дампа таблицы в текстовый файл, удаляете таблицу и перезагружаете ее из дампа. Другой способ сделать дефрагменатцию состоит в том, чтобы сменить командой ALTER тип таблицы на MyISAM, а потом опять на InnoDB. Обратите внимание, что таблица типа MyISAM должна расположиться в одном файле на Вашей операционной системе.

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

7.6.13 Обработка ошибок

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

  • Если Вы исчерпаете место в файле пространства таблиц, получите ошибку MySQL 'Table is full', и InnoDB отменит инструкцию SQL.
  • Тупик транзакции или окончание времени ожидания в блокировке даст ошибку 'Table handler error 1000000', и InnoDB отменит инструкцию SQL.
  • Дублирование ключа только отменит вставку этой специфической строки, даже в инструкции подобной INSERT INTO ... SELECT ....
  • Ошибка row too long отменит инструкцию SQL.
  • Другие ошибки обычно бывают обнаружены уровнем кода MySQL, и они отменяют соответствующую инструкцию SQL.

7.6.14 Ограничения таблиц InnoDB

  • SHOW TABLE STATUS не дает точную статистику на таблицах InnoDB, кроме физического размера, зарезервированного таблицей. Число строк только грубая оценка, используемая в оптимизации SQL.
  • Если Вы пробуете создавать уникальный индекс на префиксе столбца, Вы получите ошибку:
    CREATE TABLE T (A CHAR(20), B INT, UNIQUE (A(5))) TYPE = InnoDB;
    
    Если Вы создаете неуникальный индекс на префиксе столбца, InnoDB создаст индекс над целым столбцом.
  • INSERT DELAYED не поддерживается для таблиц InnoDB.
  • Операция MySQL LOCK TABLES не знает о InnoDB блокировках уровня строки. Это означает, что Вы можете получать блокировку уровня таблицы на таблице, даже если там все еще существуют транзакции других пользователей, которые имеют блокировки уровня строки на той же самой таблице. Таким образом, Вашим операциям на этой таблице, вероятно, придется ждать, если они сталкиваются с этими блокировками других пользователей. Также возможен тупик. Однако, это не подвергает опасности целостность транзакции потому, что набор блокировок уровней строк InnoDB будет всегда заботиться о целостности. Также блокировка уровня таблицы защищает другие транзакции от приобретения большого количества блокировок уровня строки (в противоречивом режиме блокировки) на конкретной таблице.
  • Вы не можете иметь никаких индексов на столбцах типов BLOB или TEXT.
  • Таблица не может содержать больше, чем 1000 столбцов.
  • DELETE FROM TABLE не регенерирует таблицу, но взамен удаляет все строки одну за другой, что куда медленнее. В будущих версиях MySQL Вы сможете использовать вызов TRUNCATE, который является быстрым.
  • Перед удалением базы данных с таблицами InnoDB надо сначала удалить каждую таблицу отдельно.
  • Заданная по умолчанию база данных имеет размер страницы в InnoDB 16 КБ. Перетранслируя код можно устанавливать от 8 КБ до 64 КБ. Максимальная длина строки немного меньше, чем половина страницы в версиях InnoDB <=3.23.40. Начиная с исходников 3.23.41, столбцы типов BLOB и TEXT могут быть <4 GB, общая длина строки должна также быть <4 GB. InnoDB не сохраняет поля, чей размер <=30 байтов на отдельных страницах.
  • Максимальная длина данных или журнала 2 или 4 GB в зависимости от того, насколько большие файлы поддерживает Ваша операционная система. Поддержка для файлов размером > 4 GB будет добавлена к InnoDB в будущей версии.
  • Максимальный размер пространства таблиц равен 4 миллиардам страниц базы данных. Это также максимальный размер для таблицы. Минимальный размер пространства таблиц равен 10 MB.

7.6.15 Контактная информация для InnoDB

Автором и разработчиком InnoDB является Innobase Oy Website: http://www.innodb.com. Email: Heikki.Tuuri@innodb.com.

phone: 358-9-6969 3250 (office) 358-40-5617367 (mobile)
InnoDB Oy Inc.
World Trade Center Helsinki
Aleksanterinkatu 17
P.O.Box 800
00101 Helsinki
Finland

Поиск

 

Найди своих коллег!