Как добавить индексы в таблицы MySQL?


408

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

SELECT * FROM table WHERE id = '1';

код работает нормально, так как поле ID является основным индексом. Тем не менее, для недавнего развития проекта, я должен искать в базе данных по другому полю. Например:

SELECT * FROM table WHERE product_id = '1';

Это поле не было ранее проиндексировано; тем не менее, я добавил один, поэтому mysql теперь индексирует поле, но когда я пытаюсь выполнить вышеуказанный запрос, он выполняется очень медленно. Запрос EXPLAIN показывает, что для поля product_id нет индекса, когда я его уже добавил, и в результате запрос занимает от 20 минут до 30 минут, чтобы вернуть одну строку.

Мои полные результаты EXPLAIN:

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

Может быть полезно отметить, что я только что посмотрел, и поле ID хранится как INT, тогда как поле PRODUCT_ID хранится как VARCHAR. Может ли это быть источником проблемы?


1
Можете ли вы опубликовать полные EXPLAINрезультаты? Вы уверены, что нет индекса? Или индекс есть, но MySQL решил не использовать его?
— VoteyDisciple

169
Большая таблица будет иметь 150 000 000 записей. Очень большая таблица содержит 15 000 000 000 записей. Таблица среднего размера имеет 150000. Для дальнейшего использования.
— usumoio

4
Имейте в виду, что «ИЛИ» может заставить MySql не использовать индексы. У меня был запрос с 3 или. Каждый сопоставлял индекс и работал за 15 мсек. Все вместе занимало от 25 с до времени ожидания. Поэтому я сделал 3 запроса и объединил их в UNION, это также заняло 15 мс на 500 000 строк.
— Лейф Неланд

Рассмотрим тип данных, которые вы храните. Производительность может изменяться в зависимости от типа данных, который вы сравниваете. Как вы сказали, PRODUCT_ID является типом данных VARCHAR, попробуйте изменить его на INT и проиндексировать столбец.
— Гилбертдим

Ответы:


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

Никогда не сравнивайте integerс stringsв MySQL. Если idесть int, удалите кавычки.


Я уже добавил индекс, используя этот точный SQL, но кажется, что он не был "применен" к данным, и запрос EXPLAIN показывает, что для поля нет индекса.
— Майкл

1
Хотите проверить индекс с помощью SHOW CREATE TABLE, или вы уже сделали это?
— Wrikken

33
Используйте SHOW INDEXES FROM YOURTABLE dev.mysql.com/doc/refman/5.0/en/show-index.html, чтобы проверить, были ли добавлены индексы
— Тимо Хуовинен,

6
Сегодня у меня была точная проблема, которую описывает Майкл, и решение было «Никогда не сравнивайте целые числа со строками в MySQL». Спасибо.
— user12345 10.09.14

@Wrikken Я добавил свой индекс и использовал вашу команду ПОКАЗАТЬ ИНДЕКСЫ ИЗ ВАШЕЙ ТАБЛИЦЫ. Он появляется, но я не думаю, что он используется, когда я запрашиваю свою таблицу. Нужно ли менять запрос на выборку при использовании индекса?
— Сед

148
ALTER TABLE TABLE_NAME ADD INDEX (COLUMN_NAME);

97
В 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/en/index-btree-hash.html


1
Хэш конвертируется в btree, когда я вижу, используя индексы шоу.
— Р.Н. Кушваха

1
Что будет по умолчанию из Hash и BTree, если я не укажу их?
— Бхавук Матур

2
@RNKushwaha, потому что InnoDB и MyIsam не поддерживают HASH, AFAIK, только модули памяти и NDB поддерживают это
— Hieu Vo

60

Стоит отметить, что несколько индексов полей могут значительно улучшить производительность вашего запроса. Таким образом, в приведенном выше примере мы предполагаем, что ProductID является единственным полем для поиска, но если запрос скажет ProductID = 1 AND Category = 7, тогда поможет индекс из нескольких столбцов. Это достигается с помощью следующего:

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

Кроме того, индекс должен соответствовать порядку полей запроса. В моем расширенном примере индекс должен быть (ProductID, Category), а не наоборот.


1
Хороший, явно названный индекс позволяет легко изменить его.
— Сэм Берри

Можете ли вы процитировать источник the index should match the order of the query fields?
— Бишвис Мишра

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`)

Вышеупомянутое заявление создаст полнотекстовое имя индекса с 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 использовать индекс с помощью синтаксиса подсказок по индексам , но если вы это сделаете, обязательно запустите несколько тестов, чтобы определить, действительно ли он улучшает производительность, чтобы использовать индекс, как вы намекнули ,

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