Como adiciono índices às tabelas MySQL?

407

Eu tenho uma tabela MySQL muito grande com cerca de 150.000 linhas de dados. Atualmente, quando tento executar

SELECT * FROM table WHERE id = '1';

o código funciona bem, pois o campo ID é o índice principal. No entanto, para um desenvolvimento recente no projeto, tenho que pesquisar no banco de dados por outro campo. Por exemplo:

SELECT * FROM table WHERE product_id = '1';

Este campo não foi indexado anteriormente; no entanto, eu adicionei um, então o mysql agora indexa o campo, mas quando tento executar a consulta acima, ela é executada muito lentamente. Uma consulta EXPLAIN revela que não há um índice para o campo product_id quando eu já adicionei um, e, como resultado, a consulta leva de 20 a 30 minutos para retornar uma única linha.

Meus resultados completos de EXPLAIN são:

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

Pode ser útil observar que acabei de dar uma olhada e o campo ID é armazenado como INT, enquanto o campo PRODUCT_ID é armazenado como VARCHAR. Essa poderia ser a fonte do problema?

Michael
fonte
1
Você pode postar os EXPLAINresultados completos ? Você tem certeza de que não índice? Ou o índice está lá, mas o MySQL está optando por não usá-lo?
usar o seguinte código
169
Uma tabela grande teria 150.000.000 registros. Uma tabela muito grande possui 15.000.000.000 de registros. Uma tabela de tamanho médio tem 150.000. Para referência futura.
usumoio
4
Esteja ciente de que 'OR' pode fazer o MySql não usar índices. Eu tive uma consulta com 3 OR's. Cada um usinou um índice e foi executado em 15ms. Todos juntos levaram entre 25seg e timeout. Então, eu fiz 3 consultas e as UNION'ed juntos, também levou 15ms em 500.000 linhas.
Leif Neland
Considere o tipo de dados que você está armazenando. O desempenho pode mudar com base no seu tipo de dados que você está comparando. Como você disse que PRODUCT_ID é um tipo de dados VARCHAR, tente alterá-lo para INT e indexe a coluna.
gilbertdim 24/03

Respostas:

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

Nunca compare integercom o stringsMySQL. Se idfor int, remova as aspas.

zerkms
fonte
Eu já adicionei o índice usando o SQL exato, mas parece que ele não foi "aplicado" aos dados e a consulta EXPLAIN mostra que não há índice para o campo.
Michael Michael
1
Importa-se de verificar o índice com uma SHOW CREATE TABLE, ou você já fez isso?
Wrikken
33
Use SHOW INDEXES FROM YOURTABLE dev.mysql.com/doc/refman/5.0/en/show-index.html para verificar se os índices foram adicionados
Timo Huovinen
6
Hoje eu tive o problema exato que o Michael descreve, e a solução foi "Nunca compare números inteiros com strings no mysql". Obrigado.
user12345
@Wrikken eu adicionei meu índice e usei o seu comando SHOW INDEXES FROM YOURTABLE. Ele aparece, mas acho que não é usado enquanto eu consulta minha tabela. Preciso alterar a consulta de seleção ao usar um índice?
Ced
148
ALTER TABLE TABLE_NAME ADD INDEX (COLUMN_NAME);
pabloferraz
fonte
97
No MySQL, se você usar ALTER TABLE tbl ADD INDEX (col)em vez de ALTER TABLE tbl ADD INDEX col (col), em seguida, usando ALTER TABLE tbl ADD INDEX (col)mais de uma vez vai continuar a acrescentar chamada índices col_2, col_3... cada vez. Considerando que usando a ALTER TABLE tbl ADD INDEX col (col)segunda vez, dará ERROR 1061 (42000): Duplicate key name 'col'.
Abhishek Oza
82

Você pode usar esta sintaxe para adicionar um índice e controlar o tipo de índice (HASH ou 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;

Você pode aprender sobre as diferenças entre os índices BTREE e HASH aqui: http://dev.mysql.com/doc/refman/5.5/en/index-btree-hash.html

Hieu Vo
fonte
1
Hash convertido em btree quando vejo usando índices de exibição.
RN Kushwaha 15/10
1
Qual será o padrão do Hash e BTree, se eu não especificar nenhum?
Bhavuk Mathur
2
@RNKushwaha porque InnoDB e MyISAM não suportam HASH, mecanismos de armazenamento AFAIK, apenas a memória e NDB apoiá-lo
Hieu Vo
60

Vale a pena notar que vários índices de campo podem melhorar drasticamente o desempenho da sua consulta. Portanto, no exemplo acima, assumimos que ProductID é o único campo a ser pesquisado, mas se a consulta diz ProductID = 1 AND Category = 7, um índice de várias colunas ajuda. Isso é alcançado com o seguinte:

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

Além disso, o índice deve corresponder à ordem dos campos da consulta. No meu exemplo estendido, o índice deve ser (ProductID, Category) e não o contrário.

Antony
fonte
1
É bom nomear explicitamente o índice para facilitar a reversão.
Sam Berry
Você pode citar a fonte de the index should match the order of the query fields?
Bishwas Mishra
58

Índices de dois tipos podem ser adicionados: quando você define uma chave primária, o MySQL a toma como índice por padrão.

Explicação

Chave primária como índice

Considere que você tem uma tbl_studenttabela e deseja student_idcomo chave primária:

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

A instrução acima adiciona uma chave primária, o que significa que os valores indexados devem ser exclusivos e não podem ser NULL.

Especifique o nome do índice

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

A instrução acima criará um índice comum com o student_indexnome.

Crie um índice exclusivo

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

Aqui, student_unique_indexé o nome do índice atribuído a student_id e cria um índice para o qual os valores devem ser exclusivos (aqui o nulo pode ser aceito).

Opção de texto completo

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

A instrução acima criará o nome do índice de texto completo com student_fulltext_index qual você precisará do MyISAM Mysql Engine.

Como remover índices?

DROP INDEX `student_index` ON `tbl_student`

Como verificar os índices disponíveis?

SHOW INDEX FROM `tbl_student`
Jazzzzzz
fonte
17

Você diz que tem um índice, a explicação diz o contrário. No entanto, se você realmente faz, é assim que continua:

Se você tem um índice na coluna e o MySQL decide não usá-lo, pode ser porque:

  1. Há outro índice na consulta que o MySQL considera mais apropriado para usar, e ele pode usar apenas um. A solução geralmente é um índice que abrange várias colunas se o método normal de recuperação for pelo valor de mais de uma coluna.
  2. O MySQL decide que existem muitas linhas correspondentes e acha que uma tabela pode ser mais rápida. Se não for esse o caso, às vezes ANALYZE TABLEajuda.
  3. Em consultas mais complexas, ele decide não usá-lo com base em um vodu pensado extremamente inteligente no plano de consultas que, por algum motivo, não se encaixa nos seus requisitos atuais.

No caso de (2) ou (3), você pode convencer o MySQL a usar o índice pela sintaxe da dica do índice , mas, se o fizer, certifique-se de executar alguns testes para determinar se realmente melhora o desempenho do uso do índice conforme você sugere. .

Wrikken
fonte