Announcement

Collapse
No announcement yet.

Optimierter Select funktioniert nicht in Delphi

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Optimierter Select funktioniert nicht in Delphi

    Hallo

    in meiner Anwendung mache ich zum Suchen von Artikeln das, was wohl 1000000 Programme so oder ähnlich machen:

    select artikelnummer from material

    where bezeichnung like :bezeichnung

    Wobei im Parameter :Bezeichnung ein String mit Jokerzeichen (% ...) stecken kann, damit der Benutzer generisch suchen darf. Über die Spalte Bezeichnung ist ein Index gelegt. Die Interbase-Tabelle hat ca 30000 Zeilen. Testet man dieses Statement in ISQL, so erhält man sofort ein Ergebnis. In Delphi in einer TQuery hingegen läuft das ganze ca 10 Sekunden, daher nehme ich an, es wird ein Full-Table-Scan gemacht. Was passiert mit meinem Statement? Leider habe ich nur D3Pro und keinen SQL-Monitor.

    Einen Query-Plan akzeptiert TQuery ebenfalls nicht (wohl aber ISQL).

    Vielen Dank für Hinweise!!!!

    Kai!!!!

  • #2
    Hallo,

    in der letzten Ausgabe von DER ENTWICKLER habe ich eine Alternative zum SQL-Monitor vorgestellt, mit deren Hilfe die Besitzer der Professional-Version von Delphi die gleichen Untersuchungs-Ergebnisse erhalten. Das Beispielprogramm installiert dazu einen <b>BDE-Callback</b> und kann über http://www.entwickler.com/entwickler/codes/de699/delphi/SQLAnweisungen.zip heruntergeladen werden.

    Die Frage ist, wofür die 10 Sekunden Zeit benötigt werden. Für das Zusammenstellen des Ergebnisses auf dem InterBase, oder für das Übertragen aller (!) Datensätze zum Client.

    Bei einer LIKE-Abfrage über einen Parameterwert (dessen Inhalt beim Prepare nicht feststeht) wird der InterBase sicherlich keinen Index verwenden (als Parameter könnte nur % übergeben werden, so dass ein Index nicht hilfreich ist). Beim Aufruf aus ISQL heraus wird bestimmt kein Parameter, sondern ein Wert angegeben (so das der Optimizer das % an führender Stelle sofort ausschliessen kann).

    Ich daher folgende Alternativen ausprobieren: <br>
    1. Der TQuery-Instanz einen "fertigen" SQL-Text (ohne Parameter) zuweisen und danach öffnen. <br>
    2. Oder besser: Die SELECT-Abfrage in eine <b>Stored Procedure</b> legen, die als SELECT-Prozedur die Ergebnismenge zurückliefert. Innerhalb dieser Stored Procedure sollte alles das möglich sein, was auch via ISQL abgesetzt werden kann.
    &#10

    Comment


    • #3
      Hallo Andreas,

      mit anderen Worten:

      Interbase macht das Prepare schon, bevor es meine Parameterinhalte kennt?! Du hast richtig getippt. In ISQL arbeite ich natürlich mit festen Parameter-Werten.

      Kann ich das Prepare nicht nochmals NACH der Parameterzuweisung erzwingen?

      Übrigens hole ich ja nur ganz wenige Datensätze (1...10) in der Ergebnismenge zurück. Eine ähnliche Abfrage über TQuery mit vollqualifiziertem Key (KEIN Like, sondern =) läuft ja sehr schnell (< 1s). Das Übertragen sollte also nicht das Zeitproblem verursachen

      Deine Alternative 1 gefällt mir insofern nicht nicht, da ich so alle evtl eingegebenen Sonderzeichen in den Parametern (', ") abfangen muß, die sonst CHaos in meiner Query anrichten.

      Alternative 2: Kann ich denn aus einer Stored Procedure mit einem SELECT lesen? Und was wird mit den Parametern für die Suchbegriffe, die ich dorthin übergebe? Führen die nicht zum gleichen Problem wie die direkte Abfrage?

      Auf jeden Fall werde ich mal Dein Tool ausprobieren.

      Danke + Gruß Ka

      Comment


      • #4
        Hallo Kai,

        beim Prepare wird exakt die Zeichenkette (SELECT-Anweisung) an den InterBase übergeben, der auch in TQuery.SQL eingetragen ist. Nur der Parameter-Platzhalter wird durch das im SQL-Standard vorgesehene Fragezeichen ersetzt. Somit "kennt" der InterBase nur die Anweisung, aber nicht die Parameter. Solange sich die SQL-Anweisung nicht ändert, können verschiedene SELECTs mit verschiedenen Parametern aufgerufen werden, ohne das jedesmal ein neues Prepare (mit Optimizer-Lauf des InterBase) notwendig wird.

        Zur Frage 2: Der InterBase kennt SELECT-Prozeduren, die ganz normal über eine TQuery abgefragt werden können (SELECT * FROM prozedurename). Anstelle eines Tabellen- oder View-Namen wird nur der Name der Stored Procedure übergeben. Allerdings muss diese Stored Procedure den Regeln für SELECT-Prozeduren entsprechen (siehe InterBase-Handbücher) und <b>SUSPEND</b> für jeden Datensatz in der Treffermenge aufrufen. Wenn mit ISQL der Optimizer überstimmt werden kann (Query-Plan), kann diese Anweisung auch direkt in der Stored Procedure verwendet werden (d.h. da alles auf dem InterBase Server abläuft, kann TQuery/VCL keine "Vetos" gegen bestimmte Aufrufe einlegen).

        P.S: Der InterBase unterstützt auch die Abfrage mit <b>STARTING WITH</b> - und bei dieser Joker-Abfrage wird immer ein INDEX verwendet. Eine Gegenüberstellung der Alternativen findet sich in meinem Buch <i>Client/Server Datenbankentwicklung mit Delphi</i> auf den Seiten 263 und 264.
        &#10

        Comment


        • #5
          Hallo Andreas (und alle anderen),

          ich mache es jetzt so:
          Wenn im Suchstring keine Jokerzeichen (%, ...) sind, generiere ich die Abfrage mit STARTING WITH,
          wenn Jokerzeichen im Suchbegriff eingegeben wurden, kommt ein LIKE in die Abfrage. Im zweiten Fall muß der Benutzer dann eben mit einer längeren Antwortzeit rechnen, bekommt aber auch ein Ergebnis.
          Ich denke, so ist es am schnellsten und am benutzerfreundlichsten.

          Kai

          Comment


          • #6
            Hallo Kai,

            beim Einsatz von STARTING WITH wird implizit vom InterBase ein %-Joker (logisch) angehängt, da der Server alle die Datensätze zurückliefert, die mit der übergebenen Zeichenkette <b>beginnen</b>. Man muss also nicht extra ein % übergeben

            Comment


            • #7
              Hallo Andreas,

              ja klar - es ist sogar nach meinen Experimenten so, daß Du selber kein % anhängen DARFST, sonst liefert STARTING WITH keine Ergebnismenge.

              Die Unterscheidung in meinem Programm treffe ich, weil der User ja auch auf die Idee kommen könnte (irgendeiner WIRD es tun!!), einen Joker irgendwo mitten im Suchwort zu platzieren,
              z.B. '%Brenner' oder 'Model A_09'. Da versagt nämlich STARTING WITH und mein LIKE kommt zum tragen :-)

              Gruß Ka

              Comment


              • #8
                <ul>
                <li> Like wird immer mit einem Fulltable-Scan bearbeitet so weiß ich weiß
                <li> Machst Du ein explizietes Prepare bevor Du den Parameter zuweiset. Dann ist er meist etwas schneller
                <pre>
                mytable.prepare;
                mytabe.parambyName('p').AsString = "tra%lala";
                mytable.open;
                </pre>
                </ul&gt

                Comment

                Working...
                X