2011-01-04 12 views
6

Ich habe eine große Tabelle, aus der ich große Mengen von Zeilen auswählen muss.MySQL Compound-Index wird nicht verwendet

Die Tabelle speichert Anrufdetailsätze (CDRs). Beispiel:

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

Da meine Anfragen für einen Kunden Anrufe in bestimmten Terminen suchen, ich indiziert calldate und account zusammen in einem Clustered-Index wie folgt:

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 

Wenn jedoch die folgende Abfrage ausgeführt wird, die EXPLAIN Ergebnis zeigt, daß nur die Datumzeit Teil des Schlüssels verwendet wird:

Abfrage:

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

EXPLAIN Ergebnis:

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

Es scheint nur die ersten 8 Bytes (das Datum Teil des Schlüssels) verwendet wird. Die WHERE-Klausel verweist jedoch explizit auf beide Teile des Schlüssels mit einem AND, sodass theoretisch der vollständige Schlüssel verwendet werden sollte.

Sollte ich separate Indizes für Calldate und Accountcode erstellen und sie vom Abfrageoptimierer zusammenführen lassen? Warum wird der vollständige Index nicht verwendet?

Danke für die Hilfe!

+0

Es scheint, als ob es 100% aller Zeilen mit dieser Abfrage gefiltert hat. Ist das nicht der Wert der gefilterten Spalte? Können Sie ein Beispiel angeben, das diese Filterung nicht bietet? Ich stimme einer der Antworten unten zu, Sie sollten zuerst den Filter und dann die Sortierung haben. Index Kontocode, Anruf. Sie sollten ein viel besseres Ergebnis erhalten. – TheJacobTaylor

Antwort

6

Kurze Antwort: Sie könnten den Index hier effektiver verwenden, wenn Ihr Schlüssel (accountcode, calldate) statt (calldate, accountcode) lautet.

Der beste Weg, das Problem zu verstehen, besteht darin, mehrspaltige Schlüssel als eine Verkettung der verschiedenen Spalten zu betrachten. Wenn beispielsweise Spalte 1 die Werte "A, B, C, D" und Spalte 2 "W, X, Y, Z" hätte, würde man einen Index für "AW, BX, CY, DZ" usw. erstellen und alles setzen von denen in einen B-Baum.

Um eine Bereichsabfrage durchzuführen, finden Sie den ersten Nachfolger des unteren Bereichs und iterieren, bis Sie den oberen Bereich überschritten haben. Dies bedeutet, dass Sie den Index nur effektiv verwenden können, um eine Bereichsabfrage für ein Suffix des Schlüssels durchzuführen.

+0

Vielen Dank für die Einsicht, wie Bereichsabfragen auf mehrspaltigen Schlüsseln funktionieren, die Erklärung war sehr wertvoll! In der Tat wird der volle Index verwendet, wenn die Schlüssel umgekehrt angeordnet sind. –

+0

@Vinay, Nun, das ist vorgesehen **, wenn ** 'accountcode' größere Kardinalität hat als' calldate'. – Pacerier

1

Da Sie nach einer Reihe von Daten suchen (> '2010-12-01'), sehe ich nicht, wie der Optimierer den vollständigen Index verwenden könnte. Das Beste, was es tun kann, ist die Suche nach dem passenden Accountcode. Wenn Sie jetzt nach genau einem Datum und genau einem Accountcode suchen, würde ich erwarten, dass der vollständige Index verwendet wird.

Verwandte Themen