Performanceproblem mit DB Abfrage

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

  • #16
    Hi,

    ich würde ja erstmal alle Theta-Style-Joins in ANSI-Style-Joins umwandeln. Wenn das außer besserer Lesbarkeit auch performancemäßig was bringen sollte, melde dich mal bitte hier.

    Mich würde eigentlich auch interessieren, ob dann das Explain anders aussieht.

    Gruß,

    Amica
    [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
    Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
    Super, danke!
    [/COLOR]

    Kommentar


    • #17
      Also die vorher genannte Abfrage war deshalb so schnell weil sie nur ein Ergebniss geliefert hat.
      Ich hab da leider was übersehn. :-(

      Solangsam resigniere ich.

      Hab die Abfrage mal umgebaut. Liegt aber noch immer bei 0.15-0.2 sek.
      Das ist bei "nur" 20.000 Datensätzen und mehreren Usern auf der Seite eine ziemlich unangemessene DB Last wie ich finde.

      Ich will nich unverschämt sein, in der Not greift man zu vielen mitteln :-)

      Aber vielleicht macht sich ja einer, wenn er ein wenig Zeit übrig hat, mal die Mühe und testet das selber mal.
      Meine Nerven liegen blank.....diesbezüglich.

      Ich hab das ganze Forum und google durchforstet. Es finden sich auch viele Infos. Aber es bringt mich leider nix weiter.

      Naja jedenfalls danke für die Mühe! Ich poste einfach mal die notwendigen Daten. Vielleicht sieht einer was.
      Es geht wirklich nur noch um diese blöde Abfrage.

      Code:
      SELECT COUNT( *  ) AS total
      
      FROM
      
      products p
      
      LEFT JOIN products_to_categories p2c ON p.products_id = p2c.products_id
      
      AND p2c.categories_id = '52'
      AND p.section_id IN('0', '13')
      AND p.products_status = '1'
      
      LEFT JOIN products_description pd ON p2c.products_id = pd.products_id
      
      AND pd.language_id = '2'
      Die Tabellen dazu:

      Code:
      CREATE TABLE IF NOT EXISTS `products` (
        `products_id` int(11) NOT NULL AUTO_INCREMENT,
        `products_quantity` int(4) NOT NULL,
        `products_model` varchar(12) DEFAULT NULL,
        `products_image` varchar(64) DEFAULT NULL,
        `products_price` decimal(15,4) NOT NULL,
        `products_date_added` datetime NOT NULL,
        `products_last_modified` datetime DEFAULT NULL,
        `products_date_available` datetime DEFAULT NULL,
        `products_weight` decimal(5,2) NOT NULL,
        `products_status` tinyint(1) NOT NULL,
        `products_tax_class_id` int(11) NOT NULL,
        `manufacturers_id` int(11) DEFAULT NULL,
        `products_ordered` int(11) NOT NULL DEFAULT '0',
        `section_id` int(11) NOT NULL DEFAULT '0',
        `ppp_id` int(11) NOT NULL,
        `grundpreis_menge` varchar(50) NOT NULL,
        `grundpreis_id` int(11) NOT NULL,
        `grundpreis` decimal(15,4) NOT NULL,
        `lieferstatus_id` int(11) NOT NULL,
        `bundle_id` int(11) NOT NULL,
        `products_index` int(1) DEFAULT NULL,
        `products_download` int(1) DEFAULT NULL,
        `products_download_count` varchar(50) DEFAULT NULL,
        `products_download_datei` varchar(100) NOT NULL,
        `products_download_maxdays` varchar(10) NOT NULL,
        `customers_groups_price_22` decimal(15,4) NOT NULL DEFAULT '0.0000',
        `customers_groups_price_23` decimal(15,4) NOT NULL DEFAULT '0.0000',
        PRIMARY KEY (`products_id`),
        KEY `idx_products_model` (`products_model`),
        KEY `idx_products_date_added` (`products_date_added`)
      ) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=19988 ;
      
      
      CREATE TABLE IF NOT EXISTS `products_description` (
        `products_id` int(11) NOT NULL AUTO_INCREMENT,
        `language_id` int(11) NOT NULL DEFAULT '1',
        `products_name` varchar(64) NOT NULL,
        `products_description` text,
        `products_url` varchar(255) DEFAULT NULL,
        `products_viewed` int(5) DEFAULT '0',
        PRIMARY KEY (`products_id`,`language_id`),
        KEY `products_name` (`products_name`),
        KEY `pid` (`products_id`),
        KEY `lid` (`language_id`)
      ) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=19988 ;
      
      
      CREATE TABLE IF NOT EXISTS `products_to_categories` (
        `products_id` int(11) NOT NULL,
        `categories_id` int(11) NOT NULL,
        PRIMARY KEY (`products_id`),
        KEY `pid+cid` (`products_id`,`categories_id`)
      ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
      Das sagt EXPLAIN:

      Code:
      1 SIMPLE p ALL     [I]NULL[/I]     [I]NULL[/I]     [I]NULL[/I]     [I]NULL[/I] 19966                          
      
      1 SIMPLE p2c eq_ref PRIMARY,pid+cid PRIMARY 4 oscommerce2.p.products_id 1 
      
      1 SIMPLE pd eq_ref PRIMARY,pid,lid PRIMARY 8 oscommerce2.p2c.products_id,const 1 Using index
      Zum Verständnis:

      Tabelle products enthält Produkte.

      Tabelle products_to_categories enthält die zum jeweiligen Produkt gehörende Kategorie.

      Tabelle products_description enthält hauptsächlich Produktnamen und Beschreibung (mehrsprachig).
      Die Produkt ID kommt jeweils 2x vor....dannach die dazugehörige Sprach ID 1 => Deutsch 2 => Englisch. Deshalb auch der mehrspaltige PRIMARY. Aber an dem liegts nich, hab ich getestet.

      Wie bereits gesagt ich würde mich sehr freuen wenn ich eine Erklärung für den langsamen Abruf bekommen könnte :-)

      Viele grüße und ein schönes WE!
      Zuletzt geändert von xtramen; 19.03.2010, 18:25.

      Kommentar


      • #18
        Wahrscheinlich kann man es dann halt nicht weiter optimieren. Eine solche Datenmenge wirst du ja aber nie uneingeschränkt abrufen wollen. Versuch mal 20000 Datensätze auf einer Webseite darzustellen, da crasht doch jeder Browser.
        [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
        Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
        Super, danke!
        [/COLOR]

        Kommentar


        • #19
          Ja da hast du sicherlich recht .
          Ich brauch halt das Ergebniss aller vorhandenen Datensätze für eine Blätterfunktion.

          Ich hätte halt nicht geglaubt das MySQL zum zählen unter Bedingungen sich so schwer tut.

          Nix für ungut, ich danke dir recht herzlich!

          Gruss

          Kommentar


          • #20
            Zitat von xtramen Beitrag anzeigen
            Ich brauch halt das Ergebniss aller vorhandenen Datensätze für eine Blätterfunktion.
            Wieso das? Gerade bei einer Blätterfunktion kommt man doch prima mit LIMIT zurecht und evtl. noch SQL_CALC_FOUND_ROWS, damit man die Gesamtanzahl hat und sagen kann "Seite k von n".
            [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
            Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
            Super, danke!
            [/COLOR]

            Kommentar


            • #21
              Moin

              Oha! DIese Funktion kannte ich nicht.
              LIMIT ist klar, dies benutze ich auch beim Navigieren.

              Mir ging es darum die Gesamtzahl der Artikel unter Berücksichtigung der Bedingungen zu bekommen.

              Das es so einfach ist hätt ich nich gedacht.
              Da hätt ich mir so einiges ersparen können. :-)

              Danke, danke, danke!

              Gruss
              Zuletzt geändert von xtramen; 20.03.2010, 08:51.

              Kommentar


              • #22
                Zitat von xtramen Beitrag anzeigen
                Da hätt ich mir so einiges ersparen können. :-)
                Tja, immer schon dazuschreiben, was man eigentlich vorhat. Wenn das Stichwort Blättern schon eher gefallen wäre, hätte ich dir das auch schon eher sagen können
                [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
                Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
                Super, danke!
                [/COLOR]

                Kommentar


                • #23
                  aaaaalso

                  Auf die Gefahr hin das ich anfange zu nerven.....sorry schonmal vorweg.
                  Aber ich bin perfektionist!

                  Auch wenn die Abfrage jetzt ein wenig schneller ist (mit was ich Leben könnte, wenn es nich besser geht) komm ich nich dahinter was die Funktion effektiv bringen soll.

                  Denn das LIMIT wird vollkommen ignoriert.

                  Und wie ich verstanden und gelesen habe soll ja grad das der Vorteil der Funktion gegenüber COUNT() sein.

                  SQL_CALC_FOUND_ROWS oder: Wie man effektiv Bltternavigationen umsetzt Beitrag PHP Performance

                  Mit SQL_CALC_FOUND_ROWS (0.1 sek) :

                  Code:
                  1 SIMPLE p index PRIMARY,test test 12     [I]NULL[/I] 19966 Using where; Using index                    
                  1 SIMPLE p2c eq_ref PRIMARY,pid PRIMARY 8 oscommerce2.p.products_id,const 1 Using index                    
                  1 SIMPLE pd eq_ref PRIMARY,pid,lid PRIMARY 8 oscommerce2.p.products_id,const 1 Using index
                  und ohne (selbe Abfrage mit select * )(0.0011 sek):

                  Code:
                  1 SIMPLE p index PRIMARY,test PRIMARY 4     [I]NULL[/I] 20 Using where                    
                  1 SIMPLE p2c eq_ref PRIMARY,pid PRIMARY 8 oscommerce2.p.products_id,const 1 Using index                    
                  1 SIMPLE pd eq_ref PRIMARY,pid,lid PRIMARY 8 oscommerce2.p.products_id,const 1
                  Wie man sieht wird das LIMIT wird halt ignoriert und auch andere Indizes verwendet. Deshalb werden dann knapp 20.000 rows produziert.

                  Code:
                   SELECT SQL_CALC_FOUND_ROWS p.products_id
                  
                  FROM products_description pd
                  
                  INNER JOIN products_to_categories p2c ON pd.products_id = p2c.products_id
                  INNER JOIN products p ON pd.products_id = p.products_id AND pd.language_id = '2'
                  
                  
                  
                  WHERE p2c.categories_id = '52'
                  
                  AND p.products_status = '1'
                  AND (p.section_id = '0' || p.section_id = '13')
                  
                  ORDER BY p.products_id LIMIT 0,20
                  Mach ich da was falsch oder warum is das so?

                  Gruss
                  Zuletzt geändert von xtramen; 20.03.2010, 12:54.

                  Kommentar


                  • #24
                    Was hast du denn als Limit angegeben?
                    [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
                    Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
                    Super, danke!
                    [/COLOR]

                    Kommentar


                    • #25
                      Zitat von xtramen Beitrag anzeigen
                      Auch wenn die Abfrage jetzt ein wenig schneller ist (mit was ich Leben könnte, wenn es nich besser geht) komm ich nich dahinter was die Funktion effektiv bringen soll.

                      Denn das LIMIT wird vollkommen ignoriert.
                      Works as designed.

                      http://dev.mysql.com/doc/refman/5.1/en/select.html:
                      SQL_CALC_FOUND_ROWS tells MySQL to calculate how many rows there would be in the result set, disregarding any LIMIT clause.
                      http://dev.mysql.com/doc/refman/5.1/...ion_found-rows:
                      A SELECT statement may include a LIMIT clause to restrict the number of rows the server returns to the client. In some cases, it is desirable to know how many rows the statement would have returned without the LIMIT, but without running the statement again. To obtain this row count, include a SQL_CALC_FOUND_ROWS option in the SELECT statement, and then invoke FOUND_ROWS() afterward

                      Du scheinst nicht verstanden zu haben, wofür diese Funktionalität gedacht ist.
                      I don't believe in rebirth. Actually, I never did in my whole lives.

                      Kommentar


                      • #26
                        @ AmicaNoctis: habs auf 20 Datensätze limitiert. Sorry werde nächstes mal den COde auf 100 Zeichen umbrechen.

                        @ Wahsaga:

                        Works as designed.
                        Ich wüsste nicht wie ich die Abfrage besser designen kann.
                        Hab schon recht viel rumprobiert. Bin leider kein Profi was DB Design angeht.
                        Bis zu diesem Problem hast völlig gereicht.

                        Trotz MySQL Manual versteh ich nun trotzdem den Vorteil gegenüber COUNT() nicht ganz.

                        Ich habs so verstanden das man die Datensätze limitieren kann, was ja mehr Performance bringt, aber trotzdem an die Gesamtanzahl der Datensätze kommt.
                        Nun wird aber bei mir wie gesagt das LIMIT ignoriert.

                        Sorry vielleicht sitz ich aufm Schlauch....aber die DOKUS zu MySQL sind einfach sehr trocken um sie als nichtprofi auf Anhieb zu verstehn.

                        Gruss

                        EDIT: Ok ich habs nun kapiert! :-) Danke.
                        Zuletzt geändert von xtramen; 20.03.2010, 13:43.

                        Kommentar

                        Lädt...
                        X