2011-01-04 16 views
6

Ho una tabella grande da cui devo selezionare grandi quantità di righe.Indice composto MySQL non utilizzato

La tabella memorizza i record dei dettagli delle chiamate (CDR). Esempio:

+-------------+--------------+------+-----+---------------------+----------------+ 
| 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 |  |      |    | 

Poiché le mie domande cercano una clientela chiamate in determinate date, ho indicizzati calldate e accountcode insieme in un indice cluster in questo modo:

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 

Tuttavia, quando si esegue la seguente query, il SPIEGARE risultato mostra che solo la parte datetime della chiave viene utilizzato:

Query:

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

SPIEGARE risultato:

+----+-------------+-------+-------+---------------+----------+---------+------+---------+----------+-------------+ 
| 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 | 
+----+-------------+-------+-------+---------------+----------+---------+------+---------+----------+-------------+ 

Sembra solo i primi 8 byte (la porzione data della chiave) viene utilizzato. Tuttavia la clausola WHERE fa esplicitamente riferimento a entrambe le parti della chiave con un AND, quindi in teoria dovrebbe essere usata la chiave completa.

Devo creare indici separati per calldate e accountcode e consentire a Query Optimizer di unirli? Perché l'indice completo non viene utilizzato?

Grazie per l'aiuto!

+0

Sembra che abbia filtrato il 100% di tutte le righe con quella query. Non è questo il valore della colonna filtrata? Puoi fornire un esempio che non ha quel filtro? Sono d'accordo con una delle risposte qui sotto, dovresti prima avere il filtro, poi l'ordinamento. indice, codice dell'account. Dovresti ottenere un risultato molto migliore. – TheJacobTaylor

risposta

6

Risposta breve: Sarebbe in grado di utilizzare l'indice in modo più efficace qui se la chiave era (accountcode, calldate) anziché (calldate, accountcode).

Il modo migliore per comprendere il problema consiste nel pensare a chiavi a più colonne come una concatenazione delle diverse colonne. Ad esempio se la colonna 1 aveva i valori "A, B, C, D" e la colonna 2 "W, X, Y, Z" dovresti costruire un indice su "AW, BX, CY, DZ" ecc. E mettere tutto di quelli in un albero B.

Per eseguire una query di intervallo, si trova il primo successore di fascia bassa dell'intervallo e si itera fino a superare l'intervallo superiore. Ciò significa che puoi utilizzare efficacemente l'indice solo per eseguire una query di intervallo su un suffisso della chiave.

+0

Grazie per la comprensione di come le query di intervallo funzionano su chiavi a più colonne, la spiegazione è stata molto preziosa! In effetti, l'indice completo viene utilizzato se le chiavi vengono ordinate al contrario. –

+0

@Vinay, beh, questo è fornito ** se ** 'accountcode' ha una cardinalità maggiore di' calldate'. – Pacerier

1

Poiché si sta cercando un intervallo di date (> '2010-12-01'), non vedo come l'ottimizzatore potrebbe utilizzare l'indice completo. Il meglio che può fare è scansionare il range di date cercando il codice account corrispondente. Ora, se stavi cercando esattamente una data e esattamente un accountcode, allora mi aspetto che venga utilizzato l'indice completo.