Ankündigung

Einklappen
Keine Ankündigung bisher.

PDO count(*) Tabelle ist langsam

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • PDO count(*) Tabelle ist langsam

    Hallo zusammen

    Ich habe endeckt, dass ein Count-Abfrage sehr langsam ist und zwar:

    Statement:
    "SELECT count(*) FROM shop_products a LEFT JOIN shop_products_lg l on a.id = l.product_id WHERE l.language_id = :language_id"

    Diese Abfrage benötigt ca. 300ms ist denn dies normal? Ich habe nur 3000 Produkte.

    Ich habe schon etliches ausprobiert wie indexs. Lieder aber alles ohne Verbesserung.

    Für einen Tip wäre ich sehr dankbar.

  • #2
    Zitat von strub Beitrag anzeigen
    Hallo zusammen

    Ich habe endeckt, dass ein Count-Abfrage sehr langsam ist und zwar:

    Statement:
    "SELECT count(*) FROM shop_products a LEFT JOIN shop_products_lg l on a.id = l.product_id WHERE l.language_id = :language_id"

    Diese Abfrage benötigt ca. 300ms ist denn dies normal? Ich habe nur 3000 Produkte.

    Ich habe schon etliches ausprobiert wie indexs. Lieder aber alles ohne Verbesserung.

    Für einen Tip wäre ich sehr dankbar.
    300 ms = 0,3 s - "Meine Sorgen möcht' ich haben!"

    Kommentar


    • #3
      Ich kenne die Antwortzeiten nicht, die für Dich normal sind.
      Deine 3000 Produkte werden in der Abfrage allerdings nicht allein abgefragt, sondern mit einer nicht näher beschriebenen Tabelle gejoined und anschließend gefiltert. Mangels Detailangaben kann man nicht mal sagen, ob der join korrekt ist.
      Ein fehlerhafter join kann zu mehr Datensätzen führen, als in der Ausgangstabelle (natürlich auch zu weniger).
      Auch wenn das Ergebnis halbwegs plausibel ist, könnte der Join bedeuten, das Millionen von Daten abgeglichen werden müssen.

      Kommentar


      • #4
        Zitat von strub Beitrag anzeigen

        Für einen Tip wäre ich sehr dankbar.
        was sagt das EXPLAIN ANALYSE dazu?
        PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

        Kommentar


        • #5
          "Meine Sorgen möcht' ich haben!"
          Alf2016 Was willst du uns sagen?
          Hast du eine Lösung anzubieten?
          Wenn nein, dann halte dich aus den Diskussionen fern.

          Kommentar


          • #6
            Danke euch allen für die Hilfe.

            Die Analyze sagt folgendes:
            id
            1 SIMPLE a index PRIMARY,id id 8 NULL 2455 2620.00 100.00 100.00 Using index
            1 SIMPLE l eq_ref PRIMARY PRIMARY 12 tablename.a.id,const 1 1.00 100.00 100.00 Using index

            Hintergrundinfo:
            Für meine Suchfunktion wird eben ein Count benötigt für die Pagnation und für weitere Infos. Die Suchfunktion hat eben auch noch andere Inhalte wie Artikel, Downloads, etc. welche man durchsuchen kann.
            Momentan benötigt die Suche ca. 1,5 Sekunden für alle Inhalte, dies eben wegen den Counts. Dieser macht aber 80% aus.

            Kommentar


            • #7
              Nun ja. Da über Deine Tabellen nur sehr wenig bekannt ist, habe ich diese wie folgt erstell;

              Code:
              test=*# create table shop_products(id int primary key, name text);
              CREATE TABLE
              test=*# create table shop_products_lg (product_id int references shop_products, language_id int);
              CREATE TABLE
              Diese habe ich dann mit 100.000 bzw. 10.000.000 Rows befüllt, damit man wenigstens etwas zum messen hat:

              Code:
              test=*# insert into shop_products select s, 'prod '||s::text from generate_series(1,100000) s;
              INSERT 0 100000
              
              test=*# insert into shop_products_lg select random()*99998 + 1, random()*10000000 from generate_series(1,10000000) s;
              INSERT 0 10000000
              und Indexe erstell:

              Code:
              test=*# create index idx_prod_id on shop_products_lg(product_id);
              CREATE INDEX
              test=*# create index idx_language on shop_products_lg(language_id);
              CREATE INDEX
              Deine Abfrage braucht mit diesen Datenmengen nun 0.073 ms:

              Code:
              test=# explain analyse SELECT count(*) FROM shop_products a LEFT JOIN shop_products_lg l on a.id = l.product_id WHERE l.language_id = 4711;
                                                                                QUERY PLAN                                                                  
              ----------------------------------------------------------------------------------------------------------------------------------------------
               Aggregate  (cost=21.10..21.11 rows=1 width=8) (actual time=0.020..0.020 rows=1 loops=1)
                 ->  Nested Loop  (cost=0.73..21.09 rows=2 width=0) (actual time=0.014..0.014 rows=0 loops=1)
                       ->  Index Scan using idx_language on shop_products_lg l  (cost=0.43..12.47 rows=2 width=4) (actual time=0.013..0.013 rows=0 loops=1)
                             Index Cond: (language_id = 4711)
                       ->  Index Only Scan using shop_products_pkey on shop_products a  (cost=0.29..4.31 rows=1 width=4) (never executed)
                             Index Cond: (id = l.product_id)
                             Heap Fetches: 0
               Planning Time: 1.013 ms
               Execution Time: 0.073 ms
              (9 rows)
              Deine 300ms sind also wirklich sehr lahm.
              PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

              Kommentar


              • #8
                Hey Akretschmer danke Dir vielmal für deinen Test, dass bestätigt ja meine Vermutung.

                Doch egal was ich mache, ich kriege immer dasselbe Resultat.

                Liegt wohl daran dass du Postgre verwendest,

                Kommentar


                • #9
                  Tja, da wäre also ein Ansatzpunkt - DB System wechseln ... ein weiterer wäre dann Optimierung deiner Umgebung - wenn du darauf Zugriff hast, spendiere dem DB-Server mehr Speicher, dafür sind die immer sehr dankbar
                  Die Abfrage selbst macht laut Explain schon das schnellste - nämlich Filterung per Index - evtl hilft dir ein weiterer Index auf language_id minimal weiter
                  "Irren ist männlich", sprach der Igel und stieg von der Drahtbürste [IMG]http://www.php.de/core/images/smilies/icon_lol.gif[/IMG]

                  Kommentar


                  • #10
                    An der DB liegt es sicherlich nicht.

                    Haben deine Tabellen evtl unterschiedliche Zeichenkodierungen?
                    Stimmen die Datentypen?
                    Verwendest du als Engine Inno-DB?

                    Stell doch mal die Struktur ohne Daten hier rein.
                    Bei deiner Explain Ausgabe fehlen die Überschriften.

                    Kommentar


                    • #11
                      Zitat von strub Beitrag anzeigen
                      Diese Abfrage benötigt ca. 300ms ist denn dies normal?
                      Mit dem von dir geposteten Explain? Das Explain sagt der Query ist i.O. Die Abfrage wird komplett über die zwei Indizies ausgeführt. Das passt vorne und hinten nicht mit der Zeit.

                      Mess die Ausführungszeit über die Datenbank:

                      SET profiling = 1;
                      SELECT COUNT(*) FROM ...;
                      SHOW PROFILE;

                      Über die Konsole ausführen oder in einem Verwaltungstool. Wenn du phpmyadmin hast, gibts das auch direkt als Option (Checkbox Messen).

                      Kommentar


                      • #12
                        Hey danke nochmals. Habe mal erc's Tip angewendet und dies ergibt erfreuliches:
                        starting 0.000023
                        checking permissions 0.000007
                        Opening tables 0.000004
                        After opening tables 0.000006
                        init 0.000009
                        optimizing 0.000009
                        executing 0.000010
                        end 0.000005
                        query end 0.000007
                        closing tables 0.000005
                        freeing items 0.000006
                        updating status 0.000030
                        cleaning up 0.000006
                        Dann muss das Problem ja woanders liegen.

                        Für die Zeitzmessung benutze ich folgenden Code:
                        PHP-Code:
                        $sql "SELECT count(*) FROM shop_products a LEFT JOIN shop_products_lg l on a.id = l.product_id WHERE l.language_id = :language_id";
                        $result $pdo->prepare($sql);
                        $start microtime(true);
                        $result->execute([':language_id' => 1]);
                        $end microtime(true);
                        $result->fetch(\PDO::FETCH_NUM);
                        echo 
                        "This query took " . ($end $start); 
                        Dies ergibt bei mir im Schnitt: 0.3 - 0.9. Sehr merkwürdig.

                        Kommentar


                        • #13
                          Das passt schon besser ins Bild.

                          Läuft PHP und die Datenbank auf getrennten Hosts? Vielleicht mit DSL Verbindung dazwischen? (wobei 300ms auch schon lange dafür wären)

                          PS: Was mir grade noch auffält. Der LEFT JOIN in dem Query ist falsch. Wenn das ein LEFT JOIN sein soll, muss die Bedingung von language_id in die ON Klausel. Ansonsten ist das ein INNER JOIN. (Von der Performance ist das hier unrelevant)

                          Kommentar


                          • #14
                            Hast du eine VM laufen?
                            Wie sieht es mit den Zeichenkodierungen aus, PDO zu DB müssen gleich sein.

                            Kommentar


                            • #15
                              Wieso denn ein Inner Join? Ich möchte ja alle Daten von den Produkten haben, auch wenn da keine Sprachverknüpfungen bestehen. Dann muss ich doch einen Left Join machen oder?

                              Ja ich habe Xampp. Bin aber gerade bei der Arbeit, muss am Abend schauen. Danke schonmal.

                              Kommentar

                              Lädt...
                              X