Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   SQL Script optimieren damit es schneller geht (https://www.delphipraxis.net/191849-sql-script-optimieren-damit-es-schneller-geht.html)

Dumpfbacke 25. Feb 2017 09:18

AW: SQL Script optimieren damit es schneller geht
 
Zitat:

Zitat von hoika (Beitrag 1362620)
Hallo,
was passiert, wenn Du die letzten beiden where's weglässt?

<>"N" hattest du ja selber schon ausgeschlossen.
Das Storno kannst Du selber im Code prüfen.

Das geht auch nicht schneller. Ich habe esnur beutzt, um den Anzahl der Datensätze zu veringern.

Dumpfbacke 25. Feb 2017 09:32

AW: SQL Script optimieren damit es schneller geht
 
Ich zeige Euch mal wie die Daten in den Tabellen aussehen können. Eventuell wird es dann deutlicher wo mein Fehler leigt.

Also als erstes einmal bei dem Status N kann es keine Zeile in Tabelle2 geben. Es kann auch keine Zeile in Tabelle 2 geben bei dem der Wert des Feldes Status NULL ist.

Es liegt ein Index auf den Felder CoNummer und Status der Teabelle1 sowie CoNummer und Status der Tabelle2


Delphi-Quellcode:
Tabelle1
Masternummer CoNummer Status
1            2514     N
2            2515     Start
3            2516     Warten
4            2517     Produktion
5            2518     Ausgabe
6            2519     Komplett



Tabelle2
CoNummer Status
2515     Start
2516     Start
2517     Start
2517     Warten
2518     Start
2518     Warten
2518     Produktion
2518     Ausgabe
Als Ergebnis möchte ich nun haben 1,3,4 und 6. Also alle Datensätze aus Tabelle1 wo kein Datensatz in Tabelle 2 vorhanden ist.

dataspider 25. Feb 2017 10:19

AW: SQL Script optimieren damit es schneller geht
 
IMHO ist hier nicht viel zu machen.
Für die Verknüpfung mit Tabelle 2 hilft dir kein Index.
Fakt ist:
Die Indexe greifen nur auf Status und Storno, alle anderen Datensätze von Tabelle 1 werden beim Select "angefasst".
Du kannst nur noch sicherstellen, das zur Prüfung auch nur ein Datensatz in Tabelle 2 "angefasst" wird,
indem du statt einem Join exists verwendest.

Wenn es schnell sein soll, benötigst du IMHO ein zusätzliches indexiertes Feld in Tabelle 1,
welches über "after insert update delete" Trigger der Tabelle 2 aktuell gehalten wird.

Frank

Valle 25. Feb 2017 10:44

AW: SQL Script optimieren damit es schneller geht
 
Ich bin neugierig, aber leider erfahrungslos mit Firebird. Im Prinzip würde das hier das Ergebnis liefern, oder?

Code:
SELECT * FROM Tabelle1
WHERE NOT EXISTS (
    SELECT CoNummer FROM Tabelle2 WHERE Tabelle2.CoNummer = Tabelle1.CoNummer
)

nahpets 25. Feb 2017 11:44

AW: SQL Script optimieren damit es schneller geht
 
Zitat:

Zitat von Valle (Beitrag 1362624)
Ich bin neugierig, aber leider erfahrungslos mit Firebird. Im Prinzip würde das hier das Ergebnis liefern, oder?

Code:
SELECT * FROM Tabelle1
WHERE NOT EXISTS (
    SELECT CoNummer FROM Tabelle2 WHERE Tabelle2.CoNummer = Tabelle1.CoNummer
)

Das war beim Lesen der Anforderungen jetzt auch gerade mein erster Gedanke.

Will ich nur wissen, ob es etwas gibt oder nicht, dann frage ich mit Exists ab:
Beispiele:
SQL-Code:
/* gibt es da was in Tabelle2 zu Tabelle1? */
select benötigtespalte(n) from tabelle1
where exists (select 1 from tabelle2 where tabelle1.schlüssel = tabelle2.schlüssel)

/* gibt es nichts in Tabelle 2 zu Tabelle 1? */
select benötigtespalte(n) from tabelle1
where not exists (select 1 from tabelle2 where tabelle1.schlüssel = tabelle2.schlüssel)
Das war nach meiner bisherigen Erfahrung immer die schnellste Variante für eine Existenz- bzw. Nichtexistenzprüfung.

Brauche ich sowas nur für kleine Teilmengen der betroffenen Tabellen dann wird daraus sinngemäß:
SQL-Code:
select * from (
  select benötigtespalte(n) from tabelle1
  where EinschränkendeBedingungen zu Tabelle1
) a
where exists /* Wenns was geben soll */
(
  select Schlüsselspalten from
  (
    select Schlüsselspalten from tabelle2
    where EinschränkendeBedingungen zu Tabelle2
  ) b
)
where a.schlüssel = b.schlüssel
Ja, ich weiß, das wird zuweilen sehr schwer lesbar, aber wenn's hilft, dann ist dem so. Im Zweifelsfalle erstellt man sich für die "innern Selects" halt Views, dann ist der Zugriff wieder wie im ersten Beispiel leicht lesbar, ohne das Laufzeitveränderungen auftreten.

Zitat:

Zitat von hoika2
Genau das macht der Query-Optimizer ja schon selbst (eigentlich ...)

Syntaktisch mag das zutreffen.

Meine Erfahrung hat mich jedoch gelehrt, dass der Optimizer hier bei starken Einschränkungen der Daten auf Teilmengen, die dann zu verknüpfen sind, häufig "daneben liegt".
Er kann bei der Optimierung (vermutlich) die aus den Einschränkungen resultierenden Teilmengen nicht optimal einschätzen, um den laufzeittechnisch und dateninduziert optimalen Plan zu erstellen.

Würde dashier (sinngemäß) den Anforderungen entsprechen?
SQL-Code:
select a.Masternummer from
(
  select Masternummer from tabelle1
  where status <> 'N' and status is not null
) a
where not exists (
  select 1 from tabelle2 b
  where a.CoNummer = b.CoNummer
)
Und ist es auch akzeptabel schnell?

p80286 25. Feb 2017 11:54

AW: SQL Script optimieren damit es schneller geht
 
Zitat:

Zitat von nahpets (Beitrag 1362625)
Das war nach meiner bisherigen Erfahrung immer die schnellste Variante für eine Existenz- bzw. Nichtexistenzprüfung.

Ist leider nicht allgemeingültig!
SQL-Code:
select *
from t1 left join t2 on (t1.id=t2id)
where t2.id is null
Ist meist etwas schneller, kommt aber wohl vor allem auf die konkreten Daten (und die DB) an.
Man sollte immer beide Wege probieren.

Gruß
K-H

nahpets 25. Feb 2017 12:08

AW: SQL Script optimieren damit es schneller geht
 
Zitat:

Zitat von p80286 (Beitrag 1362629)
Ist leider nicht allgemeingültig!

Das Schlimme daran ist ja, dass es ja nicht nur bei unterschiedlichen Datenbankherstellern unterschiedlich ist, sondern je nach Datenbank eines Herstellers datenabhängig nicht zwingend den "richtigen" Weg gibt, sondern auch noch abhängig von der darunterliegenden Hardware (z. B. identische Maschinen mit lediglich unterschiedlicher Speicherbestückung) durchaus unterschiedliche Verhaltensweisen geben kann.

Im Zweifel gilt bei mir immer:

Ausprobieren, bis die (hoffentlich) beste Lösung gefunden wurde.

"Die beste Lösung" gibt es nicht.

himitsu 25. Feb 2017 12:36

AW: SQL Script optimieren damit es schneller geht
 
In Firebird kann man sich doch bestimmt auch den EXPLAIN PLAN/ANALYSE ausgeben lassen und sieht ob und welcher Index verwendet wird.

Mal probiert den JOIN umzudrehen?
Im Beispiel hat Tabelle2 mehr Einträge.
Delphi-Quellcode:
FROM Tabelle1 JOIN Tabelle2
> für jeden Eintrag in Tabelle 1 alle vielen Einträge in Tabelle 2 durchsuchen (NULL steht nicht im Index, also FullScan und Index ignoriert)
Delphi-Quellcode:
FROM Tabelle2 JOIN Tabelle1
> für jeden Eintrag in Tabelle 2 die wenigen Einträge in Tabelle 2 durchsuchen

Oder halt die Variante ohne JOIN.
SQL-Code:
SELECT *
FROM Tabelle1
WHERE NOT exists(
  SELECT true
  FROM Tabelle2
  WHERE Tabelle1.CoNummer = Tabelle2.CoNummer
    AND Tabelle1.Status = Tabelle2.Status
  LIMIT 1
)
Das SubSelect kann nun einen Index gut ausnutzen, wenn der über CoNummer+Status geht.
Keine Ahnung, ob EXISTS schon so schlau ist und die Felder (hier nur ein True) ignoriert, weil sie niemals genutzt werden,
und bereits ein LIMIT verwendet, da ja schon ab dem ersten Fund das Ergebnis feststeht.

Dumpfbacke 25. Feb 2017 12:53

AW: SQL Script optimieren damit es schneller geht
 
Zitat:

Zitat von himitsu (Beitrag 1362634)
In Firebird kann man sich doch bestimmt auch den EXPLAIN PLAN/ANALYSE ausgeben lassen und sieht ob und welcher Index verwendet wird.



Oder halt die Variante ohne JOIN.
SQL-Code:
SELECT *
FROM Tabelle1
WHERE NOT exists(
  SELECT true
  FROM Tabelle2
  WHERE Tabelle1.CoNummer = Tabelle2.CoNummer
    AND Tabelle1.Status = Tabelle2.Status
  LIMIT 1
)

Firebird kennt kein true und auch kein LIMIT 1

nahpets 25. Feb 2017 13:09

AW: SQL Script optimieren damit es schneller geht
 
Würde das in etwa so übersetzen:

Statt
SQL-Code:
SELECT *
FROM Tabelle1
WHERE NOT exists(
  SELECT true
  FROM Tabelle2
  WHERE Tabelle1.CoNummer = Tabelle2.CoNummer
    AND Tabelle1.Status = Tabelle2.Status
  LIMIT 1
)
könnte dashier gehen:
SQL-Code:
SELECT *
FROM Tabelle1
WHERE NOT exists(
  SELECT first 1 1
  FROM Tabelle2
  WHERE Tabelle1.CoNummer = Tabelle2.CoNummer
    AND Tabelle1.Status = Tabelle2.Status
)
Syntaktisch geht das so unter FireBird (grade mal ausprobiert), ob's auch sinnvolle Ergebnisse liefert, kann ich nicht sagen, first 1 1 sieht jedenfalls seltsam aus ;-)


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:01 Uhr.
Seite 2 von 3     12 3      

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 by Thomas Breitkreuz