Hopsel: (SQL) Abfrage optimieren

Hi alle!

Ich kenne mich mit SQL noch nicht sonderlich gut aus, deshalb würde ich gern wissen, ob man das kleine Abfragemonster performanter hinbekommt.

Ich arbeite mit MSSQL-Server 2005.

SELECT *  
FROM ADRESSEN  
WHERE ADRESSEN.IDNR IN (  
   SELECT DISTINCT IDNR  
   FROM ADRESSEN  
      INNER JOIN ADRESSGRU ON  
         (ADRESSEN.IDNR = ADRESSGRU.ADR_ID) AND  
         (GR_ID=5 OR GR_ID=39 /* OR [...] (wird dynamisch hinzugefügt) */)  
)  
ORDER BY NAME1 ASC

Mit dieser Abfrage erreiche ich, dass nur die Adressen angezeigt werden, die in bestimmten Gruppen sind.
Die Abfrage klappt so auch, allerdings dauert sie schon ein paar Millisekündchen.
Das DISTINCT ist nötig (?), da eine Adresse mehreren Gruppen zugeordnet sein kann. Ohne würden die Adressen, die in x Gruppen sind, auch x-mal angezeigt werden. (Seh ich doch richtig, oder?)

Hat jemand eine bessere Idee?

Das funktioniert nicht, da DISTINCT ja nicht auf Textfelder angewandt werden darf:

SELECT DISTINCT *  
FROM ADRESSEN  
   INNER JOIN ADRESSGRU ON  
      (ADRESSEN.IDNR = ADRESSGRU.ADR_ID) AND  
      (GR_ID=5 OR GR_ID=39 /* OR [...] */)  
ORDER BY NAME1 ASC

MfG H☼psel

--
"It's amazing I won. I was running against peace, prosperity, and incumbency."
George W. Bush speaking to Swedish Prime Minister unaware a live television camera was still rolling, June 14, 2001
Selfcode: ie:% fl:( br:> va:) ls:& fo:) rl:? n4:& ss:| de:] js:| ch:? sh:( mo:) zu:)
  1. Hi,

    Ich arbeite mit MSSQL-Server 2005.

    vorweg: Mit diesem System habe ich keine Erfahrung.

    SELECT *

    Gib die Liste der gewünschten Spalten explizit an. Das dürfte die Performance zwar nicht spürbar beeinflussen, ist aber trotzdem wichtig.

    WHERE ADRESSEN.IDNR IN (

    Existiert auf adressen.idnr ein Index?

    (ADRESSEN.IDNR = ADRESSGRU.ADR_ID) AND
             (GR_ID=5 OR GR_ID=39 /* OR [...] (wird dynamisch hinzugefügt) */)

    Existiert ein Index auf adressgrz.adr_id *und* gr_id? In welcher Reihenfolge, wie sind Deine Indexe aufgebaut? Lässt sich die OR-Verknüpfungskette durch ein IN ersetzen? Sind die Indexe ggf. optimiert?

    Die Abfrage klappt so auch, allerdings dauert sie schon ein paar Millisekündchen.

    Lässt sich in Deinem DBMS ein Ausführungsplan des Statements ermitteln?

    Cheatah

    --
    X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
    X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
    X-Will-Answer-Email: No
    X-Please-Search-Archive-First: Absolutely Yes
    1. Hi Cheatah!
      Schön, eine Antwort von dir zu bekommen. :-)

      Ich arbeite mit MSSQL-Server 2005.
      vorweg: Mit diesem System habe ich keine Erfahrung.

      Dann hast du mir immer noch etwas voraus.

      SELECT *
      Gib die Liste der gewünschten Spalten explizit an. Das dürfte die Performance zwar nicht spürbar beeinflussen, ist aber trotzdem wichtig.

      Inwiefern wichtig? Ich brauche jede einzelne Spalte.

      WHERE ADRESSEN.IDNR IN (
      Existiert auf adressen.idnr ein Index?

      Ja.

      (ADRESSEN.IDNR = ADRESSGRU.ADR_ID) AND
               (GR_ID=5 OR GR_ID=39 /* OR [...] (wird dynamisch hinzugefügt) */)
      Existiert ein Index auf adressgru.adr_id *und* gr_id? In welcher Reihenfolge, wie sind Deine Indexe aufgebaut?

      Nein, es existieren keine Indizes auf adr_id und gr_id. Würde das einen merklichen Geschwindigkeitsvorteil bringen?
      Ist die Reihenfolge bei der Erstellung von Indizes wichtig?

      Lässt sich die OR-Verknüpfungskette durch ein IN ersetzen?

      Ja. =)

      SELECT *  
      FROM ADRESSEN  
      WHERE ADRESSEN.IDNR IN (  
         SELECT DISTINCT IDNR  
         FROM ADRESSEN  
            INNER JOIN ADRESSGRU ON  
               (ADRESSEN.IDNR = ADRESSGRU.ADR_ID) AND  
               GR_ID in (2,3 /* [...] */)  
      )  
      ORDER BY NAME1 ASC
      

      Sind die Indexe ggf. optimiert?

      Öhm...

      Die Abfrage klappt so auch, allerdings dauert sie schon ein paar Millisekündchen.
      Lässt sich in Deinem DBMS ein Ausführungsplan des Statements ermitteln?

      Ist das mit einer Stored Procedure schon getan?
      Kann ich einer solchen eigentlich mehrere Variablen (nämlich die Gruppen-ID-Nummern) übergeben?

      Ist folgendes Statement "besser"?

      SELECT *  
      FROM ADRESSEN  
      WHERE IDNR in (  
         SELECT ADR_ID  
         FROM ADRESSGRU  
         WHERE GR_ID in (2,3 /* [...] */)  
      )  
      ORDER BY NAME1 ASC
      

      MfG H☼psel

      --
      "It's amazing I won. I was running against peace, prosperity, and incumbency."
      George W. Bush speaking to Swedish Prime Minister unaware a live television camera was still rolling, June 14, 2001
      Selfcode: ie:% fl:( br:> va:) ls:& fo:) rl:? n4:& ss:| de:] js:| ch:? sh:( mo:) zu:)
      1. Hi,

        grundsätzlich: Indizes auf Tabellen, wo viel gelesen und weniger geschrieben wird sind immer gut - wenn man sie auf die richtigen Spalten setzt.(Punkt)

        U.U. kannst du mit einem einzelnen Index (bestehend aus mehreren Spalten) bereits eine gesamte Abfrage bedienen.

        Du weisst aber schon im Allgemeinen, was Indizes sind?

        Stored Procedures und Ausführungspläne haben direkt nicht wirklich viel miteinander zu tun. Einen Ausführungsplan lässt du dir errechnen mit einem Klick im Management Studio unter dem Menü "Query" -> "Display estimated execution plan", bzw. "Include actual execution plan". (Ja, das gibt es Unterschiede, die musst du in deinem Stadium aber noch nicht wissen.)

        Ein Ausführungsplan ist wie ein Sequenz/Ablaufdiagramm wo dir der Sql Server anzeigt, welche Objekte (Tabellen, Indizes) er benutzt und welche Operationen (Key Lookup, Bookmark Lookup, Spool ....) er benutzt um die Daten zusammenzuführen, deren Menge du beschrieben hast.

        Grundsätzlich gilt es "Table Scans" und "Clustered Index Scans" zu minimieren durch geeignetes Setzen von Indices.

        Ein Index wird vom Sql Server Query Optimizer auch nur dann benutzt, wenn die erste Spalte aus dem Index auch in der Abfrage benutzt wird - nur so mal nebenbei.

        BTW: Du kannst mich gern für 1600 € / Tag netto engagieren für Tuning deiner MS Sql Server Datenbank.

        Wenn du zwei Queries vergleichen willst hinsichtlich Qualität oder Leistung, dann pack sie untereinander und lass dir für beide zusammen den "estimated execution plan" anzeigen. Da bekommst du dann zwei Ausführungspläne mit einem prozentualen Wert für den Aufwand. Der mit < 50% ist dann "besser".

        Warum SELECT * suboptimal ist, dazu findest du hier im Forumsarchiv genügend Hinweise.

        Ciao, Frank

        1. Hi Frank!

          Du weisst aber schon im Allgemeinen, was Indizes sind?

          Eindeutige Werte, die in einer Extratabelle gespeichert werden, auf "ihren" Datensatz zeigen und mit denen man einen gesuchten/mehrere gesuchte Datensätze schnell finden kann.
          Dafür dauern Einfüge- und Löschoperationen länger, da die Indizes neu berechnet werden müssen.

          [Ausführungsplan]

          Genial! Danke. =)

          BTW: Du kannst mich gern für 1600 € / Tag netto engagieren für Tuning deiner MS Sql Server Datenbank.

          Da wird mein Chef etwas dagegen haben. Zumal ich Student bin und eher an einem "Testprojekt" arbeite.

          Warum SELECT * suboptimal ist, dazu findest du hier im Forumsarchiv genügend Hinweise.

          Dafür fehlen mir die Stichworte. Kleiner Tipp?

          MfG H☼psel

          --
          "It's amazing I won. I was running against peace, prosperity, and incumbency."
          George W. Bush speaking to Swedish Prime Minister unaware a live television camera was still rolling, June 14, 2001
          Selfcode: ie:% fl:( br:> va:) ls:& fo:) rl:? n4:& ss:| de:] js:| ch:? sh:( mo:) zu:)
          1. Warum SELECT * suboptimal ist, dazu findest du hier im Forumsarchiv genügend Hinweise.
            Dafür fehlen mir die Stichworte. Kleiner Tipp?

            SELECT * suboptimal  ... oder
            SELECT * schlecht

            Cheers, Frank

          2. Hi,

            Du weisst aber schon im Allgemeinen, was Indizes sind?
            Eindeutige Werte, die in einer Extratabelle gespeichert werden, auf "ihren" Datensatz zeigen und mit denen man einen gesuchten/mehrere gesuchte Datensätze schnell finden kann.

            Indexe sind zudem i.d.R. als binärer Baum angelegt, was die Effizienz erheblich steigert. "Eindeutige Werte" halte ich aber für eine falsche Formulierung.

            Cheatah

            --
            X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
            X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
            X-Will-Answer-Email: No
            X-Please-Search-Archive-First: Absolutely Yes
            1. Hi Cheatah!

              Indexe sind zudem i.d.R. als binärer Baum angelegt, was die Effizienz erheblich steigert.

              Logisch. =)

              "Eindeutige Werte" halte ich aber für eine falsche Formulierung.

              Eindeutig in Bezug auf ihren Datensatz.
              Nein, eindeutig in Bezug auf die Datensätze, die den gleichen Index haben.

              MfG H☼psel

              --
              "It's amazing I won. I was running against peace, prosperity, and incumbency."
              George W. Bush speaking to Swedish Prime Minister unaware a live television camera was still rolling, June 14, 2001
              Selfcode: ie:% fl:( br:> va:) ls:& fo:) rl:? n4:& ss:| de:] js:| ch:? sh:( mo:) zu:)
        2. Hallo Frank,

          <<<BTW: Du kannst mich gern für 1600 € / Tag netto engagieren für Tuning deiner MS Sql Server Datenbank.>>>

          dazu hätte ich mal ne Frage. (mail)

          Gruss
          hawk

      2. Hi,

        vorweg: Mit diesem System habe ich keine Erfahrung.
        Dann hast du mir immer noch etwas voraus.

        keine Erfahrung mit MSSQL zu haben ist also besser, als damit Erfahrung zu haben? Das lasse ich einfach mal unkommentiert stehen ;-)

        SELECT *
        Gib die Liste der gewünschten Spalten explizit an. Das dürfte die Performance zwar nicht spürbar beeinflussen, ist aber trotzdem wichtig.
        Inwiefern wichtig? Ich brauche jede einzelne Spalte.

        Du brauchst vermutlich jede *derzeit* existierende Spalte. Wenn sich das DB-Layout ändert, indem beispielsweise Spalten hinzukommen, brauchst Du diese nicht - zumindest nicht per se. Und wenn eine Spalte wegfällt, auf die Du Dich hier verlässt, dann ist es absolut sinnvoll, wenn Dein Code an genau dieser Stelle versagt.

        Gib *immer* die Liste der benötigten Spalten an. Ausnahmen gibt es höchstens bei solchen Dingen wie phpMyAdmin, die mit beliebigen Strukturen agieren können sollen.

        Nein, es existieren keine Indizes auf adr_id und gr_id. Würde das einen merklichen Geschwindigkeitsvorteil bringen?

        Das ist anzunehmen.

        Ist die Reihenfolge bei der Erstellung von Indizes wichtig?

        Die Reihenfolge der Spalten innerhalb eines Indexes, ja. Ein Index sollte möglichst schnell möglichst stark einschränken. Wenn der Index über z.B. drei Spalten geht und dabei das Abfragekriterium bei den ersten beiden Spalten je zu 90% aller Werte zutrifft, so muss immer noch 81% der dritten Spalte durchsucht werden; treffen je nur 10% zu, ist von der dritten Spalte nur noch 1% relevant. Im erstgenannten Fall ist ein Full-Table-Scan möglicherweise sogar effizienter.

        Lässt sich die OR-Verknüpfungskette durch ein IN ersetzen?
        Ja. =)

        Gut. Vergleiche die beiden Ausführungspläne miteinander ;-) (Keine Ahnung, ob und wie man die bei MSSQL bekommt. MySQL hat "EXPLAIN", in Oracle hat man glaube ich z.B. in der Konsole eine Umgebungsvariable gesetzt.)

        Sind die Indexe ggf. optimiert?
        Öhm...

        Wenn auf einer Tabelle oft Änderungen durchgeführt werden, kann es sein, dass der Index reichlich ineffizient im Speicher verteilt ist, weil der bei jedem UPDATE, INSERT und DELETE ebenfalls geändert wird. Die meisten DBMSse ermöglichen es, ihn neu berechnen zu lassen. Schlimmstenfalls geht natürlich auch ein DROP INDEX mit anschließender Neuerstellung ...

        Lässt sich in Deinem DBMS ein Ausführungsplan des Statements ermitteln?
        Ist das mit einer Stored Procedure schon getan?

        Stored Procedures haben damit eigentlich gar nichts zu tun. Ein Ausführungsplan sagt, welche "Taktik" das DBMS anwendet, um die Daten zu selektieren. Also welcher Index benutzt wird, auf welche Weise, wann vom Index auf die eigentlichen Tabellendaten zugegriffen wird[1], wann wie (und wo[2]) sortiert wird usw.

        Kann ich einer solchen eigentlich mehrere Variablen (nämlich die Gruppen-ID-Nummern) übergeben?

        Keine Ahnung, Stored Procedures habe ich nur selten gebraucht und dann immer von unserem DB-Gott erstellen lassen.

        Ist folgendes Statement "besser"?

        Was sagt der Ausführungsplan? ;-)

        Cheatah

        [1] Bei Oracle war es beispielsweise auch so, dass dieser Schritt wegfiel, wenn der Index bereits alle benötigten Daten enthielt. So mancher Index bekam von uns daher noch eine Extraspalte hinzugefügt, die zur Aussiebung völlig unnötig war, aber das "Wandern" zur Tabellenzeile und -zelle ersparte.
        [2] Manche Sortierungen passen nicht mehr in den Arbeitsspeicher und werden daher auf die Festplatte ausgelagert ...

        --
        X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
        X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
        X-Will-Answer-Email: No
        X-Please-Search-Archive-First: Absolutely Yes
        1. Moin Moin!

          vorweg: Mit diesem System habe ich keine Erfahrung.
          Dann hast du mir immer noch etwas voraus.

          keine Erfahrung mit MSSQL zu haben ist also besser, als damit Erfahrung zu haben?

          Definitv. Auf meine Erfahrungen mit MSSQL hätte ich genauso gerne verzichtet wie auf meine Erfahrungen mit Zahnwurzelbehandlungen. ;-)

          Alexander

          --
          Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
        2. Hi Cheatah!

          Lässt sich in Deinem DBMS ein Ausführungsplan des Statements ermitteln?
          Ist das mit einer Stored Procedure schon getan?
          Stored Procedures haben damit eigentlich gar nichts zu tun. Ein Ausführungsplan sagt, welche "Taktik" das DBMS anwendet, um die Daten zu selektieren. Also welcher Index benutzt wird, auf welche Weise, wann vom Index auf die eigentlichen Tabellendaten zugegriffen wird[1], wann wie (und wo[2]) sortiert wird usw.

          Ich habe mich nach einer schnellen Google-Suche auf einen Post von Frank bezogen (http://forum.de.selfhtml.org/archiv/2007/5/t152328/#m991038:

          Du kannst Abfragen mit Parametern (@variable) parameterisieren, dann erzeugt MSSQL einmal einen Ausführungsplan und hält ihn für weitere subsequente Abfragen im Query Cache -> das macht er quasi automatisch.

          Das hat mich sofort an die Stored Procedures erinnert und deshalb auch die Frage danach.

          MfG H☼psel

          --
          "It's amazing I won. I was running against peace, prosperity, and incumbency."
          George W. Bush speaking to Swedish Prime Minister unaware a live television camera was still rolling, June 14, 2001
          Selfcode: ie:% fl:( br:> va:) ls:& fo:) rl:? n4:& ss:| de:] js:| ch:? sh:( mo:) zu:)
  2. yo du einer,

    Das DISTINCT ist nötig (?), da eine Adresse mehreren Gruppen zugeordnet sein kann. Ohne würden die Adressen, die in x Gruppen sind, auch x-mal angezeigt werden. (Seh ich doch richtig, oder?)

    das distinct ist nicht zwingend notwendig in deinem falle, kanst es weglassen, wenn du mit einer unterabfrage arbeitest.

    du benutzt in der unterbabfrage die gleiche tabelle wie in der oberen, wo sind den deine aliasnamen für die gleichnamigen tabellen ?

    Ilja

    1. Hi Ilja!

      das distinct ist nicht zwingend notwendig in deinem falle, kanst es weglassen, wenn du mit einer unterabfrage arbeitest.

      Ja. Gleich mehr dazu.

      du benutzt in der unterbabfrage die gleiche tabelle wie in der oberen, wo sind den deine aliasnamen für die gleichnamigen tabellen ?

      In der Unterabfrage wird ADRESSGRU genutzt, das Abfrageergebnis ist aber aus der Tabelle ADRESSEN.

      Ich hab drei unterschiedliche Möglichkeiten für Abfragen erstellt:

      SELECT *  
      FROM ADRESSEN  
      WHERE ADRESSEN.IDNR IN (  
         SELECT DISTINCT IDNR  
         FROM ADRESSEN  
            INNER JOIN ADRESSGRU ON  
               (ADRESSEN.IDNR = ADRESSGRU.ADR_ID) AND  
               GR_ID in (2,3 /* [...] */)  
      )  
      ORDER BY NAME1 ASC
      
      SELECT *  
      FROM ADRESSEN  
      WHERE IDNR in (  
         SELECT ADR_ID  
         FROM ADRESSGRU  
         WHERE GR_ID in (2,3 /* [...] */)  
      )  
      ORDER BY NAME1 ASC
      

      Diese Abfrage ist nach einem simplen Test am performantesten. Spricht etwas dagegen, mit der Unterabfrage zu arbeiten?
      Kann man das noch weiter optimieren?

      SELECT *  
      FROM ADRESSEN  
      WHERE ADRESSEN.IDNR IN (  
         SELECT IDNR  
         FROM ADRESSEN  
            INNER JOIN ADRESSGRU ON  
               (ADRESSEN.IDNR = ADRESSGRU.ADR_ID) AND  
               GR_ID in (2,3 /* [...] */)  
         GROUP BY IDNR  
      )  
      ORDER BY NAME1 ASC
      

      MfG H☼psel

      --
      "It's amazing I won. I was running against peace, prosperity, and incumbency."
      George W. Bush speaking to Swedish Prime Minister unaware a live television camera was still rolling, June 14, 2001
      Selfcode: ie:% fl:( br:> va:) ls:& fo:) rl:? n4:& ss:| de:] js:| ch:? sh:( mo:) zu:)
      1. yo,

        du benutzt in der unterbabfrage die gleiche tabelle wie in der oberen, wo sind den deine aliasnamen für die gleichnamigen tabellen ?

        In der Unterabfrage wird ADRESSGRU genutzt, das Abfrageergebnis ist aber aus der Tabelle ADRESSEN.

        meine augen mögen schon älter sein, aber ich sehe die tabelle Adressen sowohl in der unterabfrage und auch in der oberen abfrage. wenn du sowas machst, dann immer alias namen verwenden, bzw. grundsätzlich immer alias namen verwenden.

        Diese Abfrage ist nach einem simplen Test am performantesten. Spricht etwas dagegen, mit der Unterabfrage zu arbeiten?

        nein, liefert das gleiche ergebnis

        Kann man das noch weiter optimieren?

        die sortierung raus nehmen, wenn sie nicht erforderlich ist und endlich das * entfernen.

        Ilja

        1. Hi Ilja!

          meine augen mögen schon älter sein, aber ich sehe die tabelle Adressen sowohl in der unterabfrage und auch in der oberen abfrage. wenn du sowas machst, dann immer alias namen verwenden, bzw. grundsätzlich immer alias namen verwenden.

          Ich würde das ja gerne kommentarlos hinnehmen, allerdings fehlt mir die Begründung.
          Was ist ein Alias und warum sollte ich ihn nehmen?

          Kann man das noch weiter optimieren?
          die sortierung raus nehmen, wenn sie nicht erforderlich ist und endlich das * entfernen.

          Die Sortierung ist sogar eine Hauptfunktion des Programms.

          MfG H☼psel

          --
          "It's amazing I won. I was running against peace, prosperity, and incumbency."
          George W. Bush speaking to Swedish Prime Minister unaware a live television camera was still rolling, June 14, 2001
          Selfcode: ie:% fl:( br:> va:) ls:& fo:) rl:? n4:& ss:| de:] js:| ch:? sh:( mo:) zu:)
          1. yo,

            Ich würde das ja gerne kommentarlos hinnehmen, allerdings fehlt mir die Begründung.
            Was ist ein Alias und warum sollte ich ihn nehmen?

            alias namen sind ersatznamen für tabellen (objekte), zum_beispiel_weil_die_tabelle_so_lang_ist, dass keiner sie immer wieder schreiben will oder aber die gleiche tabelle kommt mehr als einmal in der abfrage vor, so wie es bei dir der fall ist. woher soll den dann das dbms wissen, welche spalte aus welchte der namensgleichen tabelle du willst ? mein tipp an dich, arbeite immer mit alias namen.

            SELECT *
            FROM ADRESSEN <---- hier das erste mal
            WHERE ADRESSEN.IDNR IN (
               SELECT DISTINCT IDNR
               FROM ADRESSEN <----- hier das zweite mal
                  INNER JOIN ADRESSGRU ON
                     (ADRESSEN.IDNR = ADRESSGRU.ADR_ID) AND
                     (GR_ID=5 OR GR_ID=39 /* OR [...] (wird dynamisch hinzugefügt) */)
            )
            ORDER BY NAME1 ASC

            Ilja

  3. Hallo ihr drei!

    Mein Abfrage sieht nun wie folgt aus:

    SELECT ADRESSEN.IDNR, ADRESSEN.NAME1 /* , [...] */  
    FROM ADRESSEN  
    WHERE ADRESSEN.IDNR in (  
       SELECT ADR_ID  
       FROM ADRESSGRU  
       WHERE GR_ID in (2, 3 /* [...] */)  
    )  
    ORDER BY NAME1 ASC
    

    Diese Abfrage ist doch tatsächlich ca. 1/3 schneller. Dafür schon mal ein dickes Dankeschön.

    Ilja hat vorgeschlagen Aliase zu verwenden. Was bringt mir das in meinem Fall?

    MfG H☼psel

    --
    "It's amazing I won. I was running against peace, prosperity, and incumbency."
    George W. Bush speaking to Swedish Prime Minister unaware a live television camera was still rolling, June 14, 2001
    Selfcode: ie:% fl:( br:> va:) ls:& fo:) rl:? n4:& ss:| de:] js:| ch:? sh:( mo:) zu:)
    1. Ilja hat vorgeschlagen Aliase zu verwenden. Was bringt mir das in meinem Fall?

      Wenn du mehrfach von den selben Tabellen selektierst, wie soll dann (ohne Alias) mssql wissen, welche Tabelle du meinst? Im besten Fall bekommst du dann eine Fehlermeldung um die Ohren geknallt, im schlimmsten Fall funktioniert es irgendwie, du denkst dass es korrekte Ergebnisse liefert, aber es gibt dir einfach nur Rubbish zurück.

      Explizität hat noch niemandem geschadet.

      Und worin liegt der Unterschied zwischen den Queries? Was sagen die Ausführungspläne?

      Ciao, Frank

      1. Hi Frank!

        Wenn du mehrfach von den selben Tabellen selektierst, wie soll dann (ohne Alias) mssql wissen, welche Tabelle du meinst?

        Ich selektiere aber nur jeweils einmal von je einer Tabelle. Oder nicht...?
        Einmal aus ADRESSEN und im Subquery einmal aus ADRESSGRU. Wozu benötige ich hier Aliase? Ich finde ehrlich gesagt auch nichts in dem dicken SQL-Handbuch über Aliase ( bzw. nur über Datenbankaliase, aber die sind hier ja wohl kaum gemeint).

        Und worin liegt der Unterschied zwischen den Queries? Was sagen die Ausführungspläne?

        SELECT ADRESSEN.IDNR, ADRESSEN.INFO /*, [...]*/ FROM ADRESSEN  
        WHERE ADRESSEN.IDNR in (SELECT ADR_ID FROM ADRESSGRU WHERE GR_ID in (5,39,3,10,1) ) ORDER BY NAME1 ASC  
          
        SELECT * FROM ADRESSEN  
        WHERE ADRESSEN.IDNR in (SELECT ADR_ID FROM ADRESSGRU WHERE GR_ID in (5,39,3,10,1) ) ORDER BY NAME1 ASC
        

        Einziger Unterschied: Einmal explizite Angabe der Spalten, einmal mit *.
        Ausführungsplan zeigt mir jeweils 50%.

        Die erste Abfrage ist aber eindeutig schneller.

        MfG H☼psel

        --
        "It's amazing I won. I was running against peace, prosperity, and incumbency."
        George W. Bush speaking to Swedish Prime Minister unaware a live television camera was still rolling, June 14, 2001
        Selfcode: ie:% fl:( br:> va:) ls:& fo:) rl:? n4:& ss:| de:] js:| ch:? sh:( mo:) zu:)
        1. Okay, beispiel

          Tabelle Price   (Fund, Investable, AsOfDate, Price)
          Tabelle Investable   (Id, Fund, Name, AsOfDate)
          Zwischen Price.Fund und Investable.Fund sowie Price.Investable und Investable.Id gibt es ForeignKey-Beziehungen

          Wenn du jetzt folgende Abfrage nimmst

          SELECT Fund, Investable, Name, AsOfDate, Price
          FROM Investable
          INNER JOIN Price
             ON Fund = Fund
             AND Investable = Id

          ... bekommst du mindestens 3 Meldungen "ambigious use of column name" o.s.ä.  weil die Spalten in beiden Tabellen gleich heissen, nicht? Aus welcher Tabelle soll denn AsOfDate nun genommen werden?

          Um das zu umgehen müsstest du schreiben

          SELECT Investable.Fund, Price.Investable, Investable.Name, Price.AsOfDate, Price
          FROM Investable
          INNER JOIN Price
             ON Price.Fund = Investable.Fund
             AND Price.Investable = Investable.Id

          Und jetzt stell dir vor, du hast n langen komplizierten Namen für die Tabelle ... sowas wie PrzybilskiUndIvanovichMonsterTabelle, willst du das jedes mal tippen oder C&P'en? Dann wird dein Code ziemlich unleserlich.

          Stattdessen würdest zu einfach Aliase p und i verwenden ... lassen sich einfacer merken und machen es damit übersichtlicher.

          SELECT I.Fund, P.Investable, I.Name, P.AsOfDate, Price
          FROM Investable I
          INNER JOIN Price P
             ON P.Fund = I.Fund
             AND P.Investable = I.Id

          Soweit verstanden. Performancemässig hat das sogut wie 0 Einfluss.

          Wie hast du dir denn den Ausführungsplan anzeigen lassen? Als "estimated" oder den wirklichen bei der Ausführung? "Estimated" heisst estimated, weils ne ungefähre Schätzung vom Server ist, der Actual Execution Plan sollte dir dann schon Unterschiede zeigen.

          Oder anders, wenn du nur 5 Spalten von den insgesamt 200 in der Tabelle brauchst, brauchen auch nur 5 gelesen werden = weniger Daten = weniger Daten im Ram usw.

          Ciao, Frank

          1. Hi Frank!

            Okay, beispiel

            Fantastisch. Ich danke dir recht herzlich.

            Soweit verstanden. Performancemässig hat das sogut wie 0 Einfluss.

            Eben das habe ich mir schon gedacht. Damit ist das Thema für mich auch gegessen. Trotzdem wieder was gelernt. Aliase werden auf jeden Fall genutzt.

            Wie hast du dir denn den Ausführungsplan anzeigen lassen? Als "estimated" oder den wirklichen bei der Ausführung?

            "Abfrage -> Tatsächlichen Ausführungsplan einschließen" aktiviert und Abfrage mit den zwei SELECT-Anweisungen ausgeführt.

            Ausgabe: "Abfragekosten (in Relation zum Batch): 50 %"

            "Estimated" heisst estimated, weils ne ungefähre Schätzung vom Server ist, der Actual Execution Plan sollte dir dann schon Unterschiede zeigen.

            Ich sehe nur in den "Clientstatistiken" einen Unterschied zwischen den beiden Abfragen. Im Ausführungsplan sind sie komplett identisch.

            Oder anders, wenn du nur 5 Spalten von den insgesamt 200 in der Tabelle brauchst, brauchen auch nur 5 gelesen werden = weniger Daten = weniger Daten im Ram usw.

            Mehr als 500 Einträge werden es wosiewo nicht. =) Und die Spaltenanzahl hält sich mit ca. 25 noch im Rahmen.

            MfG H☼psel

            --
            "It's amazing I won. I was running against peace, prosperity, and incumbency."
            George W. Bush speaking to Swedish Prime Minister unaware a live television camera was still rolling, June 14, 2001
            Selfcode: ie:% fl:( br:> va:) ls:& fo:) rl:? n4:& ss:| de:] js:| ch:? sh:( mo:) zu:)