2016-09-19 1 views
3

Ich habe eine Tabelle mit insgesamt 4 Millionen Zeilen.Schmerzhaft langsam MySQL-Abfrage mit indizierten Spalten

Wenn ich die folgende Abfrage ausführen, dauert es 40 Sekunden

SELECT * FROM `traffic` 
WHERE `callstart_timestamp` >= '2016-09-01 00:00:00' 
AND `callend_timestamp` <= '2016-09-18 00:00:00' 
AND app = 'XXXX' 

416040 insgesamt abgeschlossen ist, nahm Abfrage 40,0631 Sekunden.

Wenn ich die Bedingung AND app = 'XXXX' aus der Abfrage entfernen, wird es in weniger als einer Sekunde beendet.

Können Sie uns bitte mitteilen, was das Problem verursachen könnte, da alle Spalten indiziert sind?

Abfrage ERKLÄREN:

SIMPLE; traffic; NULL; ref; app,callend_timestamp,callstart_timestamp; app; 22; const; 1976467; 12.13; Using where; 

CREATE:

CREATE TABLE `traffic` (
    `id` varchar(20) NOT NULL, 
    `user_cli` varchar(15) NOT NULL, 
    `ddi` varchar(15) DEFAULT NULL, 
    `callstart_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    `callend_timestamp` timestamp NULL DEFAULT NULL, 
    `app` varchar(20) NOT NULL, 
    `lang` char(2) NOT NULL DEFAULT 'en' 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 


ALTER TABLE `traffic` 
    ADD PRIMARY KEY (`id`), 
    ADD KEY `app` (`app`), 
    ADD KEY `callend_timestamp` (`callend_timestamp`), 
    ADD KEY `callstart_timestamp` (`callstart_timestamp`), 
    ADD KEY `ddi` (`ddi`); 

UPDATE:

Ich habe einige der Antworten umgesetzt unten und sie hat mir sehr geholfen! Ich werde versuchen herauszufinden, welche Antwort besser zu meinem Fall passt. Ich werde mit den Ergebnissen aktualisieren.

+1

nur neugierig, Was passiert, wenn Sie die Verwendung von Index auf "App" deaktivieren? d. h., es treibt Daten statt "app" –

+0

Nur ein Vorschlag: Verschieben Sie die App in eine andere Tabelle und Referenz mit Fremdschlüssel. Dann filtern Sie einfach nach dem Primärschlüssel der App. Dies ist besonders praktisch, wenn dieselbe App varchar in vielen Zeilen verwendet wird. – drodil

Antwort

2

Die Standardantwort ist, einen Index für alle drei Spalten zu erstellen:

create index traffic_001 on traffic(app, callstart_timestamp, callend_timestamp) 

, die das allgemeine Prinzip der Umsetzung genau passende Spalten vor offener Bereichsanpassung diejenigen in der Index-Spalte-Liste folgt.

Aber es gibt eine andere Idee, die ich nicht gesehen getan haben, bevor das funktionieren könnte:

SELECT * FROM traffic 
WHERE callstart_timestamp between '2016-09-01 00:00:00' and callend_timestamp 
AND callend_timestamp between callstart_timestamp and '2016-09-18 00:00:00' 
AND app = 'XXXX' 

Logischer die Start-/Endwerte werden miteinander begrenzt. Vielleicht hilft das Codieren dieser Tatsache in die Abfrage, ohne einen Index hinzuzufügen.

+1

Der erste Index ist korrekt. Die Abfrage wird wahrscheinlich keinen Index verwenden. –

+0

@Gordon wahrscheinlich nicht, aber die Idee schien süß und ich hatte es vorher nicht gesehen (wahrscheinlich, weil es nicht funktioniert) – Bohemian

1

Try 1 Index für alle drei Spalten anstelle getrennten Indizes für jede Zugabe, die das Optimierungsprogramm mit dem Ausführungsplan verwirren:

CREATE INDEX idx_1 
ON traffic(app,callstart_timestamp,callend_timestamp); 
+0

Dies ist nicht der richtige Index für die Abfrage. –

+0

@GordonLinoff Mein schlechtes. – sagi

Verwandte Themen