Verbesserung der MySQL -Effizienz
-
16-10-2019 - |
Frage
Ich habe eine Tabelle, die jetzt über 43 Millionen Datensätze enthält. Ausführen
SELECT
, Normalerweise wähle ich Datensätze mit demselben Feld aus, sagen wirA
. Wird es effizienter sein, die Tabelle durch verschiedene Tische in mehrere Tabellen zu unterteilen?A
und in der Datenbank speichern? Wie viel kann ich gewinnen?Ich habe einen Tisch mit dem Namen
entry: {entryid (PK), B}
, enthält 6.000 Datensätze und mehrere andere Tabellen mit der ähnlichen StrukturT1: {id(PK), entryid, C, ...}
, über Millionen von Aufzeichnungen. Haben die folgenden zwei Prozesse die gleiche Effizienz?SELECT id FROM T1, entry WHERE T1.entryid = entry.entryid AND entry.B = XXX
und
SELECT entryid FROM entry WHERE B = XXX
//format a string S as (entryid1, entryid2, ... )
//then run
SELECT id FROM T1 WHERE entryid IN S
Lösung
In diesem Fall werde ich zuerst Ihre zweite Frage beantworten.
Es gibt eine Möglichkeit, die Fragen zu mischen, um sich als eine zu verhalten und es effizient zu tun.
Ihre erste Methode ist eine Abfrage, die sich wie folgt verhält
- Beitritt von
T1
undentry
durchentryid
Bildung einer riesigen Temperaturtabelle - Überqueren Sie die Temperaturtabelle, um die WHERE -Klausel zu verarbeiten
Ihre zweite Methode sind im Wesentlichen zwei Abfragen
- Sieh nach oben
entryid
wobei B ein Wert xxx ist - Alles kompilieren
entryid
Werte in einer Zeichenfolge - Ausführen von Abfragen mithilfe
WHERE entryid IN
- Die übereinstimmende Liste in einer nicht indizierten Temperaturtabelle
- Kartesianische Beitritt zurück zu T1, um zu sehen, welche Werte übereinstimmen
In beiden Fällen müssen Sie immer noch eine Temperaturtabelle von bilden entryid
Werte
Sie müssen die Ausführung der Abfrage neu organisieren, auch bekannt als Refactoring.
Hier ist Ihre erste Abfrage, die total neu gestaltet ist:
SELECT
A.entryid
FROM
(SELECT entryid id FROM entry WHERE B = XXX) A
LEFT JOIN T1 USING (id)
;
Dies präsentiert Ihre Frage, aber es macht zwei Dinge
- Es stellt zuerst in der Liste der Einträge mit der Where -Klausel zusammen
- Es führt den Join basierend auf der Länge der Unterabfrage a durch
Diese Umstrukturierung sollte die Verarbeitung ohne zusätzliche Tabellenänderungen beschleunigen.
Seit der Unterabfrage A wird jedoch erhältlich entryid
Werte basierend auf dem Wert von B
, Sie sollten einen Index haben, der diese schnell zusammenrunden. Bitte erstellen Sie diesen Index:
ALTER TABLE entry ADD INDEX B_entryid_ndx (B,entryid);
Mit dieser neuen neu refaktorierten Abfrage und der Erstellung dieses zusätzlichen Index ist es so schnell wie möglich, da die Refactoring -Kräfte, wo sie vor dem Zusammenfügen stattfinden können, umgestaltet werden.
In Bezug auf Ihre erste Frage sollte die refaktorierte Abfrage genau das abrufen, was sie braucht, unabhängig davon, ob sie nicht aufgeteilt ist. Die Partitionierung wäre nur eine Auswahl der Speichermotorauswahl.
MySQL unterstützt zwei Paradigmen für die Partitionierung
- Lagernmotor zusammenführen (Mapping identisch strukturierte MyISAM -Tabellen als eine)
- Tischpartitionierung
Mit der Merge -Speicher -Engine gibt es keinen langen Migrationspfad. Die Zuordnung findet in 2 Sekunden statt. Die Wartung jeder einzelnen Tabelle kann eine Abfrage gegen die Merge -Engine beeinflussen, wenn es keinen Primärschlüssel gibt, um ein MyISAM -Tisch aus einer anderen MyISAM -Tabelle einzigartig zu identifizieren.
Mit der Tabellenpartition verfügt die einzelnen Tabellen mit einer Partitionskarte ein. Die Mapping kann einen Migrationspfad enthalten. Die Wartung ist nur eine gemischte Tasche wie bei jedem anderen Tisch.
In beiden Fällen muss ein gut gestaltetes Indexierungsschema vorhanden sein. Wieso den? Die Abfrage ist wo, bestellen von und gruppen nach Klauseln sollte bestimmen, welche Indizes wirklich benötigt werden, um die Abfrage zu unterstützen.
Andere Tipps
Ich würde über die Verwendung von Tabellenpartitionierung nachdenken. Sie erwähnen keine MySQL -Version oder Speicher -Engine -Typen. Hier ist der DOC -Link:
http://dev.mysql.com/doc/refman/5.6/en/partitioning.html
für 5.6