Índices MySQL - quais são as melhores práticas?

208

Eu tenho usado índices em meus bancos de dados MySQL por um tempo agora, mas nunca aprendi corretamente sobre eles. Geralmente, coloco um índice em todos os campos que pesquisarei ou seleciono usando umWHERE cláusula, mas às vezes não parece tão preto e branco.

Quais são as melhores práticas para índices MySQL?

Exemplos de situações / dilemas:

  • Se uma tabela tiver seis colunas e todas elas forem pesquisáveis, devo indexar todas ou nenhuma?

  • Quais são os impactos negativos no desempenho da indexação?

  • Se eu tiver uma coluna VARCHAR 2500 pesquisável em partes do meu site, devo indexá-la?

Haroldo
fonte
5
Você provavelmente deve refazer a pergunta. A escolha dos índices é uma parte importante para a otimização de qualquer modelo de banco de dados. E para o meu ponto de vista não relacionado ao php.
VGE

Respostas:

242

Você definitivamente deve gastar algum tempo lendo sobre a indexação, há muito escrito sobre isso e é importante entender o que está acontecendo.

Em termos gerais, um índice impõe uma ordem nas linhas de uma tabela.

Por uma questão de simplicidade, imagine que uma tabela seja apenas um grande arquivo CSV. Sempre que uma linha é inserida, é inserida no final . Portanto, a ordem "natural" da tabela é apenas a ordem na qual as linhas foram inseridas.

Imagine que você carregou esse arquivo CSV em um aplicativo de planilha muito rudimentar. Tudo o que essa planilha faz é exibir os dados e numerar as linhas em ordem seqüencial.

Agora imagine que você precisa encontrar todas as linhas que possuem algum valor "M" na terceira coluna. Dado o que você tem disponível, você tem apenas uma opção. Você digitaliza a tabela verificando o valor da terceira coluna para cada linha. Se você tem muitas linhas, esse método (uma "verificação de tabela") pode demorar muito tempo!

Agora imagine que, além desta tabela, você tenha um índice. Esse índice específico é o índice de valores na terceira coluna. O índice lista todos os valores da terceira coluna, em alguma ordem significativa (digamos, em ordem alfabética) e, para cada um deles, fornece uma lista de números de linhas onde esse valor aparece.

Agora você tem uma boa estratégia para encontrar todas as linhas em que o valor da terceira coluna é "M". Por exemplo, você pode executar uma pesquisa binária ! Enquanto a varredura da tabela exige que você procure N linhas (onde N é o número de linhas), a pesquisa binária exige apenas que você observe as entradas do índice log-n, no pior dos casos. Uau, isso é muito mais fácil!

Obviamente, se você possui esse índice e está adicionando linhas à tabela (no final, já que é assim que nossa tabela conceitual funciona), é necessário atualizar o índice todas as vezes. Assim, você trabalha um pouco mais enquanto escreve novas linhas, mas economiza muito tempo ao procurar algo.

Portanto, em geral, a indexação cria uma troca entre eficiência de leitura e eficiência de gravação. Sem índices, as inserções podem ser muito rápidas - o mecanismo de banco de dados apenas adiciona uma linha à tabela. À medida que você adiciona índices, o mecanismo deve atualizar cada índice enquanto executa a inserção.

Por outro lado, as leituras se tornam muito mais rápidas.

Espero que isso cubra suas duas primeiras perguntas (como outras pessoas responderam - você precisa encontrar o equilíbrio certo).

Seu terceiro cenário é um pouco mais complicado. Se você estiver usando o LIKE, os mecanismos de indexação normalmente ajudarão na sua velocidade de leitura até o primeiro "%". Em outras palavras, se você estiver SELECIONANDO A coluna WHERE LIKE 'foo% bar%', o banco de dados usará o índice para encontrar todas as linhas em que a coluna começa com "foo" e precisará verificar esse conjunto de linhas intermediárias para encontrar o subconjunto que contém "bar". SELECT ... WHERE a coluna LIKE '% bar%' não pode usar o índice. Espero que você possa ver o porquê.

Por fim, você precisa começar a pensar em índices em mais de uma coluna. O conceito é o mesmo e se comporta de maneira semelhante ao material LIKE - essencialmente, se você tiver um índice em (a, b, c), o mecanismo continuará usando o índice da esquerda para a direita da melhor maneira possível. Portanto, uma pesquisa na coluna a pode usar o índice (a, b, c), como faria em (a, b). No entanto, o mecanismo precisaria fazer uma varredura completa da tabela se você estivesse pesquisando ONDE b = 5 EC = 1)

Espero que isso ajude a esclarecer um pouco, mas devo reiterar que é melhor você passar algumas horas procurando bons artigos que explicam essas coisas em profundidade. Também é uma boa ideia ler a documentação do servidor de banco de dados específico. A maneira como os índices são implementados e usados ​​pelos planejadores de consultas pode variar bastante.

timdev
fonte
10
E os FULLTEXTíndices? Eles podem ajudar com condições como LIKE '%bar%'?
Septagram 15/03
2
@ Septagram - FULLTEXTpode ajudar com essa consulta se bar for uma "palavra". FULLTEXTlida com palavras, não com substrings arbitrários (como LIKEfaz).
Rick James
@timdev explicitamente em que parte foi respondida a primeira pergunta? Posso detectar as segunda e terceira questões respondidas na primeira e segunda parte (antes e depois da Esperemos que cobre suas duas primeiras questões ) de sua resposta valiosa
Manuel Jordan
1
@ManuelJordan - Não há uma resposta simples para a primeira pergunta. Depende de como você deseja equilibrar as compensações no contexto do uso antecipado (ou melhor ainda, observado).
timdev 19/10/19
57

Confira apresentações como Mais dominando a arte da indexação .

Atualização 12/2012: Publiquei uma nova apresentação minha: Como criar índices, realmente . Apresentei isso em outubro de 2012 na ZendCon em Santa Clara e em dezembro de 2012 na Percona Live London.

A criação dos melhores índices é um processo que precisa corresponder às consultas que você executa no seu aplicativo.

É difícil recomendar regras de uso geral sobre quais colunas são melhores para indexar ou se você deve indexar todas as colunas, sem colunas, quais índices devem abranger várias colunas etc. Isso depende das consultas que você precisa executar.

Sim, há alguma sobrecarga, portanto você não deve criar índices desnecessariamente. Mas você deve criar os índices que beneficiam as consultas necessárias para executar rapidamente. A sobrecarga de um índice é geralmente superada por seus benefícios.

Para uma coluna que é VARCHAR (2500), você provavelmente deseja usar um índice FULLTEXT ou um índice de prefixo:

CREATE INDEX i ON SomeTable(longVarchar(100));

Observe que um índice convencional não pode ajudar se você estiver procurando por palavras que possam estar no meio desse longo varchar. Para isso, use um índice de texto completo.

Bill Karwin
fonte
3
Muito obrigado. slideshare.net/matsunobu/… foi realmente muito útil.
Bishal Paudel
1
Excelente a apresentação de slideshare.net/billkarwin/how-to-design-indexes-really #
Manuel Jordan
1
Apresentação incrível (A de 2012), realmente entendeu todo o sentido dos índices.
DarkteK
46

Não repetirei alguns dos bons conselhos em outras respostas, mas acrescentarei:

Índices compostos

Você pode criar índices compostos - um índice que inclui várias colunas. O MySQL pode usá-los da esquerda para a direita . Então, se você tem:

Table A
Id
Name
Category
Age
Description

se você tiver um índice composto que inclua Nome / Categoria / Idade nessa ordem, essas cláusulas WHERE usariam o índice:

WHERE Name='Eric' and Category='A'

WHERE Name='Eric' and Category='A' and Age > 18

mas

WHERE Category='A' and Age > 18

não usaria esse índice porque tudo precisa ser usado da esquerda para a direita.

Explicar

Use Explain / Explain Extended para entender quais índices estão disponíveis para o MySQL e qual ele realmente seleciona. O MySQL usará apenas UMA chave por consulta .

EXPLAIN EXTENDED SELECT * from Table WHERE Something='ABC'

Log de consulta lento

Ative o log de consultas lentas para ver quais consultas estão sendo lentas.

Colunas largas

Se você tiver uma coluna ampla em que a maior parte da distinção ocorre nos primeiros vários caracteres, poderá usar apenas os primeiros N caracteres no seu índice. Exemplo: temos uma coluna ReferenceNumber definida como varchar (255), mas 97% dos casos, o número de referência é 10 caracteres ou menos. Alterei o índice para olhar apenas os 10 primeiros caracteres e melhorou bastante o desempenho.

Eric J.
fonte
Eu tenho uma pergunta sobre a última parte. Li em algum lugar que, se você criar uma coluna com VARCHAR, sempre deverá configurá-la para 255. Agora, você disse que um índice definido para esse tipo de coluna pode ser limitado a apenas os 10 primeiros caracteres. Como exatamente você pode fazer isso?
AlexioVay
20

Se uma tabela tiver seis colunas e todas elas puderem ser pesquisadas, devo indexar todas ou nenhuma delas

Você está pesquisando campo por campo ou algumas pesquisas estão usando vários campos? Quais campos estão sendo mais pesquisados? Quais são os tipos de campo? (O índice funciona melhor em INTs do que em VARCHARs, por exemplo) Você tentou usar EXPLAIN nas consultas que estão sendo executadas?

Quais são os impactos negativos no desempenho da indexação

UPDATEs e INSERTs serão mais lentos. Há também os requisitos adicionais de espaço de armazenamento, mas isso não é importante nos dias de hoje.

Se eu tiver uma coluna VARCHAR 2500 pesquisável em partes do meu site, devo indexá-la

Não, a menos que seja UNIQUE (o que significa que já está indexado) ou você só procure correspondências exatas nesse campo (sem usar a pesquisa de texto completo do LIKE ou do mySQL).

Geralmente eu coloco um índice em todos os campos que procurarei ou selecionarei usando uma cláusula WHERE

Normalmente, indexaria os campos mais consultados e, em seguida, INTs / BOOLEANs / ENUMs, em vez dos campos VARCHARS. Não se esqueça, muitas vezes você precisa criar um índice em campos combinados, em vez de um índice em um campo individual. Use EXPLAIN e verifique o log lento.

Pete
fonte
11

Carregar dados com eficiência : os índices aceleram as recuperações, mas reduzem a velocidade de inserções e exclusões, além de atualizações de valores nas colunas indexadas. Ou seja, os índices diminuem a maioria das operações que envolvem gravação. Isso ocorre porque a gravação de uma linha requer a gravação não apenas da linha de dados, mas também de alterações em quaisquer índices. Quanto mais índices uma tabela possui, mais alterações precisam ser feitas e maior a degradação média do desempenho. A maioria das tabelas recebe muitas leituras e poucas gravações, mas para uma tabela com uma alta porcentagem de gravações, o custo da atualização do índice pode ser significativo.

Evitar índices : se você não precisar de um índice específico para ajudar as consultas a terem um desempenho melhor, não o crie.

Espaço em disco : um índice ocupa espaço em disco e vários índices ocupam correspondentemente mais espaço. Isso pode fazer com que você atinja um limite de tamanho de tabela mais rapidamente do que se não houver índices. Evite índices sempre que possível.

Para viagem: Não exagere no índice

Srikar Doddi
fonte
5

Em geral, os índices ajudam a acelerar a pesquisa no banco de dados, com a desvantagem de usar espaço em disco extra e reduzir a velocidade de consultas INSERT/ UPDATE/ DELETE. Use EXPLAINe leia os resultados para descobrir quando o MySQL usa seus índices.

Se uma tabela tiver seis colunas e todas elas forem pesquisáveis, devo indexar todas ou nenhuma?

A indexação de todas as seis colunas nem sempre é a melhor prática.

(a) Você usará alguma dessas colunas ao procurar informações específicas?

(b) Qual é a seletividade dessas colunas (quantos valores distintos são armazenados, em comparação com a quantidade total de registros na tabela)?

O MySQL usa um otimizador baseado em custo, que tenta encontrar o caminho "mais barato" ao executar uma consulta. E campos com baixa seletividade não são bons candidatos.

Quais são os impactos negativos no desempenho da indexação?

Já respondeu: espaço em disco extra, desempenho inferior durante a inserção - atualização - exclusão.

Se eu tiver uma coluna VARCHAR 2500 pesquisável em partes do meu site, devo indexá-la?

Experimente o Índice FULLTEXT .

Um machado
fonte
4

1/2) Os índices aceleram certas operações de seleção, mas desaceleram outras operações, como inserir, atualizar e excluir. Pode ser um bom equilíbrio.

3) use um índice de texto completo ou talvez esfinge

Paul Creasey
fonte
Para impedir que slow down other operations like insert, update and deletesvocê possa usar o START TRANSACTION; YOUR CODE HERE; COMMIT What pode ajudar a evitar slowing downas outras operações, pois ele só verifica uma das restrições uma vez. CAVEAT: Se você usar REPLACE INTOe seu SQL_MODE<> STRICT_ALL_TABLESOU TRADITIONALO Bulk Loadignorará a substituição e inserirá duplicatas.
JayRizzo
Transações não são suportadas em todos os mecanismos MySQL. AFAIK, as transações diminuem a velocidade das operações do banco de dados, mesmo que sejam usadas apenas implicitamente. O que precisamos projetar com base no desempenho real é uma maneira semi-automática de criar um perfil (medir o desempenho) de várias opções de otimização, incluindo índices e transações.
David Spector