2009-08-02 17 views
3

Ich habe eine 2 GB MySQL-Tabelle mit 500.000 Zeilen und ich führe die folgende Abfrage auf einem System ohne Last.Wie kann diese langsame (sehr langsame) MySQL-Abfrage optimiert werden?

select * from mytable 
where name in ('n1', 'n2', 'n3', 'n4', ... bunch more...) 
order by salary 

Es dauert ein Filesort und zwischen 50 und 70 Sekunden abgeschlossen.

Wenn Sie die Bestellung nach Gehalt sortieren und die Sortierung in der Anwendung ausführen, verkürzt sich die Gesamtlaufzeit (einschließlich der Sortierung) auf ca. 25-30 Sekunden. Aber das ist immer noch viel zu viel.

Irgendeine Idee, wie ich das beschleunigen kann?

Vielen Dank.

+0

Bitte siehe: http://StackOverflow.com/Questions/1204402/How-do-Iask-for-Help-optimizing-Fixing-Queries-in-Mysql – hobodave

Antwort

5

Löschen Sie die Liste der Namen in eine temporäre Tabelle und führen Sie dann einen inneren Join auf den beiden Tabellen aus. Dieser Weg ist viel schneller, als die gesamte Liste für jede Zeile zu kämmen. Hier ist der Pseudo-Code:

create temporary table names 
    (name varchar(255)); 

insert into names values ('n1'),('n2'),...,('nn'); 

select 
    a.* 
from 
    mytable a 
    inner join names b on 
     a.name = b.name 

Beachten Sie auch, dass name sollte es einen Index haben. Das macht die Dinge viel schneller. Danke an Thomas, dass du diese Notiz geschrieben hast.

+3

Stellen Sie sicher, dass die ursprüngliche Tabelle einen Index für den Namen hat das Beste aus dem Beitritt machen. –

+0

Danke, das ist ein bisschen schneller; über 25s für die gleichen Abfragen, aber 25s ist immer noch nicht wirklich eine echte Verbesserung ... – CharlesS

+1

Mit oder ohne Bestellung von? Mit der Reihenfolge nach ist die Abfrage 50% schneller, ohne dass sie nur geringfügig schneller ist. Sie werden einen Index für beide Tabellen nur für Name benötigen. Führen Sie dann EXPLAIN für die Abfrage aus, um zu sehen, was sie tut. –

0
create index xyz on mytable(name(6)); 

„IN“ Abfragen sind fast alle Tage ineffizient, da sie wie diese konzeptionell verarbeitet werden:

select * from mytable where name = n1 
or name = n2 
or name = n3 
... 

Der Index I oben gegeben haben kann den Abfrageoptimierer bedeuten greift auf die Zeilen von Index anstelle von Tabellenscan.

+0

Können Sie einige Referenzen angeben, die beweisen, dass "IN" -Abfragen fast immer ineffizient sind? In meiner Erfahrung mit Mysql (5.0+) haben sie die gleiche Leistung, wenn Sie einen Join oder einen Equals verwenden (ein Name = 'xxx'). Ich denke, die wichtigsten Punkte sind korrekte Index- und Serverkonfiguration. –

1

Einige Ideen:

  • Haben Sie * werden die Auswahl müssen, können Sie entkommen mit nur eine Teilmenge der Auswahl?
  • Wenn Sie mit der Auswahl einer Untergruppe wegkommen können, können Sie einen abdeckenden Index hinzufügen könnte, ist, dass bereits nach Gehalt sortiert
  • Wenn alles das gleiche Muster hat könnte man LIKE (‚n%‘) tun
1

Versuchen Sie, die gewünschten Zeilen mit einer Unterabfrage auszuwählen und ordnen Sie dann die Ergebnisse dieser Unterabfrage an. See this question.

Und Sie haben einen Index auf name in mytable, Recht?

1

auf der Datenverteilung In Abhängigkeit und die Menge der Zeilen Ihres WHERE-Klausel übereinstimmt, sollten Sie einen Index für (Gehalt, Namen) oder sogar (Name, Gehalt) obwohl diese höchstwahrscheinlich nicht versuchen, für diese Art von Abfragen sehr nützlich sein. Sie können auch die sort_buffer_size Einstellung ändern. Testen Sie alles separat und vergleichen Sie die Ausgabe von EXPLAIN.

Verwandte Themen