Как работают индексы MySQL?


402

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

Это не по теме, я знаю, но если есть кто-то, кто мог бы объяснить мне это подробно, я был бы очень, очень благодарен.



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

SELECT * FROM members WHERE id = '1'- так почему с индексом он работает быстрее? Что этот индекс делает здесь?
good_evening

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

Очень хорошо, спасибо!
Гонки

Ответы:


513

По сути, индекс таблицы работает как индекс в книге (отсюда и название):

Допустим, у вас есть книга о базах данных, и вы хотите найти некоторую информацию, скажем, о хранилище. Без индекса (при условии отсутствия другой помощи, такой как оглавление) вам пришлось бы просматривать страницы одну за другой, пока вы не найдете тему (это так full table scan). С другой стороны, в индексе есть список ключевых слов, поэтому вы можете просмотреть его и увидеть, что storageупомянуто на страницах 113-120, 231 и 354. Затем вы можете переходить на эти страницы напрямую, без поиска (это поиск с индекс, несколько быстрее).

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

  • Если бы у вас была книга по базам данных и было проиндексировано слово «база данных», вы бы увидели, что она упоминается на страницах 1–59, 61–290 и 292–400. В этом случае индекс не очень полезен, и он может Быстрее просматривать страницы по одной (в базе данных это «плохая избирательность»).
  • Для 10-страничной книги не имеет смысла создавать индекс, поскольку в итоге вы можете получить 10-страничную книгу с префиксом 5-страничного индекса, что просто глупо - просто отсканируйте 10 страниц и покончите с этим ,
  • Индекс также должен быть полезен - обычно нет смысла индексировать, например, частоту буквы «L» на странице.

3
Вы объясняете, что это, а не как технически это работает внутри.
Туту Кумари

@ Туту Кумари: см. Исправления вопроса; не стесняйтесь также пересмотреть ответ, чтобы соответствовать текущему вопросу (обратите внимание на различные механизмы и типы индексов - см., например, документацию здесь: dev.mysql.com/doc/refman/8.0/en/index-btree-hash.html )
Писквор покинул здание

259

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

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

InnoDB и индекс дерева B +

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

«Проблема» в этом типе индекса заключается в том, что вы должны запросить крайнее левое значение, чтобы использовать индекс. Итак, если в вашем индексе есть два столбца, скажем, last_name и first_name, порядок, в котором вы запрашиваете эти поля, имеет большое значение .

Итак, с учетом следующей таблицы:

CREATE TABLE person (
    last_name VARCHAR(50) NOT NULL,
    first_name VARCHAR(50) NOT NULL,
    INDEX (last_name, first_name)
);

Этот запрос будет использовать индекс:

SELECT last_name, first_name FROM person
WHERE last_name = "John" AND first_name LIKE "J%"

Но следующий не будет

SELECT last_name, first_name FROM person WHERE first_name = "Constantine"

Потому что вы first_nameсначала запрашиваете столбец, а это не самый левый столбец в индексе.

Этот последний пример еще хуже:

SELECT last_name, first_name FROM person WHERE first_name LIKE "%Constantine"

Потому что теперь вы сравниваете самую правую часть самого правого поля в индексе.

Индекс хеша

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

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

Если у вас большое VARCHARполе, вы можете «эмулировать» использование хеш-индекса при использовании B-дерева, создав другой столбец и сохранив на нем хеш-значение большого значения. Допустим, вы храните URL-адрес в поле, а значения довольно большие. Вы также можете создать целочисленное поле с именем url_hashи использовать хеш-функцию, например, CRC32или любую другую хеш-функцию для хеширования URL-адреса при его вставке. И затем, когда вам нужно запросить это значение, вы можете сделать что-то вроде этого:

SELECT url FROM url_table WHERE url_hash=CRC32("http://gnu.org");

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

SELECT url FROM url_table 
WHERE url_hash=CRC32("http://gnu.org") AND url="http://gnu.org";

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

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

Заворачивать

Некоторые факты, которые вы можете учитывать каждый раз, когда хотите поговорить об оптимизации:

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

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

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

Я настоятельно рекомендую вам прочитать книгу «High Performance MySQL», ответ на которую был определенно основан на главе об индексах.


2
Будут ли следующие запросы иметь преимущество в вышеуказанном случае? 1. SELECT last_name, first_name FROM person WHERE last_name= "Constantine" 2.SELECT last_name, first_name FROM person WHERE last_name LIKE "%Constantine"
Акшай Тару

1
Первый запрос будет, второй запрос не будет. Используйте EXPLAIN: dev.mysql.com/doc/refman/5.5/en/explain.html. Для индексации второго запроса с помощью MySQL необходимо использовать FULLTEXT INDEX: dev.mysql.com/doc/refman/5.5/en/fulltext-. search.html
Эмилио Николас

5
Я проголосовал за вас, потому что вы были в 127, а ответ № 1 был в 256. Я не мог не делать все красиво и чисто, в двоичном виде.
pbarney

Для меня это была новая информация: «порядок, в котором вы запрашиваете эти поля, очень важен». Спасибо.
Хатри

1
@pbarney через три года они около 256 и 512 соответственно, это то, что я называю двоичным увеличением!
Nanocv

43

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

1: Перейти к середине списка - выше или ниже того, что я ищу?

2: Если выше, перейдите к половине пути между серединой и дном, если ниже, посередине и сверху

3: выше или ниже? Снова перейти к средней точке и т. Д.

Используя эту логику, вы можете найти элемент в отсортированном списке примерно за 7 шагов вместо проверки каждого элемента.

Очевидно, что есть сложности, но это дает вам основную идею.


29
Это называется бинарный поиск.
ddlshack

Спасибо, наконец, ответ, который объясняет, почему это быстрее, а не просто как db функционирует с индексами.
Гершон Херцег

Фактическое количество шагов в значительной степени зависит от данных - количества уникальных значений и распределения по всему диапазону. 7 - теоретический максимум для 100 значений. Полное обсуждение того, как рассчитать количество шагов здесь stackoverflow.com/questions/10571170/…
Джошуа

Самым распространенным индексом MySQL является B + Tree, который работает аналогично бинарному поиску, но не совсем так. Алгоритмическая сложность та же самая, но способ поиска - нет. См. En.wikipedia.org/wiki/B-tree
Мэтт

4

Взгляните на эту ссылку: http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html

То, как они работают, слишком широко, чтобы освещать это в одном посте.

Вот одно из лучших объяснений индексов, которые я видел. К сожалению, это для SQL Server, а не MySQL. Я не уверен, насколько похожи эти два ...


2
Хорошая статья. Я не знаю SQL Server, но основные принципы работы выглядят очень похоже. (metanote: отключение стилей CSS во 2-й связанной статье показывает содержимое)
Писквор покинул здание

3

Возьмите это видео для более подробной информации об индексировании

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

CREATE UNIQUE INDEX index_name
ON table_name ( column1, column2,...);

Вы можете использовать один или несколько столбцов для создания индекса. Например, мы можем создать индекс tutorials_tblиспользования tutorial_author.

CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author)

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

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

mysql> CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author DESC)

1
Добро пожаловать в переполнение стека! Я отметил, что все ваши ответы связаны с вашими видео. Обратите внимание, что открытая самореклама не допускается .
SL Barth - Восстановить Монику

Он хочет продвигать свои видео. LOL
Ильяс Карим

1

Я хочу добавить свои 2 цента. Я далек от того, чтобы быть экспертом по базам данных, но недавно я немного прочитал эту тему; достаточно для меня, чтобы попытаться дать ELI5. Итак, вот объяснение для неспециалистов.


Я так понимаю, что индекс подобен мини-зеркалу вашей таблицы, почти как ассоциативный массив. Если вы передадите ему соответствующий ключ, вы можете просто перейти к этой строке в одной «команде».

Но если у вас не было этого индекса / массива, интерпретатор запросов должен использовать цикл for, чтобы пройти по всем строкам и проверить совпадение (сканирование полной таблицы).

Наличие индекса имеет «обратную сторону» дополнительного хранилища (для этого мини-зеркала) в обмен на «обратную сторону» поиска контента быстрее.

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


1

Добавление визуального представления в список ответов. введите описание изображения здесь

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

Предостережение: структура данных диска выглядит плоской на диаграмме, но на самом деле представляет собой дерево B +.

Источник: ссылка


1

В MySQL InnoDB есть два типа индекса.

  1. Первичный ключ, который называется кластеризованным индексом. Ключевые слова индекса хранятся с реальными данными записи в листовом узле B + Tree.

  2. Вторичный ключ, который не является кластеризованным индексом. Эти индексы хранят только ключевые слова первичного ключа вместе со своими собственными ключевыми словами индекса в листовом узле B + Tree. Поэтому при поиске по вторичному индексу он сначала найдет ключевые слова индекса первичного ключа и просканирует первичный ключ B + Tree, чтобы найти записи реальных данных. Это замедлит вторичный индекс по сравнению с поиском первичного индекса. Однако, если все selectстолбцы находятся во вторичном индексе, нет необходимости снова искать первичный индекс B + Tree. Это называется индексом покрытия.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.