Stefan Welscher: [MySQL] 25-minütige SELECT-Abfrage mit 2 Tabellen beschleunigen?

Moin moin,
ich hab hier zwei Tabellen.
Die erste nennt sich ref_sp (ca. 86.000 Einträge, je 11 Spalten), die zweite router (ca. 60.000 Einträge, je 83 Spalten).

Aus den Daten beider Tabellen muss ich eine dritte Datenbank bilden ref_sp_r, die alle Daten aus ref_sp und das Feld router_name aus router enthält. Dafür habe ich folgende Abfrage geschrieben:

SELECT DISTINCT r.router_name AS hostname, s.vpn_id AS vpn_id, s.sp_no AS sp_no, s.oid_r AS roid, s.oid AS soid FROM ref_sp AS s, router AS r WHERE r.oid>0 AND r.oid=s.oid_r;

Das Problem ist einfach, die Abfrage funktioniert, dauert aber 25 Minuten (CPU ist ein Intel C2D), die Lösung nicht.

Was ich bisher probiert habe:

  • INNER JOIN: Keine großartige Verbesserung
  • Beider Tabellen in PHP laden und dort zueinander matchen (ca. 40Minuten)
  • Tabelle ref_sp laden und mit einzelnen SELECT-Anfragen den hostname suchen (>1 Stunde)
  • Umstellung von  MyISAM auf InnoDB (ca. 40 Minuten)

Irgendwie muss es da noch potential geben, denn wenn ich die Abfrage mit INNER JOIN in der alten Access-DB ausführe (gleiche Datensätze) braucht die Ausführung gerade mal 5 Sekunden.

Vielen Dank im Vorraus!

  1. Hi,

    Was ich bisher probiert habe:

    welche Indexe hast Du auf die Tabellen gelegt?

    Irgendwie muss es da noch potential geben, denn wenn ich die Abfrage mit INNER JOIN in der alten Access-DB ausführe (gleiche Datensätze) braucht die Ausführung gerade mal 5 Sekunden.

    Hurra. Solange Du in der Lage bist, den Wert zu messen, dauert es zu lange. Was liefert "EXPLAIN SELECT ..." mit dem Statement?

    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,

      Was ich bisher probiert habe:

      welche Indexe hast Du auf die Tabellen gelegt?

      Anbei die Ausgabe vom Export:

        
      CREATE TABLE IF NOT EXISTS `ref_sp_id` (  
        `id` bigint(20) unsigned NOT NULL auto_increment,  
        `oid` bigint(20) unsigned NOT NULL COMMENT 's_object_id',  
        `oid_r` bigint(20) unsigned default NULL COMMENT 'r_object_id',  
        `oid_rgw` bigint(20) unsigned default NULL,  
        `oid_l` bigint(20) unsigned default NULL COMMENT 'l_object_id',  
        `oid_p` bigint(20) unsigned default NULL,  
        `oid_i` bigint(20) unsigned default NULL COMMENT 'i_object_id',  
        `oid_sw` bigint(20) unsigned default NULL,  
        `oid_d` bigint(20) unsigned default NULL COMMENT 'd_object_id',  
        `oid_lia` bigint(20) unsigned default NULL,  
        `hostname` varchar(255) collate utf8_unicode_ci NOT NULL,  
        `vpn_id` bigint(20) unsigned NOT NULL COMMENT 'sp_part1',  
        `sp_no` bigint(20) unsigned NOT NULL COMMENT 'sp_part2',  
        `sp_id` varchar(255) collate utf8_unicode_ci NOT NULL,  
        PRIMARY KEY  (`id`)  
      ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=86122 ;
      
        
      CREATE TABLE IF NOT EXISTS `router_ce` (  
        `id` bigint(20) unsigned NOT NULL auto_increment,  
        `oid` bigint(20) unsigned NOT NULL COMMENT 'r_object_id',  
      ....  
        `router_name` varchar(255) collate utf8_unicode_ci default NULL,  
      ....  
        PRIMARY KEY  (`id`)  
      ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=89521 ;
      

      (In router_ce sind entgegen meines ersten Postings doch noch 30.000 Datensätze mehr)

      Hurra. Solange Du in der Lage bist, den Wert zu messen, dauert es zu lange.

      Da sind wir einer Meinung :)

      »»Was liefert "EXPLAIN SELECT ..." mit dem Statement?

      EXPLAIN SELECT liefert:

      +----+-------------+-------+------+---------------+------+---------+------+-------+------------------------------+  
      | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra                        |  
      +----+-------------+-------+------+---------------+------+---------+------+-------+------------------------------+  
      |  1 | SIMPLE      | s     | ALL  | NULL          | NULL | NULL    | NULL | 86121 | Using where; Using temporary |  
      |  1 | SIMPLE      | r     | ALL  | NULL          | NULL | NULL    | NULL | 89520 | Using where                  |  
      +----+-------------+-------+------+---------------+------+---------+------+-------+------------------------------+  
      
      
      1. Hi!

        welche Indexe hast Du auf die Tabellen gelegt?

        Hast du mal probiert auf die Frage selbst eine Antwort zu finden? Siehst du in der (hier weggelassenen) Ausgabe einen Index? Ich nicht, abgesehen vom Primärschlüssel, der in deiner Abfrage jedoch keine Rolle spielt.

        Was liefert "EXPLAIN SELECT ..." mit dem Statement?

        EXPLAIN SELECT liefert:
        +----+-------------+-------+------+---------------+------+---------+------+-------+------------------------------+
        | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra                        |
        +----+-------------+-------+------+---------------+------+---------+------+-------+------------------------------+
        |  1 | SIMPLE      | s     | ALL  | NULL          | NULL | NULL    | NULL | 86121 | Using where; Using temporary |
        |  1 | SIMPLE      | r     | ALL  | NULL          | NULL | NULL    | NULL | 89520 | Using where                  |
        +----+-------------+-------+------+---------------+------+---------+------+-------+------------------------------+

        Hast du versucht, diese Ausgabe zu verstehen?

        Wenn keine Indexe gesetzt sind, können logischerweise auch keine verwendet werden (possible_keys: NULL). Ergebnis ist ein Full Table Scan nach Zeilen wo r.oid größer als 0 ist. "Using temporary" heißt, dass eine temporäre Tabelle mit dem Verknüpfungsergebnis angelegt wird. Wenn er bei jedem Wert der einen Tabelle (r.oid) die andere komplett nach dem passenden Verknüpfungswert (s.oid_r) durchsuchen muss, weil er keinen Index verwenden kann, dauert das natürlich.

        Lo!

      2. Hi,

        welche Indexe hast Du auf die Tabellen gelegt?
        Anbei die Ausgabe vom Export:

        also keine Indexe, vom Primary Key abgesehen (den Du in der Selektion nicht nutzt). Damit haben wir den Übeltäter.

        EXPLAIN SELECT liefert:

        +----+-------------+-------+------+---------------+------+---------+------+-------+------------------------------+

        | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra                        |
        +----+-------------+-------+------+---------------+------+---------+------+-------+------------------------------+
        |  1 | SIMPLE      | s     | ALL  | NULL          | NULL | NULL    | NULL | 86121 | Using where; Using temporary |
        |  1 | SIMPLE      | r     | ALL  | NULL          | NULL | NULL    | NULL | 89520 | Using where                  |
        +----+-------------+-------+------+---------------+------+---------+------+-------+------------------------------+

          
        Die type=ALL sind kritisch und müssen unbedingt[1] eliminiert werden. Wenn Du günstige Indexe erzeugst, fallen sie weg.  
          
        Cheatah  
          
        [1] Es gibt extrem seltene Fälle, wo ein Full Table Scan tatsächlich performanter als ein Index ist. Die Tabelle hat dann aber auch nur, sagen wir, zwei oder drei Datensätze.
        
        -- 
        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. yo,

          [1] Es gibt extrem seltene Fälle, wo ein Full Table Scan tatsächlich performanter als ein Index ist. Die Tabelle hat dann aber auch nur, sagen wir, zwei oder drei Datensätze.

          erstens sind die fälle nicht extrem selten und zweitens nicht nur, wenn die tabellen sehr klein ist. ein full scan kann durchaus sinnvoll sein und ist nicht immer zu eleminieren, sondern liegt in der natur der aufgabe und der daten. immer nach einem index zu schreien und es als allheilmittel zu propagieren macht keinen sinn. es kommt immer auf die situation drauf an und vor allem immer wieder auf den praxistest.

          Ilja

        2. Hi,

          welche Indexe hast Du auf die Tabellen gelegt?
          Anbei die Ausgabe vom Export:

          also keine Indexe, vom Primary Key abgesehen (den Du in der Selektion nicht nutzt). Damit haben wir den Übeltäter.

          EXPLAIN SELECT liefert:

          +----+-------------+-------+------+---------------+------+---------+------+-------+------------------------------+

          | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows  | Extra                        |
          +----+-------------+-------+------+---------------+------+---------+------+-------+------------------------------+
          |  1 | SIMPLE      | s     | ALL  | NULL          | NULL | NULL    | NULL | 86121 | Using where; Using temporary |
          |  1 | SIMPLE      | r     | ALL  | NULL          | NULL | NULL    | NULL | 89520 | Using where                  |
          +----+-------------+-------+------+---------------+------+---------+------+-------+------------------------------+

          
          >   
          > Die type=ALL sind kritisch und müssen unbedingt[1] eliminiert werden. Wenn Du günstige Indexe erzeugst, fallen sie weg.  
            
          OK, von Indexes außerhalb des Primärschlüssels hab ich bis jetzt noch nichts gehört gehabt, klingt aber spannend.  
            
          Kurz zum Abgleich:  
          Wenn ich Google richtig verstehe, werden die indizierten Spalten schon bei der Indexierung so aufbereitet, dass die Suchanfragen schneller abgearbeitet werden. Wenn ein neuer Datensatz hinzugefügt wird, wird der Index automatisch angepasst. Ich kann nahezu beliebig viele Spalten indizieren. Ich habe durch die Indizierung außer dem erhöhten Speicherbedarf keine Nachteile.  
            
          Ist das soweit korrekt?  
            
            
          Ich hab meine Datenbanken jetzt wie folgt angepasst:  
          ~~~sql
            
          CREATE TABLE IF NOT EXISTS `ref_sp` (  
            `id` bigint(20) unsigned NOT NULL auto_increment,  
            `oid` bigint(20) unsigned NOT NULL COMMENT 's_object_id',  
            `oid_r` bigint(20) unsigned default NULL,  
            `oid_rgw` bigint(20) unsigned default NULL,  
            `oid_l` bigint(20) unsigned default NULL,  
            `oid_p` bigint(20) unsigned default NULL,  
            `oid_i` bigint(20) unsigned default NULL,  
            `oid_sw` bigint(20) unsigned default NULL,  
            `oid_d` bigint(20) unsigned default NULL,  
            `oid_lia` bigint(20) unsigned default NULL,  
            `hostname` varchar(255) collate utf8_unicode_ci NOT NULL,  
            `vpn_id` bigint(20) unsigned NOT NULL,  
            `sp_no` bigint(20) unsigned NOT NUL,  
            `sp_id` varchar(255) collate utf8_unicode_ci NOT NULL,  
            PRIMARY KEY  (`id`),  
            KEY `oid` (`oid`),  
            KEY `oid_r` (`oid_r`),  
            KEY `oid_rgw` (`oid_rgw`),  
            KEY `oid_l` (`oid_l`),  
            KEY `oid_p` (`oid_p`),  
            KEY `oid_i` (`oid_i`),  
            KEY `oid_sw` (`oid_sw`),  
            KEY `oid_d` (`oid_d`),  
            KEY `oid_lia` (`oid_lia`)  
          ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=86122 ;
          
            
          CREATE TABLE IF NOT EXISTS `router_ce` (  
            `id` bigint(20) unsigned NOT NULL auto_increment,  
            `oid` bigint(20) unsigned NOT NULL COMMENT 'r_object_id',  
          ....  
            `router_name` varchar(255) collate utf8_unicode_ci default NULL,  
          ....  
            PRIMARY KEY  (`id`),  
            KEY `oid` (`oid`),  
            KEY `router_name` (`router_name`)  
          ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=89521 ;  
          
          

          EXPLAIN SELECT sagt jetzt:

            
          +----+-------------+-------+------+---------------+-----------+---------+-------------------+-------+------------------------------+  
          | id | select_type | table | type | possible_keys | key       | key_len | ref               | rows  | Extra                        |  
          +----+-------------+-------+------+---------------+-----------+---------+-------------------+-------+------------------------------+  
          |  1 | SIMPLE      | s     | ALL  | oid_r   | NULL      | NULL    | NULL              | 86121 | Using where; Using temporary |  
          |  1 | SIMPLE      | r     | ref  | oid     | oid | 8       | rot.s.oid_r |     1 |                              |  
          +----+-------------+-------+------+---------------+-----------+---------+-------------------+-------+------------------------------+  
          
          

          Das ganze geht jetzt schon ein wenig ;) schneller (dauert nur noch ca. 10 Sekunden, zuvor waren es eben 25 Minuten)

          In der ersten Spalte steht jetzt immernoch type ALL.
          Sollte das jetzt noch weg und wenn ja, irgendwelche Ideen wie das geht?
          Auch wenn ich alle Spalten indiziere steht da noch ALL.

          1. Hi,

            Hi,

            nebenbei: Es wäre nett, wenn Du die zitierten Texte auf das kürzen würdest, auf das Du Dich beziehst.

            Wenn ich Google richtig verstehe, werden die indizierten Spalten schon bei der Indexierung so aufbereitet, dass die Suchanfragen schneller abgearbeitet werden. Wenn ein neuer Datensatz hinzugefügt wird, wird der Index automatisch angepasst. Ich kann nahezu beliebig viele Spalten indizieren. Ich habe durch die Indizierung außer dem erhöhten Speicherbedarf keine Nachteile.

            Ist das soweit korrekt?

            Ja, auch wenn es durchaus weitere Nachteile gibt. Jeder Index kostet Zeit bei UPDATE-, INSERT- und DELETE-Statements, und durch die komplexere Art und Weise der Datensuche geht auf andere Weise Zeit ins Land. Ich habe ja bereits Fälle angedeutet, in denen der Verzicht auf einen Index von Vorteil ist; und Ilja mahnt nicht zu Unrecht zu mehr Weitsicht. Soweit ich Deine Daten bisher aber verstehe, ist mindestens ein gut gewählter Index pro Tabelle uneingeschränkt empfehlenswert.

            Ich hab meine Datenbanken jetzt wie folgt angepasst:

            Zu weit gegriffen. Indexe gehören zum DB-Layout *genau wie die Statements*. Sie müssen allesamt aufeinander abgestimmt sein. Lege also genau die Indexe an, die Du benötigst; bei einer Erweiterung des DB-Layouts (beispielsweise einer neuen Abfrage) musst Du die Indexe neu bewerten. Ziehe insbesondere in Betracht, dass jeder _einzelne_ Index über mehrere Spalten gehen kann.

            In der ersten Spalte steht jetzt immernoch type ALL.
            Sollte das jetzt noch weg und wenn ja, irgendwelche Ideen wie das geht?

            Deine Abfrage über die Tabelle s betrachtet die Spalte s.oid_r. Belege diese mit einem Index.

            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
          2. yo,

            Ich habe durch die Indizierung außer dem erhöhten Speicherbedarf keine Nachteile.
            Ist das soweit korrekt?

            nein, grundsätzlich kannst du dir einen index als eigenes objekt in der datenbank vorstellen, das zusätzlich zu der tabelle angelegt wird. hinter diesen index objekten steckt letztlich eine sortierung, was eben den schnelleren zugriff zuläßt als bei einer tabelle, die in aller regel unsortiert ist. kommen neue datensätze in der tabele hinzu, werden welche gelöscht oder geändert passt das DBMS den index automatisch an, wie du ja selbst geschrieben hast. demzufolge ist ein index nicht umsonst zu haben, als faustregel gilt, er KANN abfragen beschleunigen, bringt aber einbußen beim löschen, einfügen und verändern von datensätzen. hinzukommt, dass der speicherbedarf je nach fall nicht gerade klein sein muss.

            insofern macht macht es keinen sinn, deine tabelle mit indexen zu erschießen, das bringt unter dem strich oftmals nur nachteile. gefragt ist ein sinnvoller einsatz von indexen und anderen optimierungsmöglichkeiten. tunig ist letztlich die königsdisziplin bei datenbanken und ein schwieriges thema.

            In der ersten Spalte steht jetzt immernoch type ALL.
            Sollte das jetzt noch weg und wenn ja, irgendwelche Ideen wie das geht?

            lass dich von den aussagen zuvor nicht auf die falsche fährte bringen. nur weil im explain ein ALL auftaucht muss dass noch lange nichts negatives sein. das ist reine panikmache.

            noch ein paar tipps, grundsätzlich solltest du die explizite JOIN schreibeweise verwenden, nicht wegen der geschwindigkeit, sondern vor allem wegen der besseren lesbarkeit. zum anderen hast du ein DISTINCT in deiner abfrage zu stehen. es ist zu klären, ob du dies überhaupt brauchst, ob doppelte werte vorkommen können und wenn ja, ob die dann auch wegfallen sollen. und gibt es den werte in der ref_sp Tabelle, wo die oid spalte werte mit kleiner 0 haben ? wenn du das nämlich auschließen kannst, kannst du dir auch die oid > 0 bedingung sparen, bzw, wenn nicht kannst du sie mal anstelle in der router tabelle auszuschließen mal in der ref_sp ausschließen. vieles hat einfach mit probieren zu tun.

            Ilja

            1. Hi,
              »»...als faustregel gilt, er KANN abfragen beschleunigen, bringt aber einbußen beim löschen, einfügen und verändern von datensätzen.
              Ja, das hatte ich inzwischen schon vermutet.
              Das schöne an der Quelldatenbank ist, dass sie nur zwei mal täglich von CSV-Files importiert, danach in eine Zieldatenbank aufbereitet wird und ab da nicht mehr zum schreiben verwendet wird. Aber 25 Minuten pro Abfrage waren für den Job einfach viel zu lang.

              Ich lasse dann meinen Cronjob wie folgt laufen:

              -> Temp DB aus CSV-Daten anlegen/füllen
              -> Indexe über Temp DB legen
              -> Live DB durch Temp DB ersetzen
              -> Aufbereitung starten

              Damit dürfte die Performance wohl am besten sein.

              insofern macht es keinen sinn, deine tabelle mit indexen zu erschießen, das bringt unter dem strich oftmals nur nachteile.

              Ich verstehe was du meinst, aber in dem konkreten Beispiel wird es noch andere Querries geben in denen auch die restlichen Felder benötigt werden.
              In Anbetracht der tatsache, dass die DB nach der Indizierung nur noch gelesen werden muss ist das denke ich kein Problem fast alles zu indizieren.

              zum anderen hast du ein DISTINCT in deiner abfrage stehen. es ist zu klären, ob du dies überhaupt brauchst, ob doppelte werte vorkommen können und wenn ja, ob die dann auch wegfallen sollen.

              Kann man beides mit "ja" beantworten. Die doppelten Werte würden später zu Problemen führen.

              und gibt es den werte in der ref_sp Tabelle, wo die oid spalte werte mit kleiner 0 haben ?

              Nicht <0, aber =0

              Danke euch für alle Tipps!

              1. yo,

                Das schöne an der Quelldatenbank ist, dass sie nur zwei mal täglich von CSV-Files importiert, danach in eine Zieldatenbank aufbereitet wird und ab da nicht mehr zum schreiben verwendet wird.

                es gibt halt unterschiedliche typen von Datenbanken, OLTP, OLAP, etc. je mehr wir wissen, was genau du importierst und was deine anforderungen sind, um so besser können wir hilfe leisten.

                -> Indexe über Temp DB legen

                du meinst sicherlich eine temp tabellen, eine temporäre datenbank wäre mir neu. und man muss schauen, ob man die indexe braucht.

                -> Live DB durch Temp DB ersetzen

                auch hier die frage, ob man immer alles neu machen muss, hängt aber von deinem umfeld ab.

                Ich verstehe was du meinst, aber in dem konkreten Beispiel wird es noch andere Querries geben in denen auch die restlichen Felder benötigt werden.

                das ist der falsche weg, indexe erst einsetzen und vor allem auch vorher testen, wenn man sie den braucht. es gibt viele, sehr viele dinge die verhindern, das ein index wie angedacht auch wirklich vom dbms benutzt wird.

                Kann man beides mit "ja" beantworten. Die doppelten Werte würden später zu Problemen führen.

                nur um noch mal sicher zu gehen, es gibt definitiv auch doppelte werte über alle spalten, die ausgegeben werden ?

                und gibt es den werte in der ref_sp Tabelle, wo die oid spalte werte mit kleiner 0 haben ?
                Nicht <0, aber =0

                ahh, o werte hatte ich unterschlagen. und 0 werte kommen auch in beiden tabellen vor ? für das dbms ist es immer besser auf gleichheit zu prüfen, als auf größer/kleiner oder ungleichheit. dies könntest du mit einem trick erreichen, indem du in einer zusätzlichen spalte alle werte mit 0 auf 0 beläßt und die anderen auf 1 füllst. dannach einen zusammengestzten index erstellen.

                noch mal den tipp, vinzenz hat ihn dir auch gegeben, benutze explizite joins- mir ging es ähnlich am anfang wollte ich nicht aus gewohnheit. aber du wirst es zu schätzen wissen.

                Ilja

                1. Hallo Ilja,

                  noch mal den tipp, vinzenz hat ihn dir auch gegeben, benutze explizite joins- mir ging es ähnlich am anfang wollte ich nicht aus gewohnheit. aber du wirst es zu schätzen wissen.

                  hattest Du in Oracle noch die proprietäre Outer-Join-Syntax anwenden (und lernen) müssen?

                  Freundliche Grüße

                  Vinzenz

                  1. moin Vinzenz,

                    hattest Du in Oracle noch die proprietäre Outer-Join-Syntax anwenden (und lernen) müssen?

                    ich habe auf 9i gelernt, das war genau die Version, wo der wechsel zu explizite JOINS stattgefunden hat. und da alles noch so frisch war, musste beide schreibweisen in Oracle lernen, zumal ich dann in der praxis auch mit einer 8er version zu tun hatte.....

                    Ilja

          3. Hallo Stefan,

            ich habe Deine Abfrage mit expliziter Join-Syntax umgeschrieben. Performance sollte das nicht bringen (das war mal), ich finde sie nur wesentlich lesbarer.

            SELECT DISTINCT  
                r.router_name AS hostname,  
                s.vpn_id AS vpn_id,  
                s.sp_no AS sp_no,  
                s.oid_r AS roid,  
                s.oid AS soid  
            FROM  
                ref_sp AS s  
            INNER JOIN  
                router AS r  
            ON  
                r.oid = s.oid_r  
            WHERE  
                r.oid > 0;  
            
            

            Wenn ich Google richtig verstehe, werden die indizierten Spalten schon bei der Indexierung so aufbereitet, dass die Suchanfragen schneller abgearbeitet werden. Wenn ein neuer Datensatz hinzugefügt wird, wird der Index automatisch angepasst. Ich kann nahezu beliebig viele Spalten indizieren. Ich habe durch die Indizierung außer dem erhöhten Speicherbedarf keine Nachteile.

            Ist das soweit korrekt?

            nein, das ist nicht soweit korrekt. INSERT- und UPDATE-Operationen werden aufwendiger, weil der Index angepasst werden muss.

            Bei großen Datenimports kann es günstiger sein, zuerst Indexe zu löschen, den Datenimport durchzuführen und danach die Indexe wieder neu anzulegen.

            Zu Deinem Problem solltest Du das Optimierungskapitel des MySQL-Handbuchs durcharbeiten, insbesondere den Abschnitt zum Vermeiden von Full-Table-Scans.

            Ich hab' überhaupt keine Vorstellung, welche Daten in Deinen Spalten enthalten sind, keine Vorstellung, wie oft diese in Deinen (inzwischen) indizierten Spalten vorkommen können, da Du diese wichtigen Informationen einfach verschweigst. DB-Tuning, Abfragen-Tuning ist oft genug von den vorhandenen Daten abhängig, wie Du im von mir verlinkten Kapitel nachlesen kannst.

            Ein paar Beispieldatensätze der Ausgangstabellen sowie das gewünschte Ergebnis mit einer Nicht-SQL-Beschreibung sind im Normalfall hilfreicher als vollständige CREATE-Statements ohne jeglichen Kommentar.

            Freundliche Grüße

            Vinzenz

            1. Hi,

              ich habe Deine Abfrage mit expliziter Join-Syntax umgeschrieben. Performance sollte das nicht bringen (das war mal), ich finde sie nur wesentlich lesbarer.

              Da mache ich eher die gegenteilige Erfahrung, komme mit der Nicht-Join-Schreibweise besser zurecht. Wenn es keine Performance bringt würde ich das gerne so lassen.

              Ich hab' überhaupt keine Vorstellung, welche Daten in Deinen Spalten enthalten sind, keine Vorstellung, wie oft diese in Deinen (inzwischen) indizierten Spalten vorkommen können, da Du diese wichtigen Informationen einfach verschweigst. DB-Tuning, Abfragen-Tuning ist oft genug von den vorhandenen Daten abhängig, wie Du im von mir verlinkten Kapitel nachlesen kannst.

              Das sind leider Firmendaten die in nicht ohne weiteres nach außen geben darf, deswegen übe ich mich hier lieber in Zurückhaltung, auch wenn ich mir bewusst bin, dass es das debugging leider schwieriger macht.

              1. Hallo,

                ich habe Deine Abfrage mit expliziter Join-Syntax umgeschrieben. Performance sollte das nicht bringen (das war mal), ich finde sie nur wesentlich lesbarer.

                Da mache ich eher die gegenteilige Erfahrung, komme mit der Nicht-Join-Schreibweise besser zurecht. Wenn es keine Performance bringt würde ich das gerne so lassen.

                Du findest es also einfacher und verständlicher, zwei Dinge zu mischen, die wenig miteinander zu tun haben. Du findest es einfacher und verständlicher, bei INNER JOINs eine andere Schreibweise als bei OUTER JOINs zu verwenden? Vielleicht verwendest Du ja überhaupt keine OUTER JOINs.

                Ich finde eine einheitliche Schreibweise viel angenehmer. Ich sehe sofort, über welche Bedingungen Tabellen miteinander verknüpft sind und welche Bedingungen die Gesamtergebnismenge einschränken.

                Das sind leider Firmendaten die in nicht ohne weiteres nach außen geben darf, deswegen übe ich mich hier lieber in Zurückhaltung, auch wenn ich mir bewusst bin, dass es das debugging leider schwieriger macht.

                ich schrieb Beispieldaten. Ich schrieb nicht "Echtdaten".
                Einfach Daten, unter denen man sich etwas vorstellen kann. Nein, das sind nicht foo, bar und baz.

                Freundliche Grüße

                Vinzenz