Estoy tratando de indexar mi blogentries
base de datos para un mejor rendimiento, pero encontré un problema.
Aquí está la estructura:
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;
Una consulta como la siguiente utiliza el índice correctamente:
EXPLAIN SELECT id_id,title_id FROM blogentries ORDER by id_id DESC
+ ---- + ------------- + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- + El | id | select_type | mesa | tipo | posibles_claves | clave | key_len | ref | filas | Extra | + ---- + ------------- + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- + El | 1 | SIMPLE | blogentries | indice | NULL | PRIMARIO | 114 NULL | 126 Usando index | + ---- + ------------- + ------------- + ------- + -------- ------- + --------- + --------- + ------ + ------ + -------- ----- +
Sin embargo, cuando agrego el entry_id
en la SELECT
consulta, usa el ordenamiento de archivos
EXPLAIN SELECT id_id,title_id,entry_id FROM blogentries ORDER by id_id DESC
+ ---- + ------------- + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- + El | id | select_type | mesa | tipo | posibles_claves | clave | key_len | ref | filas | Extra | + ---- + ------------- + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- + El | 1 | SIMPLE | blogentries | TODOS | NULL | NULL | NULL | NULL | 126 Usando ordenar archivos | + ---- + ------------- + ------------- + ------ + --------- ------ + ------ + --------- + ------ + ------ + ------------ ---- +
Me preguntaba por qué sucede esto y cómo puedo evitarlo. ¿Se debe al VarChar
, y eso debería cambiarse a otra cosa?
Estoy tratando de hacer que todas mis consultas usen el índice, ya que me encuentro con valores Handler_read_rnd
y Handler_read_rnd_next
valores altos.
Si necesita alguna otra información, también puedo publicarla.
WHERE 1=1
a su segunda consulta.SELECT @@sort_buffer_size
)?Respuestas:
Como no tiene una
WHERE
cláusula en ninguna consulta, está devolviendo todas las filas en ambos casos, por lo que creo que el uso o no uso del índice tendría muy poco impacto en el rendimiento en estos ejemplos.fuente
ORDER BY
?varchar(5000)
.Como se documenta en
ORDER BY
Optimización :En su artículo de blog ¿Qué es exactamente read_rnd_buffer_size? Peter Zaitsev explica:
Esto sugiere que
max_length_for_sort_data
hay un límite en el tamaño total de las columnas que uno está seleccionando, por encima del cualfilesort
se utilizará a en lugar de una clasificación basada en índices.En su caso, la selección
entry_id
(5002 bytes) toma el tamaño total sobre el valor predeterminado de 1 KB de esta variable y, porfilesort
lo tanto, se utiliza. Para elevar el límite a 8 KB, puede hacer lo siguiente:fuente
Has recibido muchas respuestas interesantes aquí, pero nadie ha respondido exactamente la pregunta: ¿por qué está sucediendo esto? Según tengo entendido, cuando una consulta SELECT contiene datos de longitud variable en MySQL, y no hay un índice que coincida con TODAS las columnas solicitadas, siempre usará un clasificador de archivos. El tamaño de los datos no es terriblemente relevante aquí. Es difícil encontrar una respuesta directa a esta pregunta en la documentación de MySQL, pero aquí hay una buena publicación de blog donde alguien está experimentando un problema muy similar al tuyo.
Consulte también: 10 consejos para optimizar las consultas de MySQL (que no apestan) .
Entonces, si es viable tener un índice en entry_id, entonces podría agregarlo y estar listo. Pero dudo que sea una opción, ¿qué hacer?
Si debe hacer algo al respecto es una pregunta aparte. Es importante saber que 'clasificador de archivos' está mal nombrado en MySQL : en realidad es solo el nombre del algoritmo utilizado para ordenar esta consulta en particular, y en muchos casos, el orden realmente sucederá en la memoria. Si no espera que esta tabla crezca mucho, probablemente no sea gran cosa.
Por otro lado, si esta tabla va a tener un millón de filas, es posible que tenga un problema. Si necesita admitir la paginación de consultas en esta tabla, entonces podría tener un problema de rendimiento realmente serio aquí. En ese caso, dividir sus datos de longitud variable en una nueva tabla y unir para recuperarlos es una optimización válida a tener en cuenta.
Aquí hay un par de otras respuestas sobre SO que hablan sobre esta pregunta:
fuente
filesort
aparentemente no se utilizó en ese caso. También creo que incluso ordenar una tabla pequeña solo en la memoria podría ser un golpe de rendimiento inaceptable: por ejemplo, si la consulta se realiza mucho (y la tabla cambia para que no se puedan usar los cachés).Intente agregar una
WHERE
cláusula a sus consultas.http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html
fuente
ORDER BY
, coincide exactamente con el índice, por lo que no es necesario tener unaWHERE
cláusula.Hasta donde yo sé, varchar solo puede contener un máximo de 8000 bytes, que son aproximadamente 4000 caracteres. Por lo tanto, 5000 parecería estar excediendo el límite de almacenamiento, y en este caso probablemente la razón por la cual la clasificación se está desordenando.
"varchar [(n | max)] Longitud variable, datos de caracteres no Unicode. n puede ser un valor de 1 a 8,000. max indica que el tamaño máximo de almacenamiento es 2 ^ 31-1 bytes. El tamaño de almacenamiento es el valor real longitud de los datos ingresados + 2 bytes. Los datos ingresados pueden tener una longitud de 0 caracteres. Los sinónimos SQL-2003 para varchar varían en caracteres o varían en caracteres ".
Espero que esto responda a su pregunta
fuente
CHAR
andVARCHAR
types : "Los valores en las columnas VARCHAR son cadenas de longitud variable. La longitud se puede especificar como un valor de 0 a 255 antes de MySQL 5.0.3 y de 0 a 65.535 en 5.0.3 y versiones posteriores. la longitud máxima de aVARCHAR
en MySQL 5.0.3 y posterior está sujeta al tamaño máximo de fila (65.535 bytes, que se comparte entre todas las columnas) y al conjunto de caracteres utilizado. "Solo tiene 126 filas en su tabla. Incluso si cada fila tiene un tamaño máximo de aproximadamente 5 KB, eso significaría que el tamaño total para leer desde el disco es solo de aproximadamente 600 KB, esto no es mucho. Para ser sincero, es una cantidad muy pequeña, probablemente menor que el tamaño de caché de la mayoría de las unidades de disco modernas.
Ahora, si el servidor necesita recuperar sus datos para cumplir con su consulta, la operación más costosa es leerlos desde el disco. Pero, leerlo de acuerdo con el orden del índice NO siempre es la forma más rápida de hacerlo, especialmente cuando la cantidad de datos es tan pequeña.
En su caso, es MUCHO más eficiente leer datos de la tabla completa del disco como un solo bloque en la memoria (probablemente en una sola operación de lectura o búsqueda de disco), y luego ordenarlo en RAM para satisfacer ORDER BY, que es instantáneo en comparación con el disco operación de lectura. Si el servidor lee sus datos de acuerdo con el índice, tendría que emitir hasta 126 (¡Uy!) Operaciones de lectura, buscando de ida y vuelta dentro del mismo archivo de datos muchas veces.
En otras palabras, la exploración secuencial NO siempre es algo malo, y mysql no es necesariamente estúpido. Si intenta forzar a mysql a usar ese índice, lo más probable es que funcione más lento que el análisis secuencial que tiene actualmente.
Y la razón por la que estaba usando el índice cuando no se incluyó el campo de 5 KB es porque los datos recuperados no constituían el 99% de los datos en la tabla. Cuando incluyó su campo de 5 KB, ahora la consulta tiene que leer el 99% de los datos, y es más barato leerlo todo y luego ordenarlo en la memoria.
fuente
JOIN
condiciones yWHERE
cláusulas satisfactorias , noORDER BY
cláusulas.¿Qué versión de MySQL estás usando?
EN 5.1, traté de configurar su escenario y llené algunos datos ficticios. Usando los SQL que proporcionó, solo obtengo un escaneo de tabla cada vez de acuerdo con EXPLAIN. Por defecto, cuando usa el orden por MYSQL, recurre al ordenamiento de archivos incluso si el índice primario se usa en el orden por.
fuente