| |
Начиная с 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):
ROLLBACK
, чтобы игнорировать внесенные
изменения (если Вы не работаете в режиме auto commit).
Преимущества транзакционно-небезопасных таблиц (transaction-safe tables, NTST):
Вы можете объединять TST и NTST таблицы в одних и тех же инструкциях.
Таблицы 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 появляется как подкаталог.
Начиная с 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 . |
Предположим, что Вы установили 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
Если что-то идет неправильно в создании базы данных InnoDB, Вы должны удалить все файлы, созданные InnoDB. Это означает все файлы данных, журналы, маленький сархивированный журнал, и в случае, если Вы уже создавали таблицы InnoDB, также соответствующие файлы .frm для этих таблиц из каталогов баз данных MySQL. Затем Вы можете попробовать создание базы данных 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.
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, после чего начали работу снова. Это выйдет быстрее, чем ждать миллионы дисковых вводов-выводов.
Вы не можете увеличивать размер файла данных InnoDB. Чтобы добавлять
больше места в пространство таблиц, Вы должны добавить новый файл данных.
Чтобы сделать это, Вы должны закрыть Вашу базу данных MySQL, отредактировать
файл настроек my.cnf, добавляя новый файл к
innodb_data_file_path
, и затем снова запустить MySQL.
В настоящее время Вы не можете удалять файл данных из InnoDB. Чтобы
уменьшить размер вашей базы данных, Вы должны использовать
mysqldump
для изготовления дампа всех Ваших таблиц, создать
новую базу данных и импортировать Ваши таблицы в новую базу данных.
Если Вы хотите изменять число или размер журналов InnoDB, Вы должны закрыть MySQL и удостовериться, что все закрывается без ошибок. Затем скопируйте старые журналы в безопасное место, на всякий случай (если что-то пошло неправильно в закрытии системы, и Вы будете нуждаться в них, чтобы восстановить базу данных). Удалите старые журналы из каталога журналов, отредактируйте файл настроек my.cnf и запустите MySQL снова. 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
Если Ваша база данных получает разрушение или есть дисковые сбои, Вы должны делать восстановление из копии. В случае искажения Вы должны сначала найти копию, которая не разрушена.
InnoDB реализует механизм контрольной точки, названный размытой контрольной точкой. InnoDB сбрасывает страницы изменяемой базы данных из буфера маленькими блоками, так что нет смысла выполнять сброс единым блоком, что надолго затормозит работу.
При восстановлении после аварийного отказа InnoDB ищет контрольную точку, отмеченную в журнале. InnoDB знает, что все модификации базы данных перед меткой уже представлены в дисковом образе. Затем InnoDB просматривает журналы вперед с места контрольной точки, применяя регистрируемые модификации.
InnoDB пишет журналы с учетом ротации. Все совершенные модификации, которые делают страницы базы данных в буфере отличными от образов на диске, должны быть доступны в журналах в случае, если InnoDB должен делать восстановление. Это означает, что, когда InnoDB начинает использовать новый журнал по схеме ротации, он должен удостовериться, что база данных на диске уже содержит все модификации. Другими словами, InnoDB должен делать контрольную точку, и часто это включает сброс изменяемой страницы базы данных на диск.
Вышеупомянутое объясняет, почему создание Ваших журналов очень большими может экономить дисковый ввод-вывод при введении контрольных точек. Может иметь смысл устанавливать полный размер журналов столь же большим, как буфер, или даже больше. Недостаток больших журналов в том, что восстановление после аварийного отказа может длиться долго потому, что будет присутствовать больший объем файла регистрации нужный, чтобы обратиться к базе данных.
Данные и журналы InnoDB двоично-совместимы на всех платформах, если формат
чисел с плавающей запятой на машинах тот же самый. Вы можете перемещать базу
данных InnoDB просто копируя все релевантные файлы, которые мы уже напечатали
в предыдущем разделе по поддержке базы данных. Если форматы чисел с плавающей
запятой на машинах различны, но Вы не использовали в Ваших таблицах типы
данных FLOAT
или DOUBLE
, процедура такая же: только
копируйте релевантные файлы. Если форматы различные, и Ваши таблицы содержат
данные с плавающей запятой, Вы должны использовать mysqldump и
mysqlimport, чтобы переместить эти таблицы.
В модели транзакции InnoDB цель была в том, чтобы объединить самые лучшие стороны мультиверсионной базы данных и традиционной блокировки с двумя фазами. Блокировка InnoDB работает на уровне строк и по умолчанию выполняет запросы чтения без блокировки, поскольку они обрабатываются непротиворечиво, в стиле Oracle. Таблица блокировки в InnoDB сохранена настолько компактно, что увеличение блокировки не нужно: обычно нескольким пользователям позволяют блокировать каждую строку в базе данных или любом произвольном подмножестве строк, без проблем с памятью у InnoDB.
В InnoDB все действия пользователя выполняются внутри транзакции. Если в
MySQL используется режим auto commit, то каждая инструкция SQL формирует
одиночную транзакцию. Если этот режим выключен, то мы можем думать, что
пользователь всегда имеет транзакцию открытой. Если он выдает SQL-инструкцию
COMMIT
или ROLLBACK
, которая заканчивает текущую
транзакцию, новая будет запущена. Обе инструкции выпустят все блокировки
InnoDB, которые были установлены в течение текущей транзакции.
COMMIT
означает, что изменения, сделанные в текущей транзакции,
стали постоянными и будут видимы другим пользователям. С другой стороны,
ROLLBACK
отменяет все модификации, сделанные текущей транзакцией.
Непротиворечивое чтение означает, что InnoDB использует поддержку разных версий, чтобы представить к запросу образ базы данных в некоторый момент времени. Запрос будет видеть изменения, сделанные точно теми транзакциями, которые совершились перед этой отметкой времени, и никаких изменений, сделанных позже или нейтральными транзакциями. Исключительная ситуация к этому правилу: запрос будет видеть изменения, сделанные транзакцией, которая выдает этот запрос.
Когда транзакция выдает первое непротиворечивое чтение, InnoDB назначает образ или отметку времени, которую использует все непротиворечивое чтение в той же самой транзакции. В образе будут отображены все транзакции, которые совершились перед его назначением. Таким образом, непротиворечивое чтение внутри той же самой транзакции, будет также непротиворечивым относительно нее. Вы можете получать более свежий образ для Ваших запросов, завершая текущую транзакцию и выдавая после этого новые запросы.
Непротиворечивое чтение представляет собой заданный по умолчанию режим, в
котором InnoDB обрабатывает инструкции SELECT
. Непротиворечивое
чтение не устанавливает никаких блокировок на таблицах, к которым обращается,
и, следовательно, другие пользователи свободны в их изменении в то же время.
Непротиворечивое чтение неудобно в некоторых обстоятельствах. Предположим,
что Вы хотите добавлять новую строку в вашу таблицу, 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
для строк.
На уровне строки блокировка 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.
Вы можете использовать блокировку следующего ключа, чтобы обеспечить уникальность регистрации Вашей прикладной программы: если Вы читаете Ваши данные в общем режиме и не смотрите дубликат для строки, которую Вы собираетесь вставлять, затем Вы можете безопасно вставлять Вашу строку и знать, что набор блокировок на преемнике Вашей строки в течение чтения предотвратит вставку дубликата для Вашей строки.
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 знает относительно блокировок уровня
строки, возможно, что Вы получаете блокировку таблицы на таблице, где другой
пользователь в настоящее время имеет блокировки уровня строки. Но это не
помещает целостности транзакции.InnoDB автоматически обнаруживает тупик транзакции и откатывает ту
транзакцию, чей запрос блокировки был последним при формировании тупика, то
есть цикл в графе ожидания транзакций. InnoDB не может обнаружить тупики, где
набор блокировок включается MySQL-инструкцией LOCK TABLES
, или
если набор блокировок включается в другом драйвере таблицы. Вы должны решить
эти ситуации, используя параметр innodb_lock_wait_timeout
в
my.cnf.
Когда InnoDB выполняет полную обратную перемотку транзакции, все блокировки транзакции будут сняты. Однако, если обратно в результате ошибки прокручена только одна инструкция SQL, часть этого набора блокировок может сохраниться, что не снимет весь набор блокировок.
Когда Вы устанавливаете непротиворечивое чтение, то есть выдаете обычную
инструкцию 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;
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.
Начиная с версии 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
Некоторые замечания относительно этого вывода:
UNIV_SYNC_DEBUG
, определенном в univ.i.
InnoDB внутренне добавляет два поля к каждой строке, сохраненной в базе данных. Поле с 6 байтами сообщает идентификатор транзакции для последней транзакции, которая вставила или модифицировала строку. Также стирание внутренне обрабатывается как модификация, где будет установлен специальный бит в строке, чтобы отметить ее как удаленную. Каждая строка также содержит поле с 7 байтами, называемое указателем прокрутки. Он указывает на файл регистрации отмены, записываемый в сегмент обратной перемотки. Если строка модифицировалась, то запись файла регистрации отмены содержит информацию, необходимую, чтобы восстановить содержание строки.
InnoDB использует информацию в сегменте обратной перемотки, чтобы выполнить операции отмены, необходимые в обратной перемотке транзакции. InnoDB также применяет эту информацию, чтобы формировать более ранние версии строки для непротиворечивого чтения.
Файл регистрации отмены в сегменте обратной перемотки разделен на протоколы вставки и модификации. Протокол вставки необходим только в обратной перемотке транзакции и может быть отброшен, как только транзакция завершена. Протокол модификации используется также в непротиворечивом чтении и может быть отброшен, как только в нем исчезнет надобность (не будет транзакций, которым надо на его основе формировать более раннюю версию строки).
Вы должны не забыть регулярно закрывать Ваши транзакции. Иначе InnoDB не сможет отбрасывать данные из файлов регистрации отмены модификации, и сегмент обратной перемотки может стать слишком большим, заполняя пространство таблиц.
Физический размер записи файла регистрации отмены в сегменте обратной перемотки обычно меньший, чем соответствующая вставленная или модифицируемая строка. Вы можете использовать эту информацию, чтобы вычислить потребность в свободном месте в сегменте обратной перемотки.
В такой мультиверсионной схеме строка физически не будет удалена из базы данных немедленно, когда Вы удаляете ее инструкцией SQL. Только когда InnoDB сможет отбросить запись файла регистрации отмены модификации, написанную для стирания, он также сможет физически удалить соответствующую строку и индексные записи из базы данных. Эта операция удаления названа очисткой, и выполняется она очень быстро.
Каждая таблица InnoDB имеет специальный индекс, названный сгруппированным
индексом, где сохранены данные строк. Если Вы определяете PRIMARY
KEY
на Вашей таблице, то индексом первичного ключа будет как раз
именно сгруппированный индекс.
Если Вы не определяете первичный ключ для Вашей таблицы, InnoDB внутренне генерирует сгруппированный индекс, где строки упорядочиваются по идентификаторам, которые InnoDB назначает строкам в такой таблице. Идентификатор строки представляет собой поле с 6 байтами, которое увеличивается по мере вставки новых строк. Таким образом, строки будут упорядочены физически в порядке их вставки.
Обращение к строке через сгруппированный индекс быстро потому, что данные строки будут на той же самой странице, где завершился индексный поиск. Во многих БД данные традиционно сохранены на другой странице. Если таблица большая, сгруппированная индексная архитектура часто здорово уменьшает медленный дисковый ввод-вывод, когда она сравнивается с традиционным решением.
Записи в несгруппированных индексах (они же вторичные индексы) в InnoDB содержат значение первичного ключа для строки. InnoDB использует это значение ключа, чтобы искать строку из сгруппированного индекса. Обратите внимание, что, если первичный ключ длинный, вторичные индексы используют большее количество места в памяти.
Все индексы в InnoDB представляют собой B-деревья, где индексные записи сохранены в листе страницы дерева. Заданный по умолчанию размер индексной страницы равен 16 kB. Когда новые записи вставлены, InnoDB пробует оставлять 1/16 страницы свободной для будущих вставок и модификации индексных записей.
Если индексные записи вставлены в последовательном (возрастающем или убывающем) порядке, возникающие в результате индексные страницы будут относительно полными (15/16). Если записи вставлены в произвольном порядке, то страницы будут заполнены на 1/2-15/16. Если уровень заполнения (fillfactor) индексных страниц ниже 1/2, InnoDB пробует перестроить индексное дерево, чтобы освободить страницу.
Нормальной ситуацией в прикладной программе базы данных является то, что первичный ключ представляет собой уникальный идентификатор, и новые строки будут вставлены в порядке возрастания первичного ключа. Таким образом, вставки в сгруппированный индекс не требуют произвольного чтения с диска.
С другой стороны, вторичные индексы обычно неуникальны, и вставки во вторичные индексы выполняются в относительно произвольном порядке. Это вызвало бы много произвольного дискового ввода-вывода без специального механизма, используемого в InnoDB.
Если индексная запись была вставлена в неуникальный вторичный индекс, InnoDB проверит наличие страницы этого индекса в буферном пуле. Если это имеет место, InnoDB будет делать вставку непосредственно в индексную страницу. Но если индексная страница не найдена в буфере, InnoDB вставляет запись в специальную структуру буфера вставки.
Буфер вставок периодически объединяется с вторичными индексными деревьями в базе данных. Часто мы можем объединять несколько вставок на той же самой странице индексного дерева и, следовательно, экономить медленный дисковый ввод-вывод. Доказано на практике, что буфер вставок может ускорять вставки в таблицу до 15 раз.
Если база данных размещена почти полностью в основной памяти, то самый быстрый способ выполнять запросы состоит в том, чтобы использовать хэшируемые индексы. InnoDB имеет автоматический механизм, который контролирует индексные поиски, и если InnoDB обращает внимание, что запросы могли бы работать лучше с хэшируемым индексом, такой индекс будет автоматически сформирован.
Но такой индекс всегда формируется, основываясь на существующем индексе B-дерева таблицы. InnoDB может формировать хэш-индекс на префиксе любой длины ключа, определенного для B-дерева, в зависимости от того, какой образец InnoDB ищет на индексе B-дерева. Хэш-индекс может быть частичным: не требуется, чтобы целый индекс B-дерева кэшировался в буфере. InnoDB будет формировать хэшируемые индексы по требованию к тем страницам индекса, к которым часто обращаются.
После запуска базы данных, когда пользователь делает вставку в таблицу
T
, где был определен столбец с автоприращением, и пользователь
не задает явное значение для столбца, InnoDB выполняет SELECT
MAX(auto-inc-column) FROM T
и назначает полученное значение,
увеличенное на один, столбцу и счетчику автоприращеня. Мы говорим, что
счетчик для таблицы T
с автоприращением был инициализирован.
Обратите внимание, что, если пользователь определяет во вставке значение 0 столбцу с автоприращением, то InnoDB обрабатывает строку так, как если бы значение не было определено вообще.
После того, как счетчик автоприращения был инициализирован, если пользователь вставляет строку, где он явно определяет значение столбца, и это значение больше, чем текущее значение счетчика, он будет установлен в определенное значение столбца. Если пользователь явно не определяет значение, то InnoDB увеличивает счетчик на единицу и назначает новое значение столбцу.
Механизм автоприращения при назначении значений из счетчика обходит блокировки и обработки транзакции. Следовательно, Вы можете получать промежутки в последовательности чисел, если Вы откатываете транзакции, которые применяют числа из счетчика.
Поведение автоприращения не определено, если пользователь задает отрицательное значение столбцу, или если значение становится большим, чем максимальное целое число, которое может быть сохранено в определенном целочисленном типе.
В дисковом вводе-выводе 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 заранее подгружает в буфер ее остатки.
Файлы данных, которые Вы определяете в файле конфигурации, формируют пространство таблиц InnoDB. В настоящее время Вы не можете непосредственно указывать, где именно будут размещены данные. Можно только утверждать, что в пространстве таблиц, начиная с нижнего конца.
Пространство таблиц состоит из базы данных страниц, чей заданный по умолчанию размер равен 16 КБ. Страницы сгруппированы в юлоки по 64 страницы. Файлы внутри пространства таблиц названы сегментами в InnoDB. Имя сегмента обратной перемотки несколько вводит в заблуждение потому, что он фактически хранит много сегментов в пространстве таблиц.
Для каждого индекса в InnoDB мы распределяем два сегмента: первый для узлов листьев B-дерева, второй для безлистных узлов.
Когда сегмент растет внутри пространства таблиц, InnoDB распределяет первые 32 страницы для него индивидуально. После этого InnoDB начинает распределять целые сегменты. InnoDB может добавлять к большому сегменту до 4 блоков страниц одновременно, чтобы гарантировать хорошую последовательность всех данных в нем.
Когда Вы выдаете запрос SHOW TABLE STATUS FROM ... LIKE ...
,
чтобы спросить о доступном свободном месте в пространстве таблиц, InnoDB
сообщит о месте, которое является пригодным для использования в полностью
свободных сегментах пространства таблиц. InnoDB всегда резервирует некоторые
сегменты для уборки и других внутренних целей, это зарезервированное место не
будет включено в свободное пространство.
Когда Вы удаляете данные из таблицы, InnoDB переделает соответствующие индексы B-дерева. В зависимости от ситуации будут освобождены страницы или сегмент. Удаление таблицы или всех строк из нее однозначно освободит место другим пользователям, но помните, что удаленные строки могут быть физически удалены только в операции очистки после того, как они больше не требуются в обратной перемотке транзакции или при непротиворечивом чтении.
Если имеются произвольные вставки или удаления в индексах таблицы, они могут стать фрагментированными. Под фрагментацией мы понимаем, что физическое расположение индексных страниц на диске не соответвует алфавитному расположению записей на страницах, или что имеется много неиспользуемых страниц в блоках с 64 страницами, которые были выделены этому индексу.
Можно ускорить индексные просмотры, если Вы периодически используете
mysqldump
для сброса дампа таблицы в текстовый файл, удаляете
таблицу и перезагружаете ее из дампа. Другой способ сделать дефрагменатцию
состоит в том, чтобы сменить командой ALTER
тип таблицы на
MyISAM
, а потом опять на InnoDB
. Обратите внимание,
что таблица типа MyISAM
должна расположиться в одном файле на
Вашей операционной системе.
Если вставки к индексу всегда делаются в порядке возрастания, и записи удалены только с конца, то алгоритм управления местом в файлах InnoDB гарантирует, что фрагментация в индексе происходить не будет.
Обработка ошибок в InnoDB не всегда такая же, как определяется в ANSI SQL. Согласно стандарту ANSI, любая ошибка в течение инструкции SQL должна вызвать обратную перемотку этой инструкции. InnoDB иногда откатывает только часть инструкции. Следующий список определяет обработку ошибок InnoDB.
'Table is full'
, и InnoDB отменит инструкцию SQL.
'Table handler error 1000000'
, и InnoDB отменит инструкцию SQL.
INSERT INTO ... SELECT ...
.
SHOW TABLE STATUS
не дает точную статистику на таблицах
InnoDB, кроме физического размера, зарезервированного таблицей. Число строк
только грубая оценка, используемая в оптимизации SQL.
CREATE TABLE T (A CHAR(20), B INT, UNIQUE (A(5))) TYPE = InnoDB;Если Вы создаете неуникальный индекс на префиксе столбца, InnoDB создаст индекс над целым столбцом.
INSERT DELAYED
не поддерживается для таблиц InnoDB.
LOCK TABLES
не знает о InnoDB блокировках
уровня строки. Это означает, что Вы можете получать блокировку уровня таблицы
на таблице, даже если там все еще существуют транзакции других пользователей,
которые имеют блокировки уровня строки на той же самой таблице. Таким
образом, Вашим операциям на этой таблице, вероятно, придется ждать, если они
сталкиваются с этими блокировками других пользователей. Также возможен тупик.
Однако, это не подвергает опасности целостность транзакции потому, что набор
блокировок уровней строк InnoDB будет всегда заботиться о целостности. Также
блокировка уровня таблицы защищает другие транзакции от приобретения большого
количества блокировок уровня строки (в противоречивом режиме блокировки)
на конкретной таблице.
BLOB
или TEXT
.
DELETE FROM TABLE
не регенерирует таблицу, но взамен удаляет
все строки одну за другой, что куда медленнее. В будущих версиях MySQL Вы
сможете использовать вызов TRUNCATE
, который является быстрым.
Автором и разработчиком 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
Закладки на сайте Проследить за страницей |
Created 1996-2024 by Maxim Chirkov Добавить, Поддержать, Вебмастеру |