Beeinflusst die Reihenfolge der Spalten in einer WHERE-Klausel in MySQL die Abfrageleistung?


38

Ich habe Leistungsprobleme bei bestimmten Datenbankabfragen mit möglicherweise großen Ergebnismengen.

Bei der fraglichen Abfrage habe ich drei ANDs in der WHERE-Klausel

Ist die Reihenfolge der Klauseln wichtig?

Wie in, wenn ich die ASI_EVENT_TIME-Klausel an die erste Stelle setze (da dies die meisten Ergebnisse aus den Klauseln entfernen würde).

Verbessert dies die Laufzeit der Abfrage?

ABFRAGE:

SELECT DISTINCT  activity_seismo_info.* 
FROM `activity_seismo_info` 
WHERE 
    activity_seismo_info.ASI_ACTIVITY_ID IS NOT NULL  AND 
    activity_seismo_info.ASI_SEISMO_ID IN (43,44,...,259) AND 
    (
        activity_seismo_info.ASI_EVENT_TIME>='2011-03-10 00:00:00' AND 
        activity_seismo_info.ASI_EVENT_TIME<='2011-03-17 23:59:59'
    ) 

ORDER BY activity_seismo_info.ASI_EVENT_TIME DESC

Erklärung der Abfrage:

+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
| id | select_type | table   | type  | possible_keys             | key          | key_len | ref  | rows  | Extra                       |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+ 
|  1 | SIMPLE      | act...o | range | act...o_FI_1,act...o_FI_2 | act...o_FI_1 | 5       | NULL | 65412 | Using where; Using filesort |
+----+-------------+---------+-------+---------------------------+--------------+---------+------+-------+-----------------------------+

Verwenden von:

PHP 5.2

MySQL 5.0.51a-3ubuntu5.4

Antrieb 1.3

Symfony 1.2.5


Die BESTELLUNG DURCH dauert wahrscheinlich so lange. "Using filesort" kann sehr langsam sein. Ich habe festgestellt, dass das Bestellen in der Anwendungslogik VIEL schneller ist als das Verwenden von ORDER BY.
Maclema

Dieselbe Frage habe ich vor einiger Zeit (vor dieser Site) beim Stackoverflow gestellt. Überprüfen Sie die Links auf Antworten, die ich dort erhalten habe. stackoverflow.com/questions/3805863/…
Scott

2
@maclema - Wenn Ihre Anwendung nicht auf einem weitaus schnelleren Computer als Ihre Datenbank ausgeführt wird, ist Ihre Behauptung zweifellos falsch, ganz zu schweigen von der sinnlosen Last all dieser Sortierlogik in Ihrer Anwendung. order bygehört in die Datenbank.
Jack Douglas

Antworten:


24

Das glaube ich nicht. Das Abfrageoptimierungsprogramm sollte clever genug sein.

Sie können versuchen, die WHERE-Klauseln neu anzuordnen, und sehen, dass EXPLAINS Ihnen dies jeweils mitteilt.


Informationen zur Optimierung dieser Abfrage: Gibt es einen Index für ASI_EVENT_TIME? (Dies ist meiner Meinung nach das Entscheidendste für diese Abfrage, da Sie auch die Ergebnisse danach sortieren).

Gibt es Indizes für die anderen beiden Felder (ASI_SEISMO_ID und ASI_ACTIVITY_ID)?

Es wäre hilfreich, wenn Sie die Tabellenstruktur posten würden.


Ich hätte nie gedacht, einen Index der Ereigniszeiten zu erstellen. Ich werde das morgen auf einer Entwickler-Datenbank versuchen und prüfen, ob es einen merklichen Unterschied gibt.
Patrick

@Patrick Angenommen, alle anderen Abfragen, die diesen Index verwenden, ordnen dieses Datum in absteigender Reihenfolge an, möchten Sie den Indexschlüssel (activity_seismo_info.ASI_EVENT_TIME) auch in absteigender Reihenfolge anordnen.
Matt M

@MattM Ich wusste nicht, dass Sie einen Indexschlüssel bestellen KÖNNTEN. Ehrfürchtig Wenn ich den Indexschlüssel bestelle, beeinträchtigt dies zwangsläufig die Leistung in der entgegengesetzten Richtung, bis zu dem Punkt, dass sie schlechter ist als kein Indexschlüssel?
Patrick

@Patrick Du hast recht. Mein Gehirn steckt im SQL Server-Land fest. Sie können die Sortierreihenfolge in MYSQL angeben und es wird analysiert, aber es wird ignoriert. Alle Indizes werden in MYSQL in aufsteigender Reihenfolge sortiert. Entschuldigung für die Verwirrung.
Matt M

13

Aus der Dokumentation :

Wenn die Tabelle einen mehrspaltigen Index enthält, kann der Optimierer jedes Präfix ganz links des Index zum Suchen von Zeilen verwenden. Wenn Sie beispielsweise einen dreispaltigen Index für (col1, col2, col3) haben, haben Sie indizierte Suchfunktionen für (col1), (col1, col2) und (col1, col2, col3).

MySQL kann keinen Index verwenden, wenn die Spalten kein Präfix ganz links vom Index bilden.

Also ja, es sollte die gleiche Reihenfolge wie die Spalten in einem zusammengesetzten Index haben .


4
Wenn die Tabelle über einen mehrspaltigen Index verfügt, spielt die Auswahl der Spalten auf der linken Seite eine Rolle - die Reihenfolge, in der Sie sie auswählen, spielt jedoch keine Rolle. Wenn Sie also den Index a, b, c haben und dies tun, ist WHERE c = 'foo' AND a = 'bar' AND b = 'foobar'der Index weiterhin zur Verwendung berechtigt.
Texelate

10

Nein, das spielt keine Rolle.

Der Optimierer führt eine Reihe einfacher Transformationen durch, nachdem er die SQL analysiert hat - dies ist eine davon.


8

WO FOO UND BAR

optimiert das selbe wie

WO Bar und Foo

Jedoch,

WO ungleich 1 UND ungleich 2

Beide Teile können nicht optimiert werden. Beispielsweise,

WO EIN ZWISCHEN 1 UND 3 UND B> 17

kann INDEX (a, b) oder INDEX (b, a) nicht gut gebrauchen

Um es anders auszudrücken, werden zuerst alle '=' Tests verwendet, die in der WHERE-Klausel UND-verknüpft sind. Dann kann ein Nicht-'=' (IN, BETWEEN,>, etc) behandelt werden. Nicht mehr als einer kann effektiv optimiert werden.

Ihre Anfrage enthält 3 solche Klauseln.

Wie sich herausstellt, ist INDEX (EVENT_TIME) wahrscheinlich das nützlichste - es hilft bei einem der ANDs und kann verwendet werden, um "filesort" für ORDER BY zu vermeiden.

Wenn es keine doppelten Zeilen gibt (warum zum Teufel würde es da sein?), Dann werde DISTINCT los. Das verursacht noch mehr Aufwand.

Bitte geben Sie SHOW CREATE TABLE und SHOW TABLE STATUS an, wenn Sie Fragen zur Leistung stellen.

Update ... Neuere Versionen (z. B. MySQL 5.7) können in einigen Situationen IN( list of constants )fast so behandelt werden =. Um auf Nummer sicher zu gehen, halten Sie sich an diese Reihenfolge (jeder Teil ist optional):

  1. Beliebig viele =.
  2. Einige INs.
  3. Höchstens eine Reichweite.

1

MySQL, wo Optimierungsdokument sagt:

Sie könnten versucht sein, Ihre Abfragen neu zu schreiben, um Rechenoperationen zu beschleunigen und gleichzeitig die Lesbarkeit zu beeinträchtigen. Da MySQL ähnliche Optimierungen automatisch durchführt , können Sie diese Arbeit oft vermeiden und die Abfrage in einer verständlicheren und besser zu wartenden Form hinterlassen. Einige der von MySQL durchgeführten Optimierungen sind:

  • ...

  • Für jede Tabelle in einem Join, ein einfacherer WHERE konstruiert ist , ein schnell zu bekommen WHERE Auswertung für die Tabelle und auch Reihen so schnell wie möglich zu überspringen .

  • Jeder Tabellenindex wird abgefragt und der beste Index wird verwendet, es sei denn, das Optimierungsprogramm ist der Ansicht, dass die Verwendung eines Tabellenscans effizienter ist . Zu einem Zeitpunkt wurde ein Scan verwendet, der darauf basierte, ob der beste Index mehr als 30% der Tabelle umfasste, aber ein fester Prozentsatz bestimmt nicht mehr die Wahl zwischen einem Index oder einem Scan. Das Optimierungsprogramm ist jetzt komplexer und stützt seine Schätzung auf zusätzliche Faktoren wie Tabellengröße, Anzahl der Zeilen und E / A-Blockgröße.

Auf diese Weise ist es sinnvoll, dass der Abfrageoptimierer die WIE-Reihenfolge weglässt, in der wir die Spalten in der Abfrage verwendet haben (Nicht nur MySQL, sondern auch SQL ist eine deklarative Sprache und muss tun, was wir wollen, nicht wie wir wollen).

Ich mag es immer noch, die gleiche Sortierung für die Spalten eines zusammengesetzten Schlüssels in der Abfrage zu haben, aber es ist manchmal unvermeidlich, wenn wir beispielsweise ORM oder ActiveRecord verwenden. In einigen Frameworks wie yii2 wird das Anpassen der Beziehungskriterien an das Ende von angehängt eine "Ein" -Zustand, aber wir benötigen immer noch die Funktionen von QueryBuilders in verschiedenen Teilen einer Anwendung.


-2

JEDES Feld, das in Ihren WHERE / HAVING-Klauseln verwendet wird und eine hohe Selektivität aufweist (die Anzahl der eindeutigen Werte / die Gesamtzahl der Datensätze> 10% ~ 20%), MUSS indiziert werden.

Wenn Ihre ASI_EVENT_TIMESpalte also viele mögliche Werte enthält, indizieren Sie sie zuerst alle. Versuchen Sie dann, wie @ypercube sagte, sie neu anzuordnen und sehen Sie, was EXPLAIN Ihnen sagt. Sollte in etwa gleich sein.

Darüber hinaus möchten Sie einen Blick auf die Indizierung von SQL LIKE-Filtern werfen . Es ist zwar nicht das, worauf Sie eine Antwort benötigen, aber Sie werden trotzdem lernen, wie die Indizierung unter der Haube funktioniert.

* Bearbeiten: Weitere Informationen zur Indizierung finden Sie in den Kommentaren unter den unten angegebenen Links.


8
-1 Das Indizieren jeder Spalte ist KEINE bewährte Methode. Jeder Index kostet Sie in mehrfacher Hinsicht. Stellen Sie sicher, dass Sie gute Indizes auswählen, die normalerweise aus mehreren Spalten bestehen, normalerweise in der Reihenfolge der verwendeten Selektivität und Häufigkeit. Dies kann SQL Server sein, die Indexinformationen sind jedoch weiterhin gültig: sqlskills.com/BLOGS/KIMBERLY/post/… .
Eric Humphrey - Lotsahelp

@Eric Humphrey +1 Für die Erklärung und den Link zu Kimberlys Site.
Matt M

Wenn Sie sich irren, kann der Index einer Spalte Ihre Leistung bei ausgewählten Abfragen beeinträchtigen : mysqlperformanceblog.com/2007/08/28/… . Sie sollten NIEMALS die Faustregel anwenden: Manchmal funktioniert es, manchmal nicht.
sumar

Ich stimme zu. Dies gilt jedoch, wenn die Werteselektivität gering ist. In Anbetracht des von Patrick (diesem Frageautor) verwendeten Datentyps DATETIME wird eine Indizierung empfohlen. Normalerweise hat dieser Feldtyp einen ziemlich großen Wertesatz, es sei denn, es gibt eine merkwürdige Situation, wenn er nur mehrere mögliche Daten verwendet. * Ich werde meine Antwort oben bearbeiten, um eine klarere und gültigere Aussage zu machen.
Eye
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.