Eu li artigos sobre FORCE
índice, mas como posso forçar o MySQL a IGNORE ALL
indexar?
Eu tentei SELECT * FROM tbl IGNORE INDEX(*)
, mas não tive sucesso.
Quanto ao motivo pelo qual eu (e outros) preciso fazer isso: Por exemplo, eu precisava resumir as estatísticas de 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 sempre tenho que ver quais índices estão definidos ou determinar qual índice será usado via Explicar. Seria muito útil simplesmente escrever IGNORE INDEX ALL
e simplesmente não se importar.
Alguém sabe a sintaxe ou um hack? (Dezenas de linhas via tabelas de definição do MySQL não são realmente um atalho).
Adicionado da discussão do bate -papo :
Marca de referência:
sem índice = 148,5 segundos
com índice = 180 segundos e ainda rodando com Enviando 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;
InnoDB, o teste com índice (sem USE INDEX() ou similar) ainda está em execução, 250 segundos, acabei de matá-lo.
Não está absolutamente claro por que você deseja isso, mas pode usar a dica
USE INDEX ()
para dizer ao otimizador para não usar nenhum índice. Dos documentos do MySQL: dicas de índiceSua consulta se torna:
Nota lateral: a expressão complexa:
pode ser simplificado de 4 chamadas de função para 1:
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 Índice Agrupado. No entanto, ainda existe outra maneira, 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
domain_name
será verificado. Sedomain_name
estiver indexado, você deve escolher uma coluna para oWHERE column_name=column_name
que não esteja indexado.Acabei de tentar isso em uma mesa grande em um servidor Staging
Nenhum índice foi escolhido
Supondo que você tenha esses dois índices:
Então não importa o que o otimizador faz; ele deve digitalizar essencialmente uma quantidade idêntica de material.
Caso 1: Faz um scan da tabela (ou usa domain_id): Vai fazer o scan dos pares (id, name), localizando todos os nomes, fazendo o SUBSTRING..LOCATE, GROUP BY, e finalmente ORDER BY. O GROUP BY e o ORDER BY provavelmente precisam de uma tabela tmp e filesort. Verifique
EXPLAIN SELECT ...
se isso acontece.Caso 2: Ele faz uma varredura de índice (do nome_do_domínio): Esse índice realmente contém pares (nome, id) -- porque o InnoDB implicitamente coloca o 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 - 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% dele, devido a esta ser uma varredura de tabela/índice?) Se couber, execute a consulta duas vezes. A segunda vez será cerca de 10 vezes mais rápida devido a não atingir o disco (caching).Se esta for uma tarefa única, o SSD ajudará. Caso contrário, e você pode armazenar em cache a tabela inteira, isso não ajudará depois que o buffer_pool for carregado.