Índice de cobertura usado apesar da falta da coluna

8

Eu tenho a seguinte consulta, usando MariaDB 10 / InnoDB:

SELECT id, sender_id, receiver_id, thread_id, date_created, content 
FROM user_message 
WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY date_created DESC 
LIMIT 20

Essa consulta busca mensagens de acordo com as condições especificadas e classifica por data de criação.

Eu tenho um índice de cobertura acabado (thread_id, date_created).

Ao executar EXPLAIN, o índice correto é usado e recebo a saída "Using where", embora a consulta esteja usando uma coluna no meio da instrução que não está no índice. Eu posso usar qualquer valor para "placeholder = x" e o resultado é o mesmo.

Se eu alterar a classificação para usar outra coluna, o EXPLAIN indica corretamente "Usando onde. Usando arquivosort".

Estou tendo um momento de coçar a cabeça. Alguém poderia esclarecer isso? O que eu esperaria ver é que seria necessária uma variedade de arquivos adicional, pois o índice de cobertura não poderia ser completamente usado devido à coluna adicional.

Tom
fonte

Respostas:

8


Consulta Caso A :

WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY some_column DESC 
LIMIT 20

Índice:

(thread_id, date_created)

Plano:

Index is used
Using Where
Using filesort

Não tem problema, certo? Se o índice for usado (para corresponder parcialmente à WHEREcondição), ainda precisamos de uma operação de classificação para ordenar os resultados por some_column(que não está no índice). Também precisamos de uma verificação extra (Usando Onde) para manter também apenas as linhas que correspondem à 2ª condição. ESTÁ BEM.


Caso B (a pergunta)
Consulta:

WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY date_created DESC 
LIMIT 20

Índice:

(thread_id, date_created)

Plano:

Index is used
Using Where
-- no "Using filesort"

Então, por que não precisa de uma classificação aqui ? Porque o índice é suficiente para classificar como a consulta deseja. Obviamente, existe o problema adicional da condição extra ( AND placeholder = FALSE) que não é coberta pelo índice.

OK, mas realmente não precisamos de um tipo aqui. O índice pode nos fornecer resultados que correspondem à primeira condição ( WHERE thread_id = 12345) e estão na ordem desejada para saída. A única verificação adicional de que precisamos - e o que o plano faz - é obter as linhas da tabela, na ordem fornecida pelo índice, e verificar essa segunda condição até obtermos 20 correspondências. É isso que significa "Usando Onde" ".

Podemos obter as 20 partidas nas primeiras 20 linhas (muito boas e rápidas) ou nas 100 primeiras (ainda é provável que seja suficientemente rápida) ou nos primeiros 1000000 (provavelmente muito, muito lentas) ou podemos obter apenas 19 partidas da tabela mesmo depois de ler todas as linhas correspondentes do índice (realmente muito lento em uma tabela grande). Tudo depende da distribuição dos dados.


Processo C (mesmo plano melhor)
Consulta:

WHERE thread_id = 12345 
  AND placeholder = FALSE
ORDER BY date_created DESC 
LIMIT 20

Índice:

(placeholder, thread_id, date_created)

Plano:

Index is used
-- no "Using Where"
-- no "Using filesort"

Agora, nosso índice corresponde às condições e à ordem de. O plano é bem simples: obtenha as primeiras * 20 correspondências do índice e leia as linhas correspondentes da tabela. Nenhuma verificação extra (Não "Usando Onde") e nenhuma classificação (não "Usando arquivosort") é necessária.

first *: os 20 primeiros ao ler o índice de trás para frente a partir do final (como temos ORDER BY .. DESC), mas isso não é um problema. Os índices da árvore B podem ser lidos para frente e para trás com desempenho quase igual.

ypercubeᵀᴹ
fonte
7
  • O uso do índice indica um " Índice de cobertura " - todas as colunas em qualquer lugar do site SELECTestão em qualquer lugar do índice. Portanto, você não tem um índice de "cobertura". E não é prático criar um índice de cobertura para sua consulta (muitas colunas mencionadas).
  • Usando onde - principalmente barulho.
  • Usando filesort - A consulta precisa de uma classificação, mas pode estar na RAM ou em uma tabela temporária. E pode haver vários tipos (por exemplo, GROUP BY x ORDER BY b)
  • Qualquer um deles permitirá olhar apenas para 20 linhas; qualquer outro índice exigirá que mais linhas sejam tocadas, possivelmente a tabela inteira:

    INDEX(thread_id, placeholder, date_created)
    INDEX(placeholder, thread_id, date_created)
  • Não, a cardinalidade dos componentes de um índice composto não importa ao ordenar as colunas no índice.

Meu Cookbook explica como obter o índice ideal, dado a SELECT.

Rick James
fonte
Obrigado pelo livro de receitas - folha muito agradável.
Tom