Ich habe ein paar Duplikate in einer Datenbank, die ich überprüfen möchte. Was ich also getan habe, um zu sehen, welche Duplikate sind, habe ich folgendermaßen gemacht:
SELECT relevant_field
FROM some_table
GROUP BY relevant_field
HAVING COUNT(*) > 1
Auf diese Weise werden alle Zeilen mit relevantem_Feld mehr als einmal angezeigt. Die Ausführung dieser Abfrage dauert Millisekunden.
Jetzt wollte ich jedes der Duplikate untersuchen, also dachte ich, ich könnte jede Zeile in einer Tabelle mit einem relevanten Feld in der obigen Abfrage AUSWÄHLEN, also gefiel mir Folgendes:
SELECT *
FROM some_table
WHERE relevant_field IN
(
SELECT relevant_field
FROM some_table
GROUP BY relevant_field
HAVING COUNT(*) > 1
)
Dies stellt sich aus irgendeinem Grund als äußerst langsam heraus (es dauert Minuten). Was genau ist hier los, um es so langsam zu machen? relevant_field ist indiziert.
Schließlich habe ich versucht, aus der ersten Abfrage eine Ansicht "temp_view" zu erstellen (SELECT relevant_field FROM some_table GROUP BY relevant_field HAVING COUNT(*) > 1)
und stattdessen meine zweite Abfrage wie folgt durchzuführen :
SELECT *
FROM some_table
WHERE relevant_field IN
(
SELECT relevant_field
FROM temp_view
)
Und das funktioniert gut. MySQL erledigt dies in einigen Millisekunden.
Gibt es hier SQL-Experten, die erklären können, was los ist?
Antworten:
Schreiben Sie die Abfrage in diese um
Ich denke,
st2.relevant_field
muss in der Auswahl sein, weil sonst diehaving
Klausel einen Fehler gibt, aber ich bin nicht 100% sicherNiemals
IN
mit einer Unterabfrage verwenden. das ist notorisch langsam.Nur
IN
mit einer festen Werteliste verwenden.Mehr Tipps
SELECT *
wählen Sie nicht nur die Felder aus, die Sie wirklich benötigen.relevant_field
aktiviert haben, um den Equi-Join zu beschleunigen.group by
den Primärschlüssel verwenden.Allgemeine Lösung für 90% Ihrer
IN (select
AnfragenVerwenden Sie diesen Code
quelle
HAVING COUNT(*) > 1
. In MySQL ist es normalerweise schneller.st2.relevant_field
nicht der Fall istNULL
(es ist bereits in derON
Klausel enthalten), wird das Ergebnis nicht geändert .afield
niemals der Fall seinnull
wird. Dankegroup by
istst1.id
, nicht eingeschaltetst1.relevant_field
.Die Unterabfrage wird für jede Zeile ausgeführt, da es sich um eine korrelierte Abfrage handelt. Sie können eine korrelierte Abfrage in eine nicht korrelierte Abfrage verwandeln, indem Sie alles aus der Unterabfrage auswählen, wie folgt:
Die letzte Abfrage würde folgendermaßen aussehen:
quelle
SELECT *
Umhüllung erforderlich ist.Unterabfragen vs Joins
http://www.scribd.com/doc/2546837/New-Subquery-Optimizations-In-MySQL-6
quelle
Ich habe Ihre Abfrage in einer meiner Datenbanken ausprobiert und auch versucht, sie als Join zu einer Unterabfrage umzuschreiben.
Das hat viel schneller geklappt, probieren Sie es aus!
quelle
Versuche dies
quelle
Ich habe Ihre langsame SQL-Abfrage mit www.prettysql.net neu formatiert
Wenn Sie eine Tabelle sowohl in der Abfrage als auch in der Unterabfrage verwenden, sollten Sie beide immer wie folgt aliasisieren:
Hilft das?
quelle
Erstens können Sie doppelte Zeilen finden und die Anzahl der Zeilen wird wie oft verwendet und nach dieser Nummer sortiert.
Erstellen Sie anschließend eine Tabelle und fügen Sie das Ergebnis ein.
Löschen Sie schließlich die Zeilen für die Veröffentlichung. Nein ist Start 0. Mit Ausnahme der ersten Nummer jeder Gruppe löschen Sie alle Zeilen für die Veröffentlichung.
quelle
Manchmal, wenn die Daten größer werden, kann mysql WHERE IN aufgrund der Abfrageoptimierung ziemlich langsam sein. Versuchen Sie, mit STRAIGHT_JOIN mysql anzuweisen, die Abfrage unverändert auszuführen, z
Aber Vorsicht: In den meisten Fällen funktioniert der MySQL-Optimierer ziemlich gut. Ich würde daher empfehlen, ihn nur zu verwenden, wenn Sie solche Probleme haben
quelle
Dies ähnelt meinem Fall, in dem ich eine Tabelle mit dem Namen habe
tabel_buku_besar
. Was ich brauche sindAuf der Suche nach Aufzeichnungen, die
account_code='101.100'
intabel_buku_besar
denen habencompanyarea='20000'
und auchIDR
als habencurrency
Ich muss alle
tabel_buku_besar
Datensätze abrufen, deren Kontocode mit Schritt 1 identisch ist, abertransaction_number
in Schritt 1 das Ergebnis hatWährend der Verwendung
select ... from...where....transaction_number in (select transaction_number from ....)
läuft meine Abfrage extrem langsam und führt manchmal zu einem Zeitlimit für Anfragen oder dazu, dass meine Anwendung nicht reagiert ...Ich versuche diese Kombination und das Ergebnis ... nicht schlecht ...
quelle
Ich finde, dass dies am effizientesten ist, um festzustellen, ob ein Wert vorhanden ist. Die Logik kann leicht invertiert werden, um festzustellen, ob ein Wert nicht vorhanden ist (dh IS NULL).
* Ersetzen Sie das relevante_Feld durch den Namen des Werts, den Sie überprüfen möchten und der in Ihrer Tabelle vorhanden ist
* Ersetzen Sie den Primärschlüssel durch den Namen der Primärschlüsselspalte in der Vergleichstabelle.
quelle