Производительность кластерного индекса InnoDB при использовании случайных значений в качестве первичного ключа - PullRequest
0 голосов
/ 15 июня 2019

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

Это пример типичной схемы:

CREATE TABLE `MUSIC_LINK` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `project_id` int(11) unsigned DEFAULT NULL,
   PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=latin1;

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

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

Я неправильно понимаю, как работают кластерные индексы в InnoDB? потому что это звучит как гигантская проблема производительности.

1 Ответ

2 голосов
/ 16 июня 2019

InnoDB:

При AUTO_INCREMENT PRIMARY KEY «следующая» строка будет помещена в «конец» BTree, который содержит данные для таблицы.Это эффективно, и «последний» блок будет много обновлен.

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

При «случайном» PK, таком как GUID, UUID, MD5, SHA1 и т. Д., «Следующая» строка, которую нужно вставить, должна перейти в какое-то «случайное» место в BTree, содержащем данные.Если buffer_pool достаточно большой, то необходимый блок все равно будет находиться в нем.Таким образом, эффективность не сильно отличается от AI.

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

Если, например, таблица в 20 раз больше, чем может храниться в buffer_pool, то следующая случайная запись будет иметь вероятность 1 из 20 блокакэшируются.То есть в 95% случаев INSERT должен ждать чтения диска.

Но ... Вы вызвали обсуждение INSERTs.А как насчет SELECTs?Какой, если есть, шаблон есть для выбора?В любом случае, если он «случайный», тип PK не имеет значения.Если, с другой стороны, выборки имеют тенденцию достигать «недавних» элементов (например, новостных статей), то ИИ выигрывает для больших таблиц из-за повышенной вероятности кэширования нужного блока.

Cluster

Комментарий подразумевает некоторую путаницу по поводу «cluster / ed / ing».Некоторые определения (в контексте MySQL / MariaDB):

  • Группа серверов с одинаковыми данными, работающими вместе.NDB Cluster vs Galera Cluster vs Clustrix (стороннее предложение)
  • «Кластерный индекс» - это когда данные присоединены к индексу.В InnoDB PK всегда кластеризован с данными.(Примечание: MyISAM и другие поставщики не обязательно делают это.)
  • Когда извлекаемые записи располагаются рядом друг с другом в макете на диске (считают PK или вторичным индексом), то эти строки «сгруппированы вместе».Это стоит отметить, потому что выборка одного блока получает несколько нужных вам строк.

Итак, вернемся к комментарию:

  • Прыжки по PRIMARY KEY (из-заиспользование того, что я назвал случайным PK, или из-за того, что строки просто не выбираются в некотором соответствующем порядке), застревает в прыжках по таблице.
  • UUID имеет «отсортированный порядок», но это бесполезно длямного всего.
...