j0Shi: Gechwindigkeitsproblem mit Subquery bei mySQL

Sers,

ich habe folgendes Problem:
in einem kleinen Shopsystem soll neben den Artikeldaten auch gleich die komplette Anzahl der vorhandenen Artikel in der übergeordneten Kategorie angezeigt werden. Also z.B:

Intel Core2Duo E8400 (Kategorie: CPUs, insgesamt 250 Artikel in dieser Kategorie)
Gigabyte Mainboard .... usw.

Da ich die Artikeldaten bisher in einer While-Schleife ausgewertet habe, habe ich in dieser Schleife zum Herausfinden der Artikelanzahl nochmal eine Abfrage geschrieben. Also count(*) WHERE cat = 237.

Da teilweise allerdings 500 Artikel auf einmal angezeigt werden hieß das bis vor kurzem noch, dass bis zu zusätzliche 500 SQL-Anfragen pro Pageview den Server belasteten. Um diesem Problem zu entgehen wollte ich alles in einer Abfrage abarbeiten. Die einzige Abfrage, die mir das dazu passende Ergebnis liefert ist:

  
SELECT *, cat AS subqcat, (  
  
SELECT COUNT( subqcat )  
FROM artikelliste  
WHERE cat = subqcat  
GROUP BY subqcat  
)  
FROM artikelliste  

Die Originalquery umfasst natürlich noch einiges mehr, so werden die Artikel z.B. auch mit anderen Tabellen verknüpft, in denen Kommentare und Preisentwicklung gespeichert wird.

Mit dieser Systematik braucht diese einfachste Anfrage für 10 Artikel 0.0719 sec, 50 0.2606 sec und 500 2,4 sec. Finde ich erstmal unzumutbar ;)
Da die eigentliche Query nochmals komplizierter ist dauert hier der Aufruf von 500 Artikeln über 20 Sekunden.
Zwar habe ich als Testsystem hier zu Hause nur einen Duron 1400 mit 512 MB aber selbst dafür ist es noch etwas lahm.

Die Frage ist, ob es evtl. noch andere Möglichkeiten gibt, dieses Problem zu lösen, oder ob ich mich doch mit den zusätzlichen Datenbankabfragen in der Schleife abfinden muss. Eine Indizierung von cat brachte keine Verbesserung.

lg
j0Shi

  1. 你好 j0Shi,

    SELECT *, cat AS subqcat, (

    SELECT COUNT( subqcat )
    FROM artikelliste
    WHERE cat = subqcat
    GROUP BY subqcat
    )
    FROM artikelliste

      
    So, wie du das machst, muss trotzdem für jede Reihe eine Query ausgeführt werden.  
      
    Ich würde daraus zwei Queries machen: eine, um die "normalen" Daten zu holen und eine, um das Zählen zu übernehmen. Etwa so:  
      
    ~~~sql
      
    SELECT *, cat AS subqcat, FROM artikelliste  
      
    -- erstelle eine Liste von subqcat  
      
    SELECT cat,COUNT(*)  
    FROM artikelliste  
    WHERE cat IN (liste, von, subqcat)  
    GROUP BY cat  
    
    

    Alternativ könnte man auch gucken, ob man nicht mit LEFT JOIN oder INNER JOIN etwas hinkriegt.

    Ich weiss nicht genau, inwieweit du die Daten überhaupt brauchst, aber man könnte man halt auch zusammenfassen, indem man die Subquery in das IN packt.

    再见,
     克里斯蒂安

    --
    Bauer sucht Frau! | Ich bin ja eigentlich kein Serien-Junkie…
    Treffen sich zwei Geraden. Sagt die eine: "Beim nächsten Mal gibst du einen aus."
    http://wwwtech.de/
    1. Erstmal danke für die Tips. Dass ich natürlich mit der Subquery das Problem der zusätzlichen Datenbankabfragen keineswegs löse ist mir nicht aufgefallen :)

      Mir ist noch eingefallen, dass man natürlich vorweg eine zweite Abfrage abschicken könnte:

        
      SELECT COUNT(cat)  
      FROM artikelliste  
      GROUP BY cat  
      
      

      Aber das meintest du ja oben auch?

      Das ganze dann in einen Array und mit array_search (PHP) in der Schleife den Wert heraussuchen. Ich habe zwar keinerlei Erfahrungen ob array_search generell schneller ist als ne vernünftige SQL-Query, aber die Anfrage oben dauert nur 0,015 secs und array_search wird kaum 20 secs dauern, zumal es ja soviele Kats nicht gibt :)

      lg
      j0Shi

      1. 你好 j0Shi,

        Mir ist noch eingefallen, dass man natürlich vorweg eine zweite Abfrage abschicken könnte:

        SELECT COUNT(cat)
        FROM artikelliste
        GROUP BY cat

        
        >   
        > Aber das meintest du ja oben auch?  
          
        Ja, so bzw. so ähnlich. Du brauchst noch die cat als Identifizierungsmerkmal dazu.  
          
        
        > Das ganze dann in einen Array und mit array\_search (PHP) in der Schleife den Wert heraussuchen. Ich habe zwar keinerlei Erfahrungen ob array\_search generell schneller ist als ne vernünftige SQL-Query, aber die Anfrage oben dauert nur 0,015 secs und array\_search wird kaum 20 secs dauern, zumal es ja soviele Kats nicht gibt :)  
          
        Aber array\_search ist doch gar nicht notwendig. Du baust einen assoziativen Array auf, bei dem cat der Schlüssen ist und count(cat) der Wert. So kannst du problemlos darauf zugreifen. Alternativ: ORDER BY cat. Und schon kannst du herausfinden, an welcher Stelle im Array die Anzahl steht.  
          
        再见,  
         克里斯蒂安  
        
        -- 
        [Bauer sucht Frau!](http://ck.kennt-wayne.de/bauer-sucht-frau) | [Ich bin ja eigentlich kein Serien-Junkie…](http://ck.kennt-wayne.de/ich-bin-ja-eigentlich-kein-serien-junkie)  
        Das Leben ist wie ein Kartenspiel: was dir gegeben wurde, ist vorbestimmt. Doch wie du damit spielst, ist deine Entscheidung.  
          
        <http://wwwtech.de/>