Як додати індекси до таблиць MySQL?


407

У мене дуже велика таблиця MySQL з приблизно 150 000 рядками даних. В даний час, коли я пробую і бігаю

SELECT * FROM table WHERE id = '1';

код працює нормально, оскільки поле ID є основним індексом. Однак для недавньої розробки проекту мені доведеться шукати в базі даних за іншим полем. Наприклад:

SELECT * FROM table WHERE product_id = '1';

Це поле раніше не було індексовано; Однак я додав його, тому mysql тепер індексує поле, але коли я намагаюся запустити вищезазначений запит, він працює дуже повільно. Запит EXPLAIN виявляє, що не існує індексу для поля product_id, коли я вже додав його, і в результаті запит займає десь від 20 хвилин до 30 хвилин, щоб повернути один рядок.

Мої повні ПОЯСНЕННІ результати:

| id | select_type | table | type | possible_keys| key  | key_len | ref  | rows  | Extra       |
+----+-------------+-------+------+--------------+------+---------+------+-------+------------------+
|  1 | SIMPLE      | table | ALL  | NULL         | NULL | NULL    | NULL |157211 | Using where |
+----+-------------+-------+------+--------------+------+---------+------+-------+------------------+

Можливо, буде корисно зазначити, що я щойно подивився, а поле ідентифікатора зберігається як INT, тоді як поле PRODUCT_ID зберігається як VARCHAR. Чи може це бути джерелом проблеми?


1
Чи можете ви опублікувати всі EXPLAINрезультати? Ви впевнені, що індексу немає ? Або індекс є, але MySQL вирішив не використовувати його?
VoteyDisciple

169
Великий стіл мав би 150 000 000 записів. Дуже велика таблиця має 15 000 000 000 записів. Таблиця середнього розміру має 150 000. Для подальшого ознайомлення.
usumoio

4
Майте на увазі, що "АБО" може змусити MySql не використовувати індекси. У мене був запит із 3 АБО. Кожен пішов на індекс і пробіг за 15 мс, Усі разом взяли між 25 сек і таймаутом. Тому я зробив 3 запити, і UNION'ed їх разом, це також зайняло 15 мс на 500 000 рядків.
Лейф Неланд

Розглянемо тип даних, який ви зберігаєте. Ефективність може змінюватися залежно від типу даних, який ви порівнюєте. Як ви сказали, що PRODUCT_ID - це тип даних VARCHAR, спробуйте змінити його на INT та індексувати стовпець.
gilbertdim

Відповіді:


606
ALTER TABLE `table` ADD INDEX `product_id_index` (`product_id`)

Ніколи не порівнюйте integerз stringsMySQL. Якщо idє int, видаліть цитати.


Я вже додав індекс за допомогою саме цього SQL, але здається, що він не "застосований" до даних, і запит EXPLAIN показує, що для цього поля немає індексу.
Майкл

1
Потрібно перевірити індекс за допомогою SHOW CREATE TABLE, чи це ви вже зробили?
Wrikken

33
Використовуйте SHOW INDEXES FROM YOURTABLE dev.mysql.com/doc/refman/5.0/uk/show-index.html, щоб перевірити, чи додані індекси
Тимо Хуовінен

6
Сьогодні у мене була точна проблема, яку @Michael описує, і рішенням було "Ніколи не порівнюйте цілі числа з рядками в mysql." Дякую.
користувач12345

@Wrikken Я додав свій індекс і використав вашу команду ПОКАЗУЙТЕ ІНДЕКСИ З ВАШОГО. Він відображається, але я не думаю, що він використовується, коли я запитую свій стіл. Чи потрібно змінювати запит вибору при використанні індексу?
Ced

147
ALTER TABLE TABLE_NAME ADD INDEX (COLUMN_NAME);

96
В MySQL, якщо використовувати ALTER TABLE tbl ADD INDEX (col)замість ALTER TABLE tbl ADD INDEX col (col), а потім з допомогою ALTER TABLE tbl ADD INDEX (col)більш ніж один раз буде продовжувати додавати індекси з іменами col_2, col_3... кожен раз. В той ALTER TABLE tbl ADD INDEX col (col)час як, використовуючи другий раз, дамо ERROR 1061 (42000): Duplicate key name 'col'.
Абхішек Оза

82

Ви можете використовувати цей синтаксис, щоб додати індекс і керувати видом індексу (HASH або BTREE).

create index your_index_name on your_table_name(your_column_name) using HASH;
or
create index your_index_name on your_table_name(your_column_name) using BTREE;

Дізнатися про відмінності між індексами BTREE та HASH можна тут: http://dev.mysql.com/doc/refman/5.5/uk/index-btree-hash.html


1
Хеш перетворюється на btree, коли я бачу, як використовують покажчики показів.
RN Kushwaha

1
Що буде за замовчуванням у Hash та BTree, якщо я не вказую жодного?
Бхавук Матур

2
@ RNKushwaha, тому що InnoDB і MyIsam не підтримують HASH, AFAIK, підтримують його лише двигуни пам’яті пам’яті та NDB
Hieu Vo

60

Варто відзначити, що кілька індексів поля можуть різко покращити ефективність вашого запиту. Отже, у наведеному вище прикладі ми припускаємо, що ProductID є єдиним полем для пошуку, але запит сказав ProductID = 1 І категорія = 7, то допомагає множина індексу стовпців. Це досягається за допомогою наступного:

ALTER TABLE `table` ADD INDEX `index_name` (`col1`,`col2`)

Крім того, індекс повинен відповідати порядку порядку запитів. У моєму розширеному прикладі індекс повинен бути (ProductID, Category), а не навпаки.


1
Приємно, явне іменування індексу дозволяє легко перевернути.
Сем Беррі

Чи можете ви цитувати джерело the index should match the order of the query fields?
Bishwas Mishra

58

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

Пояснення

Первинний ключ як індекс

Подумайте, у вас є tbl_studentтаблиця, і ви хочете student_idв якості основного ключа:

ALTER TABLE `tbl_student` ADD PRIMARY KEY (`student_id`)

Вищенаведене твердження додає первинний ключ, а це означає, що індексовані значення повинні бути унікальними і не можуть бути NULL.

Вкажіть ім'я індексу

ALTER TABLE `tbl_student` ADD INDEX student_index (`student_id`)

Наведене вище твердження створить звичайний індекс з student_indexім'ям.

Створіть унікальний індекс

ALTER TABLE `tbl_student` ADD UNIQUE student_unique_index (`student_id`)

Тут student_unique_indexім’я індексу присвоюється student_id та створює індекс, значення якого повинно бути унікальним (тут нуль можна прийняти).

Варіант повного тексту

ALTER TABLE `tbl_student` ADD FULLTEXT student_fulltext_index (`student_id`)

Вищенаведене твердження створить ім'я індексу Fulltext student_fulltext_index, за допомогою якого вам потрібен MyISAM Mysql Engine.

Як видалити індекси?

DROP INDEX `student_index` ON `tbl_student`

Як перевірити наявні індекси?

SHOW INDEX FROM `tbl_student`

17

Ви кажете, що маєте індекс, пояснення говорить інакше. Однак якщо це дійсно так, продовжувати:

Якщо у вас стовпчик індексу, і MySQL вирішує не використовувати його, він може:

  1. У запиті MySQL є ще один індекс, який вважається більш доцільним у використанні, і він може використовувати лише один. Рішення зазвичай є індексом, що охоплює декілька стовпців, якщо їх звичайний спосіб пошуку є значенням більше одного стовпця.
  2. MySQL вирішує, що існує багато відповідних рядків, і вважає, що таблицяможе швидше. Якщо це не так, іноді ANALYZE TABLEдопомагає.
  3. У більш складних запитах він вирішує не використовувати його на основі надзвичайно розумного продуманого вуду в плані запитів, який чомусь просто не відповідає вашим поточним вимогам.

У випадку (2) або (3) ви можете змусити MySQL використовувати індекс за допомогою індексу підказки sytax , але якщо ви це зробите, не забудьте виконати деякі тести, щоб визначити, чи дійсно це покращує продуктивність, щоб використовувати індекс, як ви натякаєте на нього .

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