2012-03-09 18 views
12

tengo una tabla de MySQL simple denominada 'prueba' con dos columnas:MySQL no mediante el índice de ORDER BY

  1. Auto columna incrementación int llamados 'id'
  2. VARCHAR (3000) columna llamada 'textcol '

Creo un índice en la tabla basado en la columna' textcol '. Sin embargo, la consulta ORDER BY no parece estar utilizando el índice, es decir, la instrucción EXPLAIN en una consulta simple con ORDER BY en textcol muestra NULL en la columna clave en su salida y también utiliza filesort.

Cualquier puntero para hacer cambios para ayudar a usar el índice para el ORDEN de consulta me será útil.

MySQL versión dada por comando "mysql --version':

mysql Ver 14,14 Distrib 01/05/58, por debian-linux-gnu (x86_64) usando readline 6,2

mysql> CREATE TABLE test (id INTEGER NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), textcol VARCHAR(3000)); 
Query OK, 0 rows affected (0.05 sec) 

mysql> DESCRIBE test; 
+---------+---------------+------+-----+---------+----------------+ 
| Field | Type   | Null | Key | Default | Extra   | 
+---------+---------------+------+-----+---------+----------------+ 
| id  | int(11)  | NO | PRI | NULL | auto_increment | 
| textcol | varchar(3000) | YES |  | NULL |    | 
+---------+---------------+------+-----+---------+----------------+ 
2 rows in set (0.00 sec) 

mysql> CREATE INDEX textcolindex ON test (textcol); 
Query OK, 0 rows affected, 2 warnings (0.06 sec) 
Records: 0 Duplicates: 0 Warnings: 0 

mysql> SHOW INDEX FROM test; 
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table | Non_unique | Key_name  | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| test |   0 | PRIMARY  |   1 | id   | A   |   0 |  NULL | NULL |  | BTREE  |   | 
| test |   1 | textcolindex |   1 | textcol  | A   |  NULL |  1000 | NULL | YES | BTREE  |   | 
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
2 rows in set (0.00 sec) 

mysql> INSERT INTO test (textcol) VALUES ('test1'); 
Query OK, 1 row affected (0.00 sec) 

mysql> INSERT INTO test (textcol) VALUES ('test2'); 
Query OK, 1 row affected (0.00 sec) 

mysql> INSERT INTO test (textcol) VALUES ('test3'); 
Query OK, 1 row affected (0.00 sec) 

mysql> INSERT INTO test (textcol) VALUES ('test4'); 
Query OK, 1 row affected (0.00 sec) 


mysql> EXPLAIN SELECT * FROM test ORDER BY textcol; 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra   | 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
| 1 | SIMPLE  | test | ALL | NULL   | NULL | NULL | NULL | 4 | Using filesort | 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
1 row in set (0.00 sec) 

mysql> EXPLAIN SELECT * FROM test ORDER BY id; 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra   | 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
| 1 | SIMPLE  | test | ALL | NULL   | NULL | NULL | NULL | 4 | Using filesort | 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
1 row in set (0.00 sec) 
+0

¿Sigues viendo esto con muchos datos en la tabla? Explicar no te dice qué hará siempre con esta consulta, solo qué haría con esta consulta en este momento. –

+0

Cambié el tamaño de la columna textcol a 10 bytes e inserté 30000 filas nuevas. ORDER BY en SELECT * todavía no usa el índice. Sin embargo, acabo de notar que una instrucción SELECT COUNT (*) usa el índice. ¿Alguna idea de por qué está pasando esto? – Kowshik

Respuesta

9

Ya que tiene que cargar toda la tabla para responder a la consulta y ordenar 4 elementos es barato, el optimizador de consultas podría evitar tocar el índice. ¿Todavía ocurre con tablas más grandes?

Tenga en cuenta que una columna varchar (3000) poder' t ser un índice de cobertura porque MySQL no incluirá más que los primeros 768 bytes de un varchar en un índice.

Si desea que la consulta solo lea el índice, el índice debe tener cada columna para la que está SELECT. En innodb, eso debería comenzar a funcionar para tu tabla de dos columnas una vez que hagas que textcol sea lo suficientemente pequeño; en MyISAM tendrá que incluir la columna de clave principal a sí mismo, como CREATE INDEX textcolindex ON test (textcol,id);

+0

Cambié el tamaño de la columna textcol a 10 bytes e inserté 30000 filas nuevas. ORDER BY en SELECT * todavía no usa el índice. Sin embargo, acabo de notar que una instrucción SELECT COUNT (*) usa el índice. ¿Alguna idea de por qué está pasando esto? – Kowshik

+1

Para aclarar, los índices son 1000 bytes límite para MyISAM y 767 para InnoDB, muy lejos de 3000 varchar campo. En efecto, MySQL usará un prefijo de índice, que se puede utilizar para ayudar a buscar (por ejemplo, cláusulas WHERE), pero no se puede usar para clasificar, ya que está incompleto: http://dev.mysql.com/doc/refman /5.0/en/order-by-optimization.html –

+1

@Kowshik, sin un índice de "cobertura", MySQL tendría que hacer 30,000 intentos para utilizar el índice. Un filesort es aún más fácil que 30,000 búsquedas. Intenta con 'SELECCIONAR textcol ORDER BY textcol' en su lugar. –

5

Algunos artículos útiles sobre la optimización ORDER BY:

http://www.mysqlperformanceblog.com/2006/09/01/order-by-limit-performance-optimization/

http://opsmonkey.blogspot.co.uk/2009/03/mysql-query-optimization-for-order-by.html

como se discute en gran medida, mantener el varchar abajo a 767 y agregue una clave para la orden por:

CREATE TABLE test (
id INTEGER NOT NULL AUTO_INCREMENT, 
textcol VARCHAR(767), 
PRIMARY KEY(id), 
KEY orderby (`textcol`) 
); 

Para evitar filesorts si la adición extra de 'dónde' parámetros, extienden la tecla '' OrdenarPor índice mediante un índice de varias columnas:

CREATE TABLE test (
id INTEGER NOT NULL AUTO_INCREMENT, 
tom INT(11) NOT NULL DEFAULT 0, 
gerry INT(11) NOT NULL DEFAULT 0, 
textcol VARCHAR(767), 
PRIMARY KEY(id), 
KEY orderby (`tom`,`gerry`, `textcol`) 
); 

también:

INSERT INTO test (tom, gerry, textcol) VALUES (1,2,'test4'); 
INSERT INTO test (tom, gerry, textcol) VALUES (1,2,'test2'); 
EXPLAIN SELECT id, textcol FROM test WHERE tom = 1 AND gerry =2 ORDER BY textcol; 

adicional: 'El uso de dónde; Usando el índice '

+0

Gracias por los enlaces. Aunque viejo, fueron útiles –

1

Tengo el mismo problema. MySQL es estúpido. fyi: tengo una mesa con más de 500,000,000 de registros. Yo quería a:

select * from table order by tid limit 10000000, 10; 

tres veces al día es la clave principal en la tabla y se indexa automáticamente por MySQL.

Esto llevó mucho tiempo y cancelé la consulta.luego dejo que mysql "explique" la consulta y reconozco que no usará el índice para la clave principal. después de leer muchos documentos de mysql intenté forzar a mysql a utilizar el índice a través de "USE INDEX (...)" y dis también no funcionó. Entonces reconocí que mysql parece correlacionar siempre la cláusula where con la cláusula order by. Así que traté de extender la cláusula where con una condición tocando el índice. Terminé con:

select * from table use index (PRIMARY) where tid > 0 order by tid limit 10000000, 10; 

donde tres veces al día es la clave principal en la tabla y es un valor de incremento automático que se inicia en 1.

Esto funcionó después dejo que explican la consulta MySQL para mí. Y he aquí: la consulta tomó solo 4 segundos.

+0

Gracias por publicar esto. Esto puede ser útil algún día –

Cuestiones relacionadas