Estou tentando indexar meu blogentries
banco de dados para obter um melhor desempenho, mas encontrei um problema.
Aqui está a estrutura:
CREATE TABLE IF NOT EXISTS `blogentries` (
`id_id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`title_id` varchar(100) COLLATE latin1_german2_ci NOT NULL,
`entry_id` varchar(5000) COLLATE latin1_german2_ci NOT NULL,
`date_id` int(11) NOT NULL,
PRIMARY KEY (`id_id`)
)
ENGINE=MyISAM
DEFAULT CHARSET=latin1
COLLATE=latin1_german2_ci
AUTO_INCREMENT=271;
Uma consulta como a seguinte usa o índice corretamente:
EXPLAIN SELECT id_id,title_id FROM blogentries ORDER by id_id DESC
+ ---- + ------------- + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- + | id | select_type | mesa | tipo | possible_keys | chave key_len | ref linhas | Extra | + ---- + ------------- + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- + | 1 | SIMPLES | blogentries | índice | NULL PRIMÁRIO 114 NULL 126 Usando índice | + ---- + ------------- + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- +
No entanto, quando adiciono o entry_id
na SELECT
consulta, ele usa o filesort
EXPLAIN SELECT id_id,title_id,entry_id FROM blogentries ORDER by id_id DESC
+ ---- + ------------- + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- + | id | select_type | mesa | tipo | possible_keys | chave key_len | ref linhas | Extra | + ---- + ------------- + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- + | 1 | SIMPLES | blogentries | TUDO | NULL NULL NULL NULL 126 Usando filesort | + ---- + ------------- + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- +
Fiquei me perguntando por que isso está acontecendo e como posso evitá-lo? É devido ao VarChar
, e isso deve ser alterado para outra coisa?
Estou tentando fazer com que todas as minhas consultas usem o índice, pois estou com valores Handler_read_rnd
e Handler_read_rnd_next
altos.
Se você precisar de outras informações, também posso publicá-las.
WHERE 1=1
à sua segunda consulta.SELECT @@sort_buffer_size
)?Respostas:
Como você não possui uma
WHERE
cláusula em nenhuma consulta, retornará todas as linhas nos dois casos, portanto, acho que o uso ou não uso do índice teria muito pouco impacto no desempenho nesses exemplos.fonte
ORDER BY
?varchar(5000)
.Conforme documentado em
ORDER BY
Otimização :Em seu artigo no blog O que exatamente é read_rnd_buffer_size , Peter Zaitsev explica:
Isso sugere que
max_length_for_sort_data
há um limite no tamanho total das colunas que você está selecionando, acima do qual afilesort
será usado em vez de uma classificação baseada em índice.No seu caso, selecionar
entry_id
(5002 bytes) assume o tamanho total sobre o valor padrão de 1KiB dessa variável e, portanto,filesort
é usado. Para aumentar o limite para 8KiB, você pode:fonte
Você obteve muitas respostas interessantes aqui, mas ninguém respondeu exatamente à pergunta - por que isso está acontecendo? Pelo que entendi, quando uma consulta SELECT contém dados de comprimento variável no MySQL, e não há índice que corresponda a TODAS as colunas solicitadas, ele sempre usará um tipo de arquivo. O tamanho dos dados não é muito relevante aqui. É difícil encontrar uma resposta direta a essa pergunta na documentação do MySQL, mas aqui está um bom post em que alguém está enfrentando um problema muito semelhante ao seu.
Veja também: 10 dicas para otimizar consultas MySQL (que não são ruins) .
Portanto, se for viável ter um índice em entry_id, você poderá adicioná-lo e estar pronto. Mas duvido que seja uma opção, então o que fazer?
Se você deve fazer algo sobre isso é uma questão separada. É importante saber que 'filesort' é mal nomeado no MySQL - é realmente apenas o nome do algoritmo usado para classificar essa consulta específica e, em muitos casos, a classificação realmente acontece na memória. Se você não espera que esta tabela cresça muito, provavelmente não é grande coisa.
Por outro lado, se esta tabela tiver um milhão de linhas, você poderá ter um problema. Se você precisar oferecer suporte à paginação de consultas nesta tabela, poderá ter um problema de desempenho realmente sério aqui. Nesse caso, particionar seus dados de tamanho variável em uma nova tabela e executar um JOIN para recuperá-los é uma otimização válida a ser considerada.
Aqui estão algumas outras respostas sobre SO que abordam essa questão:
fonte
filesort
aparentemente não foi usado nesse caso. Eu também acho que mesmo classificar uma tabela pequena na memória pode ser um impacto inaceitável no desempenho: por exemplo, se a consulta for realizada muito (e a tabela for alterada para que os caches não possam ser usados).Tente adicionar uma
WHERE
cláusula em suas consultas.http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html
fonte
ORDER BY
ele corresponde exatamente ao índice, portanto não há necessidade de ter umaWHERE
cláusula.Na medida do meu conhecimento, varchar pode conter apenas um máximo de 8000 bytes, que são aproximadamente 4000 caracteres. Assim, 5000 parece exceder o limite de armazenamento e, nesse caso, provavelmente a razão pela qual a classificação está ficando confusa.
"varchar [(n | max)] Dados de caracteres não Unicode de comprimento variável. n pode ser um valor de 1 a 8.000. max indica que o tamanho máximo de armazenamento é 2 ^ 31-1 bytes. O tamanho de armazenamento é o valor real comprimento dos dados inseridos + 2 bytes. Os dados inseridos podem ter 0 caracteres. Os sinônimos do SQL-2003 para varchar variam de char ou de caracteres. "
Espero que isso responda sua pergunta
fonte
CHAR
eVARCHAR
Types : "Os valores nas colunas VARCHAR são cadeias de comprimento variável. O comprimento pode ser especificado como um valor de 0 a 255 antes do MySQL 5.0.3 e de 0 a 65.535 na versão 5.0.3 e posterior. o comprimento máximo de aVARCHAR
no MySQL 5.0.3 e posterior está sujeito ao tamanho máximo de linha (65.535 bytes, que é compartilhado entre todas as colunas) e ao conjunto de caracteres usado. "Você só tem 126 linhas na sua tabela. Mesmo que todas as linhas tenham o tamanho máximo de cerca de 5 KB, isso significa que o tamanho total para leitura do disco é de apenas 600 KB - isso não é muito. Para ser franco, é uma quantidade muito pequena, provavelmente menor que o tamanho do cache da maioria das unidades de disco modernas.
Agora, se o servidor precisar recuperar seus dados para atender sua consulta, a operação mais cara será lê-los do disco. Porém, ler de acordo com a ordem do índice nem sempre é a maneira mais rápida de fazê-lo, especialmente quando a quantidade de dados é tão pequena.
No seu caso, é MUITO mais eficiente ler dados inteiros da tabela do disco como um único bloco na memória (provavelmente em apenas uma operação de leitura ou busca de disco) e depois classificá-los na RAM para satisfazer ORDER BY, que é instantâneo em comparação ao disco leia operação. Se o servidor ler seus dados de acordo com o índice, ele precisará emitir até 126 (oops!) Operações de leitura, buscando e retornando no mesmo arquivo de dados várias vezes.
Em outras palavras, a varredura seqüencial nem sempre é uma coisa ruim, e o mysql não é necessariamente estúpido. Se você tentar forçar o mysql a usar esse índice, provavelmente funcionará mais lentamente que a verificação seqüencial que você possui atualmente.
E a razão pela qual estava usando o índice quando o campo de 5 KB não foi incluído é porque os dados recuperados não constituíam 99% dos dados na tabela. Quando você incluiu seu campo de 5 KB, agora a consulta precisa ler 99% dos dados e é mais barato ler tudo e classificá-lo na memória posteriormente.
fonte
JOIN
condições eWHERE
cláusulas satisfatórias , nãoORDER BY
cláusulas.Qual versão do MySQL você está usando?
No 5.1, tentei configurar o seu cenário e preenchi alguns dados fictícios. Usando os SQLs que você forneceu, só recebo uma varredura de tabela a cada vez, de acordo com o EXPLAIN. Por padrão, quando você usa a ordem do MYSQL, recorre à classificação do arquivo, mesmo que o índice primário seja usado na ordem de.
fonte