Як працюють індекси 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
Ви пояснюєте, що це таке, а не як технічно це працює всередині.
Туту Кумарі

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

259

Перше, що ви повинні знати, це те, що індекси - це спосіб уникнути сканування повної таблиці, щоб отримати результат, який ви шукаєте.

Існують різні типи індексів і вони реалізовані в шарі зберігання, тому між ними немає стандарту, і вони також залежать від двигуна пам’яті, який ви використовуєте.

InnoDB та індекс дерева B +

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

"Проблема" щодо цього типу індексу полягає в тому, що вам потрібно запитати про найменше значення, щоб використовувати індекс. Отже, якщо ваш індекс має два стовпці, скажіть прізвище та ім'я, ім'я, порядок, який ви запитуєте в цих полях, має велике значення .

Отже, враховуючи наступну таблицю:

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 .

Я настійно рекомендую прочитати книгу "Високопродуктивний 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 +, яке працює аналогічно двійковому пошуку, але не зовсім однакове. Алгоритмічна складність однакова, але спосіб пошуку не є. Дивіться en.wikipedia.org/wiki/B-tree
Метт

4

Подивіться за цим посиланням: http://dev.mysql.com/doc/refman/5.0/uk/mysql-indexes.html

Те, як вони працюють, є занадто широкою темою, щоб висвітлювати її в одній публікації ЗП.

Ось одне з найкращих пояснень індексів, які я бачив. На жаль, це для SQL Server, а не для MySQL. Я не впевнений, наскільки вони схожі ...


2
Приємна стаття. Я не знаю SQL Server, але основні роботи виглядають дуже схоже. (метанота: вимкнення стилів CSS у другій пов’язаній статті приховує вміст)
Piskvor вийшов із будівлі

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
Ilyas karim

1

Я хочу додати свої 2 копійки. Я далеко не експерт по базі даних, але останнім часом я трохи прочитав цю тему; Досить мені спробувати і дати ELI5. Отже, ось пояснення мирян.


Я розумію це як таке, що індекс схожий на міні-дзеркало вашої таблиці, майже як асоціативний масив. Якщо ви подаєте його відповідним ключем, ви можете просто перейти до цього рядка однією "командою".

Але якщо у вас не було цього індексу / масиву, інтерпретатор запитів повинен використовувати цикл for, щоб пройти всі рядки та перевірити відповідність (сканування повної таблиці).

Наявність індексу має "недолік" додаткового сховища (для цього міні-дзеркала) в обмін на "перевершення" пошуку швидшого вмісту.

Зауважте, що (залежно від вашого db-двигуна) створення первинних, зовнішніх або унікальних ключів автоматично також встановлює відповідний індекс. Цей самий принцип є в основному, чому і як ці ключі працюють.


1

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

MySQL використовує додатковий шар непрямості: вторинні записи індексу вказують на первинні записи індексу, а сам первинний індекс містить місця на рядку на диску. Якщо зміщення рядка змінюється, потрібно оновлювати лише первинний індекс.

Caveat: Структура даних диска виглядає плоскою на діаграмі, але насправді це B + дерево.

Джерело: посилання


1

У MySQL InnoDB є два типи індексу.

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

  2. Вторинний ключ, який не є кластерним індексом. Ці індекси зберігають лише ключові слова первинного ключа, а також їхні власні ключові слова в індексі B + Tree leaf. Тож при пошуку з вторинного індексу він спочатку знайде ключові слова вказівника первинного ключа та просканує первинний ключ B + Дерево, щоб знайти справжні записи даних. Це дозволить зробити вторинний індекс повільніше порівняно з пошуком первинного індексу. Однак, якщо всі selectстовпці знаходяться у вторинному індексі, тоді не потрібно шукати первинний індекс B + Tree заново. Це називається покриттям індексу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.