[gelöst] MSSQL merkwürdig

Für Themen zu Datenbanken und Zugriff auf diese. Auch für Datenbankkomponenten.
Antworten
icho2099
Beiträge: 47
Registriert: Fr 21. Feb 2020, 19:17
OS, Lazarus, FPC: Win10/64
CPU-Target: 64 Bit
Wohnort: Osterholz-Scharmbeck

[gelöst] MSSQL merkwürdig

Beitrag von icho2099 »

Hallo,
ich verwende ZEOS Komponenten zum Zugriff auf eine MSSQL DB.
Folgende Merkwürdigkeit, die ich mir nicht erklären kann, hier nur ein Auszug aus dem SQL, welches Probleme bereitet:
JDVON, JDBIS sind Juliandates (Integer), MCU ist ein Stringfeld fester Länge(12)

Code: Alles auswählen

 DECLARE @JDVON AS INTEGER = 125001
 DECLARE @JDBIS As INTEGER = 125031
 DECLARE @MCU As NVARCHAR(12) = '    40912000'
 ......
 WHERE (1=1) 
 AND (WADCTO = 'WM') 
 AND (CD.CDITM = 76000011) 
 AND (   (MS.FWPNST >= @JDVON) AND (MS.FWPNST <= @JDBIS)  
     OR ( (MSEXT.PLANSTATUS = 1) AND (MSEXT.PLANDATUM >= @JDVON) AND (MSEXT.PLANDATUM <= @JDBIS) ) )
 AND (WOMF.WASRST  < '60') 
 AND (WOMF.WAMCU = '    40912000' )
 --AND (WOMF.WAMCU = @MCU ) 
 ORDER BY  ORT , PLZ  
Verwende ich die Zeile "AND (WOMF.WAMCU = ' 40912000' )" dann ist die Ausführung in einer Sekunde erledigt, für die korrekte Ergebnismenge von 94 Zeilen.
Wenn ich aber statt der Konstanten diese Zeile aktiviere "AND (WOMF.WAMCU = @MCU )", wo der Vergleichswert aus einer Variablen geholt werden muss,
dann benötigt die Ausführung fett 45 Sekunden. Es wird die gleiche, korrekte Ergebnismenge geliefert.
Hat jemand dafür eine plausible Erklärung?
Ich bin für jeden Hinweis dankbar.
Ich denke mal nicht, dass das etwas mit ZEOS zu tun hat, wenn ich das im MSSMS ausführe, verhält es sich ebenso merkwürdig.
Zuletzt geändert von icho2099 am Do 6. Feb 2025, 19:24, insgesamt 1-mal geändert.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6766
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: MSSQL merkwürdig

Beitrag von af0815 »

Hast du dir im SSMS ( SQL Server Management Studio ) schon mal den Ausführungsplan von beiden Versionen angesehen und verglichen ?

Speedbutton für LiveStatistik, Live-Abfrage und Client-Statistik aktivieren und beides mal durchlaufen lassen. Oft klärt sich dann, wo die Zeitfresser sind.

Der geschätzte Ausführungsplan kann da manchmal abweichen, der Abfrageoptimierer von MS ist normalerweise sehr gut, manchmal gibt es Abweichungen in tatsächlichen Plan. Gerade die Zeichenbasierenden (String) Typen können für unerwartete Ergebnisse sorgen.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
Zvoni
Beiträge: 363
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: MSSQL merkwürdig

Beitrag von Zvoni »

Welchen Datentyp hat WOMF.WAMCU?

Könnte mir vorstellen, dass es eben nicht NVARCHAR(12) ist, und MSSQL sich nen Wolf konvertiert

Ausserdem find ich deine WHERE-Klausel seltsam....
Noch nie was vom BETWEEN-Operator gehört?

Code: Alles auswählen

WHERE (1=1) 
 AND (WADCTO = 'WM') 
 AND (CD.CDITM = 76000011) 
 AND 	(
	(MS.FWPNST BETWEEN @JDVON AND @JDBIS)  
     	OR	( 
		(MSEXT.PLANSTATUS = 1) 
	AND 
		(MSEXT.PLANDATUM BETWEEN @JDVON AND @JDBIS) 
		) 
	)
 AND (WOMF.WASRST  < '60') 
 AND (WOMF.WAMCU = '    40912000' )
 --AND (WOMF.WAMCU = @MCU ) 
 ORDER BY  ORT , PLZ
EDIT: Mal als Test

Code: Alles auswählen

blablablabla
AND (TRIM(WOMF.WAMCU) = TRIM('    40912000' ))
--bzw.
AND (TRIM(WOMF.WAMCU) = TRIM(@MCU )) 
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6766
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: MSSQL merkwürdig

Beitrag von af0815 »

Zvoni hat geschrieben: Do 6. Feb 2025, 08:30 EDIT: Mal als Test

Code: Alles auswählen

blablablabla
AND (TRIM(WOMF.WAMCU) = TRIM('    40912000' ))
--bzw.
AND (TRIM(WOMF.WAMCU) = TRIM(@MCU )) 
Es könnte sein (siehe Ausführungsplan, wenn du einen machen lasst) das er in der ersten Version das Trim einmalig vorkompilieren kann, während bei der zweiten Version er jedesmal den Trim duchführen muss, weil ja nicht klar ist, ob sich @MCU nicht geändert hat. Wenn man @MCU vorher trimmt, so kann man an dieser Stelle mal das Trim wegoptimieren. Wie gesagt, ich sehe mir da gerne den tatsächlichen Ausführungsplan an.

Normalerweise haben nvarchar keine führenden Leerzeichen, ausser man schleppt sich die ein. Damit könnte man sich die beiden Trims ersparen, wenn sowohl die Daten in der Tabelle als auch die Variable sauber vorliegen. Man darf nicht vergessen Stringoperationen sind immer relativ teuer.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

icho2099
Beiträge: 47
Registriert: Fr 21. Feb 2020, 19:17
OS, Lazarus, FPC: Win10/64
CPU-Target: 64 Bit
Wohnort: Osterholz-Scharmbeck

Re: MSSQL merkwürdig

Beitrag von icho2099 »

Danke für die Antworten.
Den Ausführungsplan werde ich mir heute anschauen, mal sehen ob ich da durchsteige.
Der Datentyp ist nvarchar(12), in der Tabelle.
Die Daten selber stammen ursprünglich aus einer Oracle DB und werden in eine MSSQL geschrieben, Änderungen sind da für mich nicht zu machen.
Between() kann man nehmen, löst aber ja auch nur in zwei Vergleiche auf, ist also wohl eher gut für die Lesbarkeit.
Trim() baue ich als erstes ein, das könnte in der Tat etwas bringen.

icho2099
Beiträge: 47
Registriert: Fr 21. Feb 2020, 19:17
OS, Lazarus, FPC: Win10/64
CPU-Target: 64 Bit
Wohnort: Osterholz-Scharmbeck

Re: MSSQL merkwürdig

Beitrag von icho2099 »

Ich denke ich hab das Problem gelöst, mindestens aber gemildert.
Trim() und Between haben erwartungsgemäß nichts gebracht.

Durch den Ausführungsplan durchzusteigen ist zumindest mal nicht trivial,
aber damit habe ich in zwei Joins Zeitfresser gefunden, die sich durch zusätzliche
Einschränkungen deutlich besänftigen ließen.

Ich hätte erwartet, dass es eine Optimierung gibt, die Ausschlüsse aus der Where Klausel bereits
in die Joins einbezieht. Das passiert aber mal mehr mal weniger, in meinem Fall eher weniger.
Man muss also schon auch selber denken, sonst können sehr unhandliche temporäre Tabellen entstehen,
die sehr viel Zeit fressen.

Wieder was gelernt, danke euch für die Ratschläge.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6766
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: MSSQL merkwürdig

Beitrag von af0815 »

icho2099 hat geschrieben: Do 6. Feb 2025, 19:24 Durch den Ausführungsplan durchzusteigen ist zumindest mal nicht trivial,
aber damit habe ich in zwei Joins Zeitfresser gefunden, die sich durch zusätzliche
Einschränkungen deutlich besänftigen ließen.
Das habe ich nie behauptet :-) Ich habe damit auf den entsprechenden Adminkursen von MS zu arbeiten gelernt (und noch viel mehr).

ABER die Grafiken sind relativ einfach gehalten und wenn man zwei Grafiken vergleichen kann, so kann man grundlegende Unterschiede erkennen. Auch sieht man, wieviele physische Zugriffe nötig sind. Und diese sind immer am teuersten. Das gemeine am optimierer ist, das er gut gemeinte Indizies oft gar nicht verwendet, sondern mit partiellen Tablescanns schneller ist. Man glaubt oft nicht, welche Kleinigkeiten eine extreme Laufzeitänderung verursachen können. Das große Problem beim optimieren ist es dann, nicht eine einige Funktion zu optimieren, sondern man muss das ganze immer in der Gesamtheit betrachten und auch was wie oft verwendet wird.

Die meisten machen um den Ausführungplan einen Bogen, weil sie zu solchen Tools normalerweise nicht so einfach kommen. Man kann MS viel vorwerfen, aber der MS Server mit seinen auch kostenlosen Versionen (halt mit gewissen Einschränkungen) und dafür kostenlosen Spitzentools zu Programmierung und Wartung findet man auf anderen Plattformen nur schwer. Klar bin ich das gezwungener Massen MS-Geschädigter, habe aber auch andere Plattformen in Verwendung.

So nebenbei, man kann mit dem Ablaufplan sich einmal ansehen ob ein SubSelect vor dem Join nicht etwas bringt. Ist zwar oft nicht einleuchtend, wenn ich aber die Datenmenge vor dem Join auf ein minimum reduzieren kann, so ergibt das oft überraschend einen viel billigeren Join. (billiger = performanter, weniger Resourcen)
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
Zvoni
Beiträge: 363
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: MSSQL merkwürdig

Beitrag von Zvoni »

Auch wenn offiziell "gelöst":
https://www.sisense.com/blog/sql-query- ... perations/
Ich hätte erwartet, dass es eine Optimierung gibt, die Ausschlüsse aus der Where Klausel bereits
in die Joins einbezieht.
Siehe Link
SQL’s from clause selects and joins your tables and is the first executed part of a query. This means that in queries with joins, the join is the first thing to happen.
zu Deutsch: FROM bzw. JOINS werden als allererstes ausgeführt.

Ich erinner mich auch daran, dass ich vor ein paar Jahren eben auch diesen Hinweis gefunden habe, und daraus folgert:
Erst Filtern, DANN Joinen

Wenn du irgendwo in einem JOIN ne Tabelle mit mehreren Millionen Zeilen hast (Was mir passiert ist), welche du ungefiltert Join'st, dann kannst nach Abfeuern des Querys erst mal Kaffee holen gehen und eine rauchen.

Nächster Optimierungspunkt: Indexe auf die Felder, über welche du Join'st

Falls dein Query noch immer eine "unbefriedigende" Performance haben sollte, dann poste doch mal das ganz Ding (sofern du darfst).

Vielleicht finden wir ja was.

EDIT: Und hier: https://dba.stackexchange.com/questions ... es-minutes
Klingt nach deinem Problem.
Hab übrigens deutlich mehrere Ergebnisse gesehen, als ich Google danach gefragt habe.
Scheint die Verwendung der Variablen zu sein.

Frage: Ist das Query Bestandteil eines Frontends, oder einfach nur ne Abfrage (Aus SMSS)?
Weil wenn es einfach nur ne Abfrage ist (Kein Bestandteil eines Frontends), gibts nen Trick die Verwendung von Variablen zu vermeiden.
Zugegeben: Diesen Trick kann man auch in einem Frontend nutzen, würde jedoch aber die Verwendung von Parametern verhindern (String-Verkettung), da CTE's zum Einsatz kommen.
Alternative wäre mit Subselects zu arbeiten (welche man parametrieren kann), aber Sub-Selects kann ich leiden wie Bauchweh
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Antworten