AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Datenbanken Komplexe SQL-Abfrage optimieren
Thema durchsuchen
Ansicht
Themen-Optionen

Komplexe SQL-Abfrage optimieren

Ein Thema von omp · begonnen am 18. Feb 2025 · letzter Beitrag vom 19. Feb 2025
Antwort Antwort
omp

Registriert seit: 7. Apr 2012
63 Beiträge
 
#1

Komplexe SQL-Abfrage optimieren

  Alt 18. Feb 2025, 10:50
Datenbank: MS SQL • Version: 2022 • Zugriff über: FireDAC
Hallo. Wir haben ein Dokumentenarchiv mit einem einfachen Volltextindex. Die SQL-Abfrage sieht beispielsweise wie folgt aus:
Code:
SELECT * FROM document
WHERE docid IN (SELECT id.docid FROM ftiwid id INNER JOIN ftiword w ON id.wordid = w.wordid WHERE (w.word LIKE {s gesuchteswort%}) )
Kommt ein neues Dokument in die Datenbank, muss dieses über die docid der Abfrage hinzugefügt werden:
Code:
SELECT * FROM document
WHERE docid=200001 
OR docid IN (SELECT id.docid FROM ftiwid id INNER JOIN ftiword w ON id.wordid = w.wordid WHERE (w.word LIKE {s gesuchteswort%}) )
Tests mit Datenbank bis ca. 80.000 Datensätzen sind problemlos und schnell. In einem Archiv mit 200.000 Zeilen tritt jetzt aber ein echtes Problem auf:
Die erste Abfrage ist ok und in 2 Sekunden fertig.
Die zweite Abfrage mit "WHERE docid=200001 OR" benötigt aber über eine Stunde Zeit!

Hat jemand eine Idee, was dahintersteckt?
Besten Dank, Harald
Harald
  Mit Zitat antworten Zitat
omnibrain

Registriert seit: 11. Nov 2022
79 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: Komplexe SQL-Abfrage optimieren

  Alt 18. Feb 2025, 11:19
Hast du dir schon den Query-Execution-Plan angeschaut?
https://learn.microsoft.com/en-us/sq...l-server-ver16
  Mit Zitat antworten Zitat
Benutzerbild von Jasocul
Jasocul

Registriert seit: 22. Sep 2004
Ort: Delmenhorst
1.366 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: Komplexe SQL-Abfrage optimieren

  Alt 18. Feb 2025, 11:19
Zunächst wird die größere Datenmenge eine Rolle spielen. Aber das ist wohl offensichtlich
eine Prüfung auf "in" wird von der DB als "or" für alle gefundenen Werte umgewandelt. Bei vielen Elementen ist das keine besonders optimale Lösung. Falls MS-SQL das intern besser löst, solltest du das zusätzliche Dokument in das "in" integrieren. Also nach dem Select als weitere ID hinzufügen.

Bei potentiell vielen Treffern würde ich das umbauen und aus der IN-Prüfung eine EXISTS-PRüfung machen. Also etwa so:
Code:
SELECT * FROM document as d
where exists (SELECT id.docid FROM ftiwid id INNER JOIN ftiword w ON id.wordid = w.wordid WHERE (w.word LIKE {s gesuchteswort%}) and id.docid = d.docid)
union all -- um das or komplett rauszuschmeißen
SELECT * FROM document
WHERE docid=200001
Du kannst das ja mal testen
Peter
  Mit Zitat antworten Zitat
Delphi.Narium

Registriert seit: 27. Nov 2017
2.544 Beiträge
 
Delphi 7 Professional
 
#4

AW: Komplexe SQL-Abfrage optimieren

  Alt 18. Feb 2025, 11:21
Was wird hier eigentlich gemacht?

Zuerst brauchen wir ein bestimmtes Wort (bzw. eine Liste der IDs zu Wörtern, die dem Suchbegriff ähneln):

select wordid from ftiword where (w.word like {s gesuchteswort%})
Zu diesem Ergebnis möchten wir alle DocID:

SQL-Code:
select id.docid from ftiwid id where exists (
  select 1 from ftiword w where (w.word like {s gesuchteswort%}) and id.wordid = w.wordid
)
Zu diesem Ergebnis benötigen wir nun alle Dokumente:

SQL-Code:
select * from document a where exists
(
  select 1 from ftiwid id where exists
  (
    select 1 from ftiword w where (w.word like {s gesuchteswort%}) and id.wordid = w.wordid
  ) and id.docid = a.docid
)
Keine Ahnung, ob MSSQL mit so'ner Syntax zurecht kommt.

Warum wird im zweiten SQL nach einer konkreten ID gesucht und zusätzlich noch in einer Liste von IDs?

Hier würd' ich's dann mit 'nem Union versuchen:

SQL-Code:
select * from document where docid = 200001
union
select * from document a where exists
(
  select 1 from ftiwid id where exists
  (
    select 1 from ftiword w where (w.word like {s gesuchteswort%}) and id.wordid = w.wordid
  ) and id.docid = a.docid
)
Wenn das nicht geht:
SQL-Code:
select * from document where docid = 200001
union
SELECT * FROM document
WHERE docid IN (SELECT id.docid FROM ftiwid id INNER JOIN ftiword w ON id.wordid = w.wordid WHERE (w.word LIKE {s gesuchteswort%}) )
  Mit Zitat antworten Zitat
Benutzerbild von TigerLilly
TigerLilly

Registriert seit: 24. Mai 2017
Ort: Wien, Österreich
1.237 Beiträge
 
Delphi 12 Athens
 
#5

AW: Komplexe SQL-Abfrage optimieren

  Alt 19. Feb 2025, 09:20
Nicht raten. Messen.
Schau dir den Execution Plan an, dann weißt du, wo die Zeit liegen bleibt.
Gerne übersehen: Der Aufwand für das Locking bei Abfragen. Ergänze mal ein WITH (NOLOCK) nach den Tabellennamen (und sei dir der Konsequenzen bewusst).
Nutze den Optimzer, der gibt dir zielgerichtet Tipps zu deiner Query.
Ein Index (wenn er denn genutzt wird) kann böse defragmentiert sein - REBUILD.
Die Statistiken, die steuern, ob ein Index genutzt wird, können überholt sein - aktualisieren.

Erst dann kannst du versuchen, die Query umzubauen: CTEs, temporäre Tabellen etc.
ChatGPT ist auch ein guter Tipp, nicht alles funktioniert, aber du bekommst neue Ideen.
Certified Delphi Developer (2025)
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.487 Beiträge
 
Delphi 12 Athens
 
#6

AW: Komplexe SQL-Abfrage optimieren

  Alt 19. Feb 2025, 13:36
Die äußere Abfrage liefert nur die Dokumente zurück, deren ID bereits ermittelt wurde.
Ob mit "or", "in" oder "exists" dürfte kaum einen großen Unterschied darstellen.

Die eigentliche Bremse könnte die Verknüpfung aller Worte mit allen Dokumenten darstellen.
Neben dem verwendeten Index wirkt sich auch der Speicherverbrauch der Abfrage schnell auf die Geschwindigkeit aus.
Code:
SELECT    id.docid
FROM      ftiwid id
INNER JOIN ftiword w ON id.wordid = w.wordid
WHERE     (w.word LIKE {s gesuchteswort%})
Ich würde es mit einem left join versuchen:
Code:
SELECT    distinct id.docid
FROM      ftiword w
left join ftiwid id ON id.wordid = w.wordid
WHERE     (w.word LIKE {s gesuchteswort%})
Mehrfache Rückgabe des selben Dokuments ist hier nicht erwünscht (distinct).
Natürlich könnte man die Anzahl der Dokumente hier sinnvoll z.B. auf die ersten 200 begrenzen.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:03 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 by Thomas Breitkreuz