![]() |
Datenbank: Access • Version: 2003 • Zugriff über: FireDac
SQL Nachhilfe
Hallo liebe SQL-Experten,
ich bin hier am Optimieren meiner SQL Queries. Folgende Abfrage funktioniert wie es sein soll, jedoch ist diese mit ca. 5 sek. etwas zu langsam. Da kann man sicher noch was rausholen:
Delphi-Quellcode:
Es wäre sehr nett, wenn mir wieder jemand helfen könnte.
SELECT s.ArtNr, s.ArtName1,s.ArtGruppe, s.ArtZusInfo4
FROM sArtikel s WHERE NOT EXISTS (SELECT * FROM ArtLief l WHERE s.ArtNr = l.ArtLiefArtNr and l.ArtLiefLiefNr = s.ArtZusInfo4 ) and s.ArtInaktiv = false and s.ArtZusInfo4 like 'K*' order by s.ArtNr; LG Harry |
AW: SQL Nachhilfe
Auf den ersten Blick würde ich vermuten, dass ein left join mit Abfrage, ob das gejointe Feld null ist, schneller ist.
Denn so muss ja für jeden Datensatz eine Abfrage über die ganze Tabelle laufen. Wenn dann die dabei abgefragten Felder nicht in einem Index sind, ist das noch einmal langsamer. Indizes sind aber auch generell ein Thema, um Abfragen zu beschleunigen. Hast du dir zu der Abfrage einmal den Ausführungsplan angeschaut? Der zeigt, wo wieviel Zeit verbraucht wird. |
AW: SQL Nachhilfe
Jupp, ein JOIN, anstatt des SubSELECTs.
Und dann auch schauen, ob auf den verlinkten Feldern ein Index liegt.
SQL-Code:
INDIZE auf:
SELECT s.ArtNr, s.ArtName1,s.ArtGruppe, s.ArtZusInfo4
FROM sArtikel AS s LEFT JOIN ArtLief AS l ON l.ArtLiefArtNr = s.ArtNr AND l.ArtLiefLiefNr = s.ArtZusInfo4 WHERE s.ArtInaktiv = false AND s.ArtZusInfo4 LIKE 'K*' AND l.irgendwas IS NULL -- hier irgendein NOT NULL Keyfield, vielleicht l.ArtLiefArtNr l) ArtLiefLiefNr, ArtLiefArtNr (hier dachte ich erst es wäre zwei mal das gleiche, aber einfach das = umgedreht und schon fällt es sofort auf) s) ArtInaktiv, ArtZusInfo4, ArtNr Und bezüglich des LIKE, k.A. wie es bei Access aussieht, aber z.B. in MySQL gibt es verschiedene Indize, wobei Manche für sowas wie LIKE nicht geeignet sind. Zum Glück ist auch der * am Ende, denn die meisten Indize sind für Suchen, wo * am Anfang oder mittendrin wäre, ebenfalls ungeeignet. Gut, das System könnte natürlich auch intelligenter sein und erkennen, dass das Subselect als JOIN besser geeignet ist und es das entsprechend selbstständig umstellt. * anstatt für jede Zeile eine einzelne Abfrage auszufühen * die Tabelle nur einmal lagen und jeweils nur schnell darin zu suchen Wenn die Optimierung im DSMS nichts kann, sie also nicht erkennen würde, dass dein Subsselekt langsam ist und es scheller wäre die folgenden AND vorzuziehen, dann würde das Subselect für JEDEN Datensatz ausgewertet, anstatt nur für einen Teil, nach der Filterung durch die beiden
Delphi-Quellcode:
, also
=
SQL-Code:
Drum kommt bei mir gedanklich auch das IS NULL "gedanklich" als letztes im WHERE vor :wink:,
WHERE s.ArtInaktiv = false
AND s.ArtZusInfo4 like 'K*' AMD NOT EXISTS (SELECT * FROM ArtLief l WHERE s.ArtNr = l.ArtLiefArtNr and l.ArtLiefLiefNr = s.ArtZusInfo4 ) wobei ein NULL-Prüfung in einem INDEX wohl auch wiederum optimaler/schneller sein dürfte, als ein
Delphi-Quellcode:
oder LIKE.
=
PS: In vielen DBMS gibt SQL-Befehle oder Zusatztools, um das Statement analysieren zu lassen. Was wird wo gemacht (z.B. FullTableScann anstatt IndexScan) und vielleicht auch vie viel Zeit welcher Teil braucht. sowas hab ich jetzt noch nicht gesehn, ![]() ![]() aber ![]() |
AW: SQL Nachhilfe
Vielen lieben Dank für Euere schnell Hilfe.:bouncing4:
Himitsus erster SQL Code hat perfekt gepasst! Ausführungszeit jetzt 0.03 sek. Brutal geil! Jetzt läufts super schnell mit diesem Code:
Delphi-Quellcode:
SELECT s.ArtNr, s.ArtName1,s.ArtGruppe, s.ArtZusInfo4
FROM sArtikel AS s LEFT JOIN ArtLief AS l ON l.ArtLiefArtNr = s.ArtNr AND l.ArtLiefLiefNr = s.ArtZusInfo4 WHERE s.ArtInaktiv = false AND s.ArtZusInfo4 LIKE 'K*' AND l.ArtLiefArtNr IS NULL order by s.ArtNr; |
AW: SQL Nachhilfe
Da ist mir doch noch einer auffällig langsam:
Delphi-Quellcode:
Diesesmal scheint mir (als Dilli) das etwas komplizierter wegen den 2 inner joints.
SELECT
A.ABFDocErfNr,A.ABFDocDatum,A.ABFDocKundenNr, A.ABFDocKundekurzbez, P.ABFPosArtNr,P.ABFPosName1,P.ABFPosEPreis, M.PersKtoPreisGruppe FROM (ABFDok as A INNER JOIN ABFPos as P ON A.ABFDocId = P.ABFPosDocID ) inner join sPersKto as M on M.PersKtoNummer = A.ABFDocKundenNr where P.ABFPosArtNr = '11024060' and Year([A.ABFDocDatum]) > Year(Date())-5 and A.ABFDocType = 1 ORDER BY A.ABFDocId desc; Könnte nochmals Hilfe gebrauchen um die Query flinker zu machen. LG Harry |
AW: SQL Nachhilfe
Zitat:
Was mir sofort auffällt: Durch
Code:
kann für "ABFDocDatum" schonmal kein Index mehr gezogen werden.
Year([A.ABFDocDatum]) > Year(Date())-5
Dann teste bitte zusätzlich noch, ob es ohne
Code:
spürbar schneller ist.
order by
Leider kann ich heute nicht mehr weiterhelfen, da ich gleich auf einer Demo bin.:wink: |
AW: SQL Nachhilfe
Ich würd jetzt einfach mal das probieren:
Code:
-- Index für ABFPos
CREATE INDEX idx_ABFPos_ABFPosDocID ON ABFPos (ABFPosDocID); -- Index für sPersKto CREATE INDEX idx_sPersKto_PersKtoNummer ON sPersKto (PersKtoNummer); -- Index für ABFDok CREATE INDEX idx_ABFDok_ABFPosArtNr_Datum_Type_KundenNr ON ABFDok (ABFPosArtNr, ABFDocDatum, ABFDocType, ABFDocKundenNr); |
AW: SQL Nachhilfe
Hallo,
mit den indexen wurde es keider auch nicht schneller. LG Harry |
AW: SQL Nachhilfe
Year([A.ABFDocDatum]) > Year(Date())-5
Könnte man vllt. umformulieren zu [A.ABFDocDatum] >= DateSerial(Year(Date())-4, 1, 1 ) |
AW: SQL Nachhilfe
Jupp, da hier das Feld durch eine Funktion geht, kann nicht der Index genutzt werden, welcher auf diesem Feld liegt.
Also direkt das Feld direkt verwenden, damit der Index genutzt werden kann, wäre somit eine Lösung (siehe Jumpy) Oder einen Index auf das Jahr erstellen, also auf
Delphi-Quellcode:
.
Year([A.ABFDocDatum])
Weiß aber nicht, ob es sowas auch im Access gibt. |
AW: SQL Nachhilfe
Hallo,
das Year-Dingens könnte man so umschreiben DateAdd("yyyy", -5, Date()) Aber warum übergibst Du das nicht als konstanten Parameter? Warum wird das jedesmal berechnet? Und noch mal auf die Indizes zu kommen. INNER JOIN ABFPos as P ON A.ABFDocId = P.ABFPosDocID ) inner join sPersKto as M on M.PersKtoNummer = A.ABFDocKundenNr where P.ABFPosArtNr = '11024060' and Year([A.ABFDocDatum]) > Year(Date())-5 and A.ABFDocType = 1 Die fett markierten Felder müssten Indizes enthalten. Ich würde danach auch mal die MDB komprimieren. |
AW: SQL Nachhilfe
Das
Delphi-Quellcode:
wird nur einmal berechnet. (außer die haben bei der Funktion und dem Queryplaner echt Scheiße gebaut)
DateAdd("yyyy", -5, Date())
Aber das Date vom Feld, wird natürlich für jeden Datensatz berechnet. Ja, die Berechnung/Funktionsausführung dauert nicht lange und braucht nahezu keine Zeit, aber da es keinen Index auf dessen Ergebnis gibt, kann eben auch Keiner genutzt werden. |
AW: SQL Nachhilfe
Hallo,
kein Index? CREATE INDEX idx_ABFDok_ABFPosArtNr_Datum_Type_KundenNr ON ABFDok (ABFPosArtNr, ABFDocDatum, ABFDocType, ABFDocKundenNr); Eventuell sollte noch ein Index direkt auf ABFDocDatum gesetzt werden, also nicht so ein "komischer" Compound-Index. |
AW: SQL Nachhilfe
idx_ABFDok_ABFPosArtNr_Datum_Type_KundenNr ist ein Combi-Index, der genutzt wird, wenn im WHERE direkt auf alle Felder (ABFPosArtNr, ABFDocDatum, ABFDocType, ABFDocKundenNr) gerpft wird.
Hast du einen Index nur auf "ABFDocDatum", also
Delphi-Quellcode:
(oder z.B.
CREATE INDEX idx_ABFDocDatum ON ABFDok (ABFDocDatum);
Delphi-Quellcode:
im CREATE TABLE), dann
ABFDocDatum UNIQUE
* wird bei
Delphi-Quellcode:
dieser Index benutzt
WHERE ABFDocDatum ...
* aber nicht bei
Delphi-Quellcode:
WHERE Year(ABFDocDatum) ...
Für Letzteres bräuchte man z.B. sowas
Delphi-Quellcode:
(falls Access sowas kann)
CREATE INDEX idx_YearABFDocDatum ON ABFDok (Year(ABFDocDatum));
Und wie gesagt, kommt es teilweise auch auch auf die Art des Indize drauf an. MySQL oder z.B. Postgres kennen unterschiedliche Typen (z.B. B-tree, hash, GiST, SP-GiST, GIN, and BRIN) B-Tree ist heute oft gebräuchlich und auch für ein
Delphi-Quellcode:
geeignet, während HASH für ein LIKE absolut unnütz ist, aber für ein
LIKE 'irgendwas*'
Delphi-Quellcode:
mit langen Strings super wäre.
=
Und für
Delphi-Quellcode:
wäre es besser, wenn der B-Tree rückwärts von hinten aufgebaut ist.
LIKE '*sonstwas'
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:36 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz