2015-10-23 9 views
5

Im Folgenden sind drei MySQL-Abfragen. Der erste gibt alles zurück, was ich in einer Abfrage suche, während die zweiten beiden die gleichen Gesamtergebnisse liefern, aber in zwei Abfragen.Warum benötigen diese MySQL-Abfragen so drastisch unterschiedliche Verarbeitungszeiten, wenn sie gleichwertig erscheinen?

Ich wundere mich, warum die einzelne Abfrage dauert 2-100s mal länger zu laufen, wenn es scheint, wie Prozesszeit sollte zwischen allen drei Abfragen gleich sein. Gibt es eine Möglichkeit, die einzelne Abfrage so schnell wie die einzelnen Abfragen zu optimieren? Das Hinzufügen von mehr ORs innerhalb der WHERE-Anweisung der einzelnen Abfrage erhöht nicht die Prozesszeit, aber ich habe Fälle, in denen ich viel mehr ORs ausführen muss und die einzelne Abfrage schließlich so schnell ist wie zehn einzelne Abfragen.

Die einzelne Abfrage scheint auch nach der Ausführung zwischengespeichert zu werden, und das erste Mal kann Minuten dauern, während die einzelnen Abfragen immer innerhalb desselben Zeitrahmens abgeschlossen werden.

Würde ein mehrspaltiger Index hier einen großen Unterschied machen?

Bemerkenswert ist, dass die Tabelle kein ID-Feld als primären Index hat. Führt das zu diesem unerwünschten Verhalten?

Es ist schwierig, hier Tests auszuführen, da die Tabelle hundert Millionen Zeilen enthält und das Hinzufügen von Spalten und Indizes fast einen Tag dauert.

SINGLE QUERY (4.2S)

SELECT name_id 
FROM staging_company_search 
WHERE 
    (name_word_0 = 'the' AND name_word_1 = 'glazier') 
    OR (name_word_0 = 'bridgewaters' AND name_word_1 = ''); 

ÄQUIVALENTEN QUERIES AGGREGATE (0,8 s jeweils)

SELECT name_id 
FROM staging_company_search 
WHERE name_word_0 = 'the' AND name_word_1 = 'glazier'; 

SELECT name_id 
FROM staging_company_search 
WHERE name_word_0 = 'bridgewaters' AND name_word_1 = ''; 

ON EXPLAIN diese Abfragen

id  select_type table      type possible_keys    key   key_len ref rows  extra 
1  SIMPLE   staging_company_search range name_word_0,name_word_1 name_word_0 102  NULL 2197605 Using index condition; Using where 
1  SIMPLE   staging_company_search ref  name_word_0,name_word_1 name_word_1 102  const 128  Using index condition; Using where 
1  SIMPLE   staging_company_search ref  name_word_0,name_word_1 name_word_0 102  const 33  Using index condition; Using where 

DATABASE SCHEMA

CREATE TABLE `staging_company_search` (
    `name_id` int(11) unsigned NOT NULL DEFAULT '0', 
    `name_word_0` varchar(100) NOT NULL, 
    `name_word_1` varchar(100) NOT NULL, 
    KEY `name_id` (`name_id`), 
    KEY `name_word_0` (`name_word_0`), 
    KEY `name_word_1` (`name_word_1`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 
+0

Was passiert, wenn Sie versuchen, WO (name_word_0, name_word_1) in ((im Folgenden ', 'Glaserei'), ('Bridgewaters', '')) in der ersten Abfrage? –

+0

Noch langsamer. Diese Abfrage enthält auch etwas andere Logik und führt zu vier Kombinationen von name_words im Gegensatz zu zwei. –

+0

Ich verstehe. Wie wäre es mit einer Vereinigung der beiden äquivalenten Aggregatabfragen? Zeigt der EXPLAIN PLAN einen Unterschied zwischen diesen beiden? –

Antwort

2

Dies liegt daran, dass MySQL nur einen Index für eine einfache Abfrage verwendet.

Wenn es eine Wahl zwischen mehreren Indizes, MySQL verwendet normalerweise den Index, der die kleinste Anzahl von Zeilen (der selektivsten Index) findet.

Allerdings kann und wird mysql zwei Indizes seit Version 5.0 bis Index merge optimization verwenden. Leider passiert es nicht immer und selbst wenn es passiert sind die Ergebnisse aren't all that great.

Die erste EXPLAIN-Ausgabe zeigt, dass die Indexverschmelzungsoptimierung in Ihrer Abfrage mit der OR-Klausel nicht verwendet wird. Es ist nur über den Index auf name_word_0

name_word_0 ist für WHERE name_word_0 = 'the' AND name_word_1 = 'glazier'; aber als der Ausgang für die dritte zeigt erklären, es ist überhaupt nicht geeignet für WHERE name_word_0 = 'bridgewaters' AND name_word_1 = '';

Daher ist die kombinierte Abfrage ist wirklich langsam. Sie können dies überwinden, indem Sie einen zusammengesetzten Index erstellen, der name_word_0 und name_word_1 umfasst. Ich habe bemerkt, dass deine Schlüssellänge sehr lang ist. Sie können einen Teilindex erstellen und die Dinge wahrscheinlich noch weiter beschleunigen.

CREATE INDEX word01 ON staging_company_search (name_word_0(20), name_word_1(20)) 
2

Ich bin kein Experte, aber ich glaube, dass dies wegen der ist, wie MySQL verwaltet die Indizes, wo sie für mehrere Bedingungen überprüfen müssen („OR“). Dies wird in der "EXPLAIN-Abfrage" gesehen, in der erwartet wird, dass die erste Abfrage mehr Zeilen prüfen muss, bevor das Ergebnis zurückgegeben wird.

Ich glaube, dass die Vereinigung von zwei kleinen Ergebnissen eine bessere Leistung erzielen sollte. Können Sie Folgendes versuchen?

SELECT name_id 
FROM staging_company_search 
WHERE (name_word_0 = 'the' AND name_word_1 = 'glazier') 
UNION ALL  
    SELECT name_id 
    FROM staging_company_search 
    WHERE (name_word_0 = 'bridgewaters' AND name_word_1 = ''); 
2

Die Verwendung einer OR-Klausel in der ersten Abfrage verhindert die Verwendung Ihres Indexes. MySQL ist auf diese Weise ein bisschen dumm. Es macht einen vollständigen Tabellenscan: Blick auf jede Zeile. Es ist viel besser, nur AND-Abfragen zu verwenden, die zusammen UNION sind.

Um Ihre AND-only-Abfragen noch schneller zu machen, erstellen Sie einen zusammengesetzten Index unter (name_word_0, name_word_1, name_id). Ihre Abfragen können durch einen zufälligen Zugriff auf diesen Index vollständig erfüllt werden und sollten mit einer zwei Megarow-Tabelle untergeordnet ausgeführt werden.

Verwandte Themen