2013-03-17 8 views
15

Ich bemerkte eine dramatisch von Geschwindigkeit zu verringern, wenn ich eine Abfrage 1 LIMIT statt 5.MySQL: Drastische langsamer Ausführung der Abfrage, wenn die Verwendung LIMIT 1 statt LIMIT 5

SELECT he. * 
FROM homematic_events he 
WHERE he.homematic_devices_id =30 
ORDER BY id DESC 
LIMIT 1 

statt

SELECT he. * 
FROM homematic_events he 
WHERE he.homematic_devices_id =30 
ORDER BY id DESC 
LIMIT 5 

Meine Tabelle enthält über 12 Millionen Zeilen mit folgenden Struktur:

CREATE TABLE IF NOT EXISTS `homematic_events` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `homematic_devices_id` int(11) DEFAULT NULL, 
    `address` char(16) COLLATE utf8_unicode_ci NOT NULL, 
    `interface_id` char(16) COLLATE utf8_unicode_ci NOT NULL, 
    `key` char(32) COLLATE utf8_unicode_ci NOT NULL, 
    `value` float(12,2) NOT NULL, 
    `timestamp` datetime NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `timestamp` (`timestamp`), 
    KEY `address` (`address`), 
    KEY `key` (`key`), 
    KEY `homematic_devices_id` (`homematic_devices_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=12637557 ; 

Diese explaination sind eine Geschwindigkeit mich asurment für LIMIT 5:

mysql> EXPLAIN SELECT he. * FROM homematic_events he WHERE he.homematic_devices_id =30 ORDER BY id DESC LIMIT 5; 
    +----+-------------+-------+------+----------------------+----------------------+---------+-------+------+-----------------------------+ 
    | id | select_type | table | type | possible_keys  | key     | key_len | ref | rows | Extra      | 
    +----+-------------+-------+------+----------------------+----------------------+---------+-------+------+-----------------------------+ 
    | 1 | SIMPLE  | he | ref | homematic_devices_id | homematic_devices_id | 5  | const | 4171 | Using where; Using filesort | 
    +----+-------------+-------+------+----------------------+----------------------+---------+-------+------+-----------------------------+ 


starting       0.000010 
checking query cache for query 0.000030 
Opening tables     0.000007 
System lock      0.000004 
Table lock      0.000015 
init        0.000019 
optimizing      0.000007 
statistics      0.000098 
preparing       0.000012 
executing       0.000002 
Sorting result     0.022965 
Sending data      0.000047 
end        0.000004 
query end       0.000002 
freeing items      0.000302 
storing result in query cache  0.000009 
logging slow query    0.000002 
cleaning up      0.000003 

Dies sind explaination eine Geschwindigkeit measurment für LIMIT 1:

mysql> EXPLAIN SELECT he. * FROM homematic_events he WHERE he.homematic_devices_id =30 ORDER BY id DESC LIMIT 1; 
+----+-------------+-------+-------+----------------------+---------+---------+------+------+-------------+ 
| id | select_type | table | type | possible_keys  | key  | key_len | ref | rows | Extra  | 
+----+-------------+-------+-------+----------------------+---------+---------+------+------+-------------+ 
| 1 | SIMPLE  | he | index | homematic_devices_id | PRIMARY | 4  | NULL | 3029 | Using where | 
+----+-------------+-------+-------+----------------------+---------+---------+------+------+-------------+ 

starting        0.000010 
checking query cache for query  0.000034 
Opening tables      0.000009 
System lock       0.000004 
Table lock       0.000015 
init         0.000020 
optimizing       0.000008 
statistics       0.000069 
preparing        0.000016 
executing        0.000002 
Sorting result      0.000005 
Sending data      502.290180 
end         0.000010 
query end        0.000003 
freeing items       0.000293 
logging slow query     0.000004 
logging slow query     0.000002 
cleaning up       0.000003 

Kann jemand dieses Verhalten erklären Sie mir bitte? Ich erwähne, dass es ein Ergebnis des unterschiedlichen Index ist, der mit LIMIT 1 arbeitet. Aber warum benutzt MySQL verschiedene Schlüssel für verschiedene LIMIT-Werte?

+0

klar sein, du sagst, die Abfrage dauert ** länger mit LIMIT 1 als mit LIMIT 5, oder? –

+0

das ist richtig - in diesem Fall etwa 20.000 mal länger ;-) – Stephan

Antwort

3

Aus irgendeinem Grund ist es für MySQL irgendwie schneller, den Primärschlüssel ID zu verwenden, um auf diese Zeilen statt auf den Index zuzugreifen. Auch wenn die Abfragen, die Sie verwenden, speziell das Feld verwenden, für das homematic_devices_id Index erstellt wurde. Ich finde es auch seltsam, dass MySQL im zweiten Fall nur homematic_devices_id unter possible_keys hat, aber dann PRIMARY statt wählt. Normalerweise zeigt MySQL sowohl PRIMARY als auch andere mögliche Indizes in dieser Spalte an.

Ist es möglich, dass es sich um ein datenabhängiges Problem handelt? Haben Sie Ihre Anfrage mit anderen Geräte-IDs versucht?

Versuchen Sie in beiden Fällen zu verwenden FORCE INDEX und sehen Sie, ob Sie das Problem beheben können.

+0

hast du recht. die Einheit SELECT er. * VON homematic_events ER FORCE INDEX (homematic_devices_id) WHERE he.homematic_devices_id = 30 ORDER BY ID DESC LIMIT 1 funktioniert gut! Danke – Stephan

1

Meine Vermutung ist, dass, wenn Sie und order by mit einem limit 1 kombiniert, wobei die Anforderung intern als max() (oder min) behandelt wird, die unmittelbar mit dem Index erreicht werden kann, während, wenn sie eine limit 5 bitten, die Bestellung muss zuerst komplett erledigt werden.

8

Mit LIMIT 1, nehme ich an, der Abfrage-Analysator reißt den Primärschlüssel herunter und findet den letzten Datensatz, dessen homematic_devices_id =30 - vermutlich, weil der Analysator die Operation "Sortieren" kennt, teurer sein wird.

Wenn Sie LIMIT 5, ich vermute der Query Analyzer beschließt, zuerst die Datensätze zu finden, und sortieren Sie sie dann. Wenn Sie diesen Vorgang beschleunigen möchten, können Sie einen Index sowohl für die homematic_devices_id als auch für die ID erstellen: ALTER TABLE homematic_events_test ADD INDEX ( homematic_devices_id, id) - Indem Sie zuerst die Geräte-ID eingeben, erhalten Sie die "Where" -Klausel und die ID-Spalte hilft dem SORT

+0

Sie erwähnen ALTER TABLE 'homematic_events_test' ADD INDEX (' id', 'homematic_devices_id')? – Stephan

+1

Ich habe die Antwort aktualisiert. –

+0

Warum hat das Limit 1 "Daten senden 502.290180" es hat die Daten an dieser Stelle gefunden, es sendet es zurück zu dem, was es angefordert hat – exussum