Spec-Zone.ru › MySQL 8.4

17.9.1.5 Как работает сжатие для таблиц InnoDB

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

Алгоритмы сжатия

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

MySQL использует для сжатия хорошо известную библиотеку zlib, которая реализует алгоритм сжатия LZ77. Этот алгоритм зрелый, надёжный и эффективный как в использовании процессора, так и в уменьшении размера данных. Алгоритм является «бесплатным», так что исходные несжатые данные всегда могут быть восстановлены из сжатой формы. LZ77 сжатие работает путем поиска последовательностей данных, которые повторяются в сжимаемых данных. Закономерности значений в ваших данных определяют, насколько хорошо они сжимаются, но типичные пользовательские данные часто сжимаются на 50% или более.

В отличие от сжатия, выполняемого приложением или функциями сжатия некоторых других систем управления базами данных, сжатие InnoDB применяется как к пользовательским данным, так и к индексам. Во многих случаях индексы могут составлять 40-50% или более от общего размера базы данных, поэтому это различие существенно. Когда сжатие хорошо работает для набора данных, размер файлов данных InnoDB (пространство таблиц или .ibd файлы) составляет от 25% до 50% от несжатого размера или, возможно, меньше. В зависимости от этого меньший размер базы данных, в свою очередь, может привести к уменьшению ввода/вывода и увеличению пропускной способности с небольшими затратами на увеличение использования процессора. Вы можете настроить баланс между уровнем сжатия и издержками на процессор, изменив параметр конфигурации innodb_compression_level.

Хранение и сжатие данных InnoDB

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

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

Сжатие узлов B-дерева (как кластеризованных, так и вторичных индексов) обрабатывается по-разному от сжатия используемых для хранения длинных VARCHAR, BLOB или TEXT столбцов, как объяснено в следующих разделах.

Сжатие страниц B-дерева

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

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

Кроме того, MySQL пытается избежать ненужной распаковки и пересжатия страниц индексов при их изменении. Внутри каждой страницы B-дерева система сохраняет несжатый «журнал изменений», чтобы записывать внесённые в страницу изменения. Обновления и вставки небольших записей могут быть записаны в этот журнал изменений без необходимости полной реконструкции всей страницы.

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

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

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

Если ON равно CREATE TABLE, MySQL проверяет максимальный размер строки во время CREATE INDEX или ERROR HY000: Too big row. Если строка не помещается, выдаётся следующее сообщение об ошибке: innodb_strict_mode.

Если вы создаёте таблицу, когда INSERT выключен, и последующее UPDATE или ERROR 42000: Row size too large операция пытается создать запись индекса, которая не помещается в размер сжатой страницы, операция завершается с ошибкой ALTER TABLE. (Это сообщение об ошибке не указывает индекс, для которого запись слишком велика, или размер записи индекса или максимальный размер записи на странице индекса.) Чтобы решить эту проблему, перестройте таблицу с помощью KEY_BLOCK_SIZE и выберите больший размер сжатой страницы (ROW_FORMAT=DYNAMIC), укоротите префиксные индексы столбцов или полностью отключите сжатие с помощью ROW_FORMAT=COMPACT или innodb_strict_mode.

innodb_strict_mode не относится к общим пространствам таблиц, которые также поддерживают сжатые таблицы. Правила управления пространством таблиц для общих пространств таблиц строго соблюдаются независимо от BLOB. Для получения дополнительной информации см. Раздел 15.1.21, «CREATE TABLESPACE Statement».

Сжатие столбцов BLOB, VARCHAR и TEXT

В таблице InnoDB VARCHAR, TEXT и ROW_FORMAT=DYNAMIC столбцы, которые не являются частью первичного ключа, могут храниться на выделенных страницах. Мы называем эти столбцы ROW_FORMAT=COMPRESSED.

Для таблиц, созданных в BLOB или TEXT, значения VARCHAR, ROW_FORMAT=DYNAMIC или ROW_FORMAT=COMPRESSED столбцов могут храниться полностью вне страницы, в зависимости от их длины и длины всей строки. Для столбцов, хранящихся вне страницы, запись кластеризованного индекса содержит только 20-байтовые указатели на страницы переполнения, по одному на столбец. Хранение столбцов вне страницы зависит от размера страницы и общего размера строки. Если строка слишком длинная, чтобы уместиться полностью на странице кластеризованного индекса, MySQL выбирает наиболее длинные столбцы для хранения вне страницы, пока строка не поместится на странице кластеризованного индекса. Как отмечалось выше, если строка не помещается на сжатой странице, возникает ошибка.

Примечание

Для таблиц, созданных в TEXT или BLOB, столбцы ROW_FORMAT=REDUNDANT и ROW_FORMAT=COMPACT, которые меньше или равны 40 байтам, всегда хранятся в строке.

Таблицы, использующие BLOB и VARCHAR, хранят первые 768 байт TEXT, COMPRESSED и BLOB столбцов в записи кластеризованного индекса вместе с первичным ключом. За префиксом длиной 768 байт следуют 20-байтовые указатели на страницы переполнения, содержащие остальную часть значения столбца.

Когда таблица находится в формате TEXT, все данные, записанные на страницы переполнения, сжимаются «как есть»; то есть MySQL применяет алгоритм сжатия zlib к всему элементу данных. Помимо данных, сжатые страницы переполнения содержат несжатый заголовок и подпись, содержащие контрольную сумму страницы и ссылку на следующую страницу переполнения, среди прочего. Поэтому существенная экономия памяти может быть получена для более длинных VARCHAR, JPEG или BLOB столбцов, если данные сильно сжимаются, как это часто бывает с текстовыми данными. Данные изображений, такие как VARCHAR, обычно уже сжаты, поэтому они не сильно выигрывают от хранения в сжатой таблице; двойное сжатие может привести к затратам ЦП без существенной экономии места.

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

END_OF_DOCUMENT_MARKER

Для табличных пространств, использование 16К сжатой страницы может уменьшить затраты на хранение и ввод-вывод для BLOB, VARCHAR или TEXT столбцов, поскольку такие данные часто хорошо сжимаются и, следовательно, могут потребовать меньше страниц переполнения, даже если узлы B-дерева занимают столько же страниц, как и в несжатой форме. Общие табличные пространства не поддерживают размер страницы сжатия 16К (KEY_BLOCK_SIZE). Для получения дополнительной информации см. Раздел 17.6.3.3, «Общие табличные пространства».

Сжатие и пул буфера InnoDB

В таблице со сжатым InnoDB, каждая сжатая страница (будь то 1К, 2К, 4К или 8К) соответствует несжатой странице размером 16К байт (или меньшему размеру, если innodb_page_size установлено). Для доступа к данным на странице MySQL считывает сжатую страницу с диска, если она еще не находится в , а затем распаковывает страницу до исходной формы. В этом разделе описывается, как InnoDB управляет пулом буфера в отношении страниц сжатых таблиц.

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

MySQL отслеживает, какие страницы следует хранить в памяти, а какие извлекать, используя список наименее недавно используемых (), так что (часто используемые) данные имеют тенденцию оставаться в памяти. При доступе к сжатым таблицам MySQL использует адаптивный алгоритм LRU для достижения надлежащего баланса сжатых и несжатых страниц в памяти. Этот адаптивный алгоритм чувствителен к тому, работает ли система в или режиме. Цель состоит в том, чтобы избежать траты слишком многого времени на распаковку страниц, когда ЦП загружен, и избежать избыточного ввода-вывода, когда у ЦП есть свободные циклы, которые могут быть использованы для распаковки сжатых страниц (которые могут уже находиться в памяти). Когда система ограничена вводом-выводом, алгоритм предпочитает извлекать несжатую копию страницы, а не обе копии, чтобы освободить больше места для других страниц диска, которые должны стать резидентными в памяти. Когда система ограничена ЦП, MySQL предпочитает извлекать и сжатую, и несжатую страницу, чтобы больше памяти можно было использовать для “актуальных” страниц и уменьшить необходимость распаковки данных в памяти только в сжатом виде.

Сжатие и файлы журнала InnoDB

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

Чтобы создать сжатую таблицу в табличном пространстве по файлам на таблицу, innodb_file_per_table должен быть включен. Нет зависимости от настройки innodb_file_per_table при создании сжатой таблицы в общем табличном пространстве. Для получения дополнительной информации см. Раздел 17.6.3.3, «Общие табличные пространства».

© 2025 Oracle
Licensed under the GPLv2 License.
https://docs.oracle.com/cd/E17952_01/mysql-8.4-en/innodb-compression-internals.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API