Query optimieren

knabnetaD

Benutzer
Beiträge
12
Hallo zusammen,
ich verwende z.zt. folgende Query (auf nem MS SQL 2008 Server):

Code:
select a, b, c
from table
 
where ((b like '%bsp1%')
             or (b like '%bsp2%')
             or (b like '%bsp3%') )
 
and (not exists
             (select a
             from table2
             where table1.a = table2.a)
and not exists
             (select a
             from table3
             where table1.a = table3.a))

Was mich jetzt stört ist, dass das Ausführen dieser Query sehr lange braucht.
Die DB auf der die Query arbeitet ist nämlich einige GB groß und die Tabellen haben dementsprechend auch jeweils mehrer Millionen Einträge.

Kann ich die Query noch optimieren um die Laufzeit zu verbessern oder habt ihr sonst Ideen wie mir das gelingen kann?

Vielen Dank!
 
Werbung:
Hi

Hier im Forum gibt es auch ein Bereich für MS SQL evtl. helfen die dir dort eher als hier im MySql Forum.

Ansonsten kannst du mal diesen code versuchen (nicht getestet und ich weis nicht ob ein join schneller ist).

select a, b, c
from table

join table2 on table1.a != table2.a
join table3 on table1.a != table3.a

where tabelle.b like '%bsp1%' or
tabelle.b like '%bsp2%' or
tabelle.b like '%bsp3%'



gruß Neo
 
Also LIKE ist natürlich immer eine Bremse, kannst du da eventuell einen Ersatz für finden? Zumindest wäre es gut, wenn dein gesuchter String am Anfang der Tabelle stehen würde, dann würde ein Index auf der Spalte helfen. Das würde sicher mehr bringen als Syntax Änderungen.

Alternativ könnte man eine Sicht auf die mit LIKE gesuchten Datensätze erstellen oder noch besser, eine zusätzliche Spalte anlegen und befüllen um diesen Vorgang "Suche nach Zeichenkette" nicht jedesmal ausführen zu müssen.
 
Hi,

wie zuvor auch schon von ukulele geschrieben, ist die Filterung über ein Textfeld mit LIKE auswertungstechnisch eine echte "Katastrophe".
(Am liebsten wird so etwas auf ein Bemerkungsfeld gewünscht, welches ohnehin bereits liebend gerne entsprechende Textlängen hat und dann "vergewaltigt" werden soll, da die gewünschten Informationen in keinem anderen Feld der Applikation eingetragen werden können - aber genug über ständig bei mir einlaufende Anforderunge gejammert :rolleyes:)

Ich helfe mir, wo das möglich ist, mit einem berechneten Feld in der betreffenden Tabelle (was leisder nicht immer geht, insbesondere, wenn Replikation im Spiel ist).
Diese Felder haben den Vorteil, dass sie nur einmal pro Zeile berechnet werden und diese Berechnung auch nur dann durchgeführt wird, wenn der betreffende Eintrag in der Zeile geändert wird.
Insbesondere bei Tabelle mit mehreren Millionen Zeilen ist dieses Verhalten wichtig.

Auf diese berechneten Spalten kann man dann sogar noch einen Index setzen, was die ganze Sache dann rund macht.
Die WHERE-Clausel muss dann nur noch auf die berechnete Spalte angewendet werden.

Was definitiv performanter ist als ein JOIN ist die von dir bereits eingesetzte Unterabfrage mit EXISTS.
Hier solltest du nur noch einmal prüfen, ob in allen Tabellen auch ein Index auf die Verknüpfungs-Spalten gesetzt ist.
Die größte Performace holt man mit Indizes raus.

Wenn du die Gegenprobe mit einem Join machen möchtest, dann ist die Syntax von NeoPrince schon ganz nah dran.
Der Code würde dann so aussehen:

Code:
SELECT a,b,c
FROM table A
LEFT OUTER JOIN table1 B
    ON A.a=B.a
LEFT OUTER JOIN table2 C
    ON A.a=C.a
where (A.b like '%bsp1%' or
A.b like '%bsp2%' or
A.b like '%bsp3%')
AND B.a IS NOT NULL
AND C.a IS NOT NULL

Die LEFT OUTER JOINs machen die ganze Sache aber sehr langsam, insbesondere bei großer Datenmenge
(Aber auch hier: Indizes helfen!)

Viele Grüße,
Tommi
 
Hui

Ich hab immer gelernt Subabfragen sind böse... Dan muss ich wol noch mal ein bischen rumspielen.
Würde mich interessieren was schneller war knabnetaD

gruß Neo
 
@NeoPrince: generell ist das auch vollkommen korrekt, Sub-Select sind Sub-Optimal und man sollte dies vermeiden.
Insbesondere eine Unterabfrage, die Pro Zeile einen Spaltenwert ermittelt, ist der Tod einer jeden Abfrage-Performance. (-> ganz, ganz böse!!)
Unschön sind auch "hinzugejointe" Unterabfragen, da hier niemals ein günstiger Index für die Verknüpfung zu den anderen Tabellen der Abfrage genutzt werden kann. (-> böse!)
(Dennoch ist der SQL-Server auch hier oftmals recht fix, da dieser vorberechete Ausführungspläne nutzt.)

Etwas anders liegt der Fall bei einer EXISTS-Abfrage. Hier wird (laut Theorie) die erste Existienz einer Abfrage- und Verknüpfungs-Einschränkung geprüft,
dient also in erster Linie einer Logik-Klausel. Sobald das erste Ergebnis vorliegt, wird keine weitere Prüfung vorgenommen sondern das Ergebnis der Abfrage mit TRUE zurückgegeben.

Bei einer solchen logischen Einschränkung über JOINs ist die zu prüfende Datenmenge ungleich größer, was entsprechend Performance frißt.
Im JOIN wird zunächst die Verknüpfung jedes Datensatzes und dann in der WHERE-Klausel auch noch die Filterbedingung geprüft
Das hält sich in Grenzen, wenn keine Felder aus den "gejointen" Tabellen in der Abfrage eingebunden werden.
Dann kann eine solche Abfrage ebenfalls sehr schnell sein, insbesondere dann, wenn die Verknüpfungsfelder einen Index aufweisen (wie schon geschrieben).

Fazit zu Subselects: an der richtigen Stelle und im richtigen Kontext eingesetzt - ja, aber generell in Abfragen eher vermeiden! (was nicht immer geht)


Viele Grüße,
Tommi
 
Werbung:
Zurück
Oben