Как добавить индексы в таблицы 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, удалите кавычки.

zerkms
источник
Я уже добавил индекс, используя этот точный 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);
pabloferraz
источник
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), а не наоборот.

Antony
источник
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`
Jazzzzzz
источник
17

Вы говорите, что у вас есть индекс, объяснение говорит иначе. Однако, если вы действительно это сделаете, это как продолжить:

Если у вас есть индекс для столбца, и MySQL решает не использовать его, это может быть вызвано тем, что:

  1. Есть другой индекс в запросе, который MySQL считает более подходящим для использования, и он может использовать только один. Решением обычно является индекс, охватывающий несколько столбцов, если их обычный метод поиска по значению более одного столбца.
  2. MySQL решает, что есть много подходящих строк, и считает, что сканирование таблицы, вероятно, быстрее. Если это не так, иногда ANALYZE TABLEпомогает.
  3. В более сложных запросах он решает не использовать его на основе чрезвычайно интеллектуально продуманного вуду в плане запросов, который по какой-то причине просто не соответствует вашим текущим требованиям.

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

Wrikken
источник