Eu li artigos sobre FORCE
índice, mas como posso forçar o MySQL a IGNORE ALL
índices?
Eu tentei SELECT * FROM tbl IGNORE INDEX(*)
, mas não tive sucesso.
Quanto ao motivo pelo qual eu (e outros) precisamos fazer isso: Por exemplo, eu precisava resumir as estatísticas dos referenciadores por tld assim:
SELECT
count(*) as c,
SUBSTRING
(
domain_name,
LENGTH(domain_name) - LOCATE('.', REVERSE(domain_name)) + 2
) as tld
FROM `domains_import`
IGNORE INDEX(domain_name)
GROUP BY tld
ORDER BY c desc
LIMIT 100
... mas eu sempre tenho que olhar para quais índices são definidos ou determinar qual índice será usado pelo Explain. Seria muito útil simplesmente escrever IGNORE INDEX ALL
e simplesmente não se importar.
Alguém conhece a sintaxe ou um hack? (Dezenas de linhas através de tabelas de definição do MySQL não são realmente um atalho).
Adicionado a partir da discussão no chat :
Bechmark:
sem índice = 148,5 segundos
com índice = 180 segundos e ainda em execução com o envio de dados A matriz SSD é tão poderosa que você quase não se importa com o cache de dados ...
Definição para benchmark:
CREATE TABLE IF NOT EXISTS `domains_import` (
`domain_id` bigint(20) unsigned NOT NULL,
`domain_name` varchar(253) CHARACTER SET ascii COLLATE ascii_bin NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `domains_import`
ADD PRIMARY KEY (`domain_id`),
ADD UNIQUE KEY `domain_name` (`domain_name`);
ALTER TABLE `domains_import`
MODIFY `domain_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT;
No InnoDB, o teste com o índice (sem USE INDEX () ou similar) ainda está em execução, 250 segundos, acabei de o matar.
LEFT JOIN
eu tinha. `USE INDEX ()` fez o MySQL fazer uma varredura de tabela em uma tabela de 20K linhas e 1 paraJOIN
1s em vez de cruzar 500 linhas entre dois índices. Ficou 20x mais rápido.Você também pode incorporar
WHERE 1=1
ypercube acabou de me perguntar
Sim, mas você deu ao MySQL uma consulta realmente idiota.
1=1
reverteria para o Clustered Index. Não obstante, ainda existe outro caminho, mas requer ser um pouco malicioso para o Optimizer.Isso lançará todos os índices sob o barramento, com certeza, porque o valor de cada linha para
domain_name
muito será verificado. Sedomain_name
estiver indexado, você deve escolher uma coluna para aWHERE column_name=column_name
que não está indexada.Eu apenas tentei isso em uma tabela grande em um servidor intermediário
Nenhum índice é escolhido
fonte
WHERE id+0 = id*1
o índice ainda será usado e um extraUsing where
aparecerá.Supondo que você tenha esses dois índices:
Então não importa o que o otimizador faz; deve escanear essencialmente uma quantidade idêntica de material.
Caso 1: Faz uma varredura de tabela (ou usa domain_id): Ele varre (pares de identificação, nome), localizando todos os nomes, executando SUBSTRING..LOCATE, GROUP BY e, finalmente, ORDER BY. O GROUP BY e o ORDER BY provavelmente precisam de uma tabela tmp e de arquivos. Verifique
EXPLAIN SELECT ...
para ver se faz.Caso 2: Ele faz uma varredura de índice (de domain_name): esse índice realmente contém pares (nome, id) - porque o InnoDB coloca implicitamente a PK no final de qualquer chave secundária. O restante do processamento é paralelo ao Caso 1.
Uma coisa pode ser diferente - o tamanho dos dois BTrees. Faça
SHOW TABLE STATUS LIKE domains_import
para ver o Data_length (para o Caso 1) e o Index_length (para o Caso 2). O BTree maior será mais lento.Outra coisa pode ser diferente - armazenamento em cache. Qual é o valor de
innodb_buffer_pool_size
? Quanta RAM você tem? Os Dados (ou Índice) podem estar contidos no buffer pool. (Ou será 37%, por ser uma varredura de tabela / índice?) Se for o caso, execute a consulta duas vezes. A segunda vez será cerca de 10 vezes mais rápida devido a não bater no disco (cache).Se esta for uma tarefa única, o SSD ajudará. Caso contrário, e você pode armazenar em cache a tabela inteira, ela não ajudará depois que o buffer_pool for carregado.
fonte