2011-01-04 18 views
6

Tengo una gran tabla de la que debo seleccionar grandes cantidades de filas.Índice compuesto MySQL no utilizado

Los tabla almacena registros detallados de llamadas (CDR). Ejemplo:

+-------------+--------------+------+-----+---------------------+----------------+ 
| Field  | Type   | Null | Key | Default    | Extra   | 
+-------------+--------------+------+-----+---------------------+----------------+ 
| id   | int(45)  | NO | PRI | NULL    | auto_increment | 
| calldate | datetime  | NO | MUL | 0000-00-00 00:00:00 |    | 
| accountcode | varchar(100) | NO |  |      |    | 
| other... | varchar(45) | NO |  |      |    | 

Desde mis consultas buscar un cliente llamadas en ciertas fechas, me indexado calldate y accountcode juntos en un índice agrupado así:

CREATE TABLE `cdr` (
    `id` int(45) NOT NULL AUTO_INCREMENT, 
    `calldate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
    `accountcode` varchar(100) NOT NULL DEFAULT '', 
    other fields... 
PRIMARY KEY (`id`), 
KEY `date_acc` (`calldate`,`accountcode`) USING BTREE 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 

Sin embargo, al ejecutar la siguiente consulta, el EXPLAIN resultado muestra que sólo la parte de fecha y hora de la clave se está utilizando:

consulta:

SELECT * 
FROM cdr 
WHERE calldate > '2010-12-01' 
    AND accountcode = 'xxxxxx'; 

EXPLAIN resultado:

+----+-------------+-------+-------+---------------+----------+---------+------+---------+----------+-------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | filtered | Extra  | 
+----+-------------+-------+-------+---------------+----------+---------+------+---------+----------+-------------+ 
| 1 | SIMPLE  | cdr | range | date_acc  | date_acc | 8  | NULL | 3312740 | 100.00 | Using where | 
+----+-------------+-------+-------+---------------+----------+---------+------+---------+----------+-------------+ 

Parece solamente los primeros 8 bytes (la parte de fecha de la clave) se está utilizando. Sin embargo, la cláusula WHERE hace referencia explícitamente a ambas partes de la clave con un AND, por lo que, en teoría, debe utilizarse la clave completa.

¿Debo crear índices separados para calldate y accountcode y dejar que el optimizador de consultas a fusionar? ¿Por qué no se usa el índice completo?

¡Gracias por la ayuda!

+0

Parece que filtró el 100% de todas las filas con esa consulta. ¿No es ese el valor de la columna filtrada? ¿Puedes dar un ejemplo que no tenga ese filtrado? Estoy de acuerdo con una de las respuestas a continuación, primero debe tener el filtro, luego el género. index accountcode, calldate. Deberías obtener un resultado mucho mejor. – TheJacobTaylor

Respuesta

6

Respuesta corta: Usted sería capaz de utilizar el índice más efectivamente aquí si su clave era (accountcode, calldate) en lugar de (calldate, accountcode).

La mejor manera de entender el problema es por el pensamiento de llaves de varias columnas como una concatenación de las diferentes columnas. Como ejemplo, si la columna 1 tuviera los valores 'A, B, C, D' y la columna 2 'W, X, Y, Z', construiría un índice sobre 'AW, BX, CY, DZ' etc. y pondría todo de aquellos en un B-tree.

Para hacer una consulta gama, se encuentra el primer sucesor del extremo inferior de la gama, e iterar hasta que se excede el rango superior. Esto significa que solo puede usar efectivamente el índice para hacer una consulta de rango en un sufijo de la clave.

+0

Gracias por la información sobre cómo funcionan las consultas de rango en claves de varias columnas, ¡la explicación fue muy valiosa! De hecho, el índice completo se utiliza si las claves se ordenan al revés. –

+0

@Vinay, bien eso se proporciona ** si ** 'accountcode' tiene mayor cardinalidad que' calldate'. – Pacerier

1

Puesto que usted está buscando un rango de fechas (> '2010-12-01'), no veo cómo el optimizador puede utilizar el índice completo. Lo mejor que puede hacer es escanear el rango de fechas buscando el código de cuenta correspondiente. Ahora, si estuviera buscando exactamente una fecha y exactamente un código de cuenta, entonces esperaría que se utilizara el índice completo.

Cuestiones relacionadas