Ankündigung

Einklappen
Keine Ankündigung bisher.

Effiziente Datenbankabfragen bei Warenkorbobjekt

Einklappen

Neue Werbung 2019

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

  • Effiziente Datenbankabfragen bei Warenkorbobjekt

    Hallo zusammen,

    meine Warenkorb-Klasse hat u.a. folgende zwei Methoden:
    PHP-Code:
    public function add($product_id$quantity) {
        
    $product = new Product($product_id);
        
    $product->setInfo();    
        try {                        
            if (
    $product->validateProduct()) {                
                if (isset(
    $quantity) && intval($quantity) != 0) {
                    
    $quantity intval($quantity);    
                    
                    if (isset(
    $this->items[$product_id])) {
                        
    $this->items[$product_id]['quantity'] += $quantity;
                    }
                    else {
                        
    $this->items[$product_id]['quantity'] = $quantity;
                    }                    
                    
                    if (
    $this->items[$product_id]['quantity'] < $product->getMinSaleQty()) {
                        return 
    $this->items[$product_id]['quantity'] = $product->getMinSaleQty();
                    }
                    if (
    $this->items[$product_id]['quantity'] > $product->getMaxSaleQty()) {
                        return 
    $this->items[$product_id]['quantity'] = $product->getMaxSaleQty();
                    }
                
                }
                else {
                    throw new 
    Exception('Ungültige Mengenangabe.');
                }
            }
            else {
                throw new 
    Exception('Ungültiges Produkt.');
            }            
        }
        catch (
    Exception $e) {
            
    $_SESSION['error'] = $e->getMessage();
        }        
    }
     
    public function 
    update($product_id$quantity) {
        
    $product = new Product($product_id);    
        
    $product->setInfo();
        if (
    array_key_exists($product_id$this->getItems())) {
            
    $this->items[$product_id]['quantity'] += $quantity;
            if (
    $this->items[$product_id]['quantity'] < $product->getMinSaleQty()) {
                return 
    $this->items[$product_id]['quantity'] = $product->getMinSaleQty();
            }
            if (
    $this->items[$product_id]['quantity'] > $product->getMaxSaleQty()) {
                return 
    $this->items[$product_id]['quantity'] = $product->getMaxSaleQty();
            }
        }            

    Damit mir die Eigenschaften wie MinSaleQty, MaxSaleQty oder die Methode validateProduct() Werte zurückliefern, setze ich zunächst mit $product->setInfo() einen Query ab, welcher mir die entsprechenden Daten zum Produkt aus der Datenbank holt und anschließend in meiner Produkt-Klasse einem Array zuweist. Der Query sieht wie folgt aus:

    PHP-Code:
    protected function _queryInfo() {
        
    $sql =     'SELECT p.product_id, p.price, p.weight, p.image_src,
                        pd.name, pd.abstract, pd.description, pd.ingredients, 
                        ps.min_sale_qty, ps.max_sale_qty
                FROM product AS p
                    LEFT JOIN product_description AS pd 
                        ON pd.product_id = p.product_id
                    LEFT JOIN product_stock AS ps
                        ON ps.product_id = p.product_id
                WHERE p.product_id = :product_id
                AND pd.lang = :lang'
    ;    
        
    $db Database::getInstance()->getConnection(); 
        
    $pstmt $db->prepare($sql);
        
    $pstmt->bindParam(':lang'$GLOBALS['lang']);
        
    $pstmt->bindParam(':product_id'$this->productId);        
        
    $pstmt->execute();
        return 
    $pstmt->fetch(PDO::FETCH_ASSOC);

    Jetzt meine eigentliche Frage. Wäre besser, wenn ich einzelne Querys für jeden Eigenschaft / Methode erzeuge oder stattdessen die allumfassende Query beibehalte. Ehrlich gesagt habe ich keine Ahnung, was besser ist. Ein großer Query oder mehrere kleine Querys?

  • #2
    Ob jetzt ein einzelner großer oder mehrere kleine Abfragen besser sind, läßt sich nicht so ohne weiteres beantworten. Es hängt auch davon ab, ob bei dem großen Query viele Daten transportiert werden.

    Teste doch mal in der MySQL-Console:
    a) wie lang dauert das Ausführen des grossen Query
    b) wie lang dauert das Ausführen des kleinen Query * Häufigkeit der Abfrage
    c) wie sieht der EXPLAIN der jeweiligen Abfragen aus ( EXPLAIN SELECT ... )

    Falls es Fragen zum EXPLAIN gibt, bitte die Ausgabe als Bild oder gut formatiert hier zeigen.

    Soweit mal ein paar Ideen dazu.

    Grüße
    Thomas

    Kommentar


    • #3
      Erstmal vielen Dank für deine Antwort. Mit der MySQL-Console und EXPLAIN hatte ich bisher noch nichts am Hut ... Zeit wird's. Allerdings irritiert mich etwas an dem Ergebnis des EXPLAIN meiner großen Abfrage:

      PHP-Code:
      Array ( [id] => [select_type] => SIMPLE [table] => [type] => const [possible_keys] => PRIMARY [key] => PRIMARY [key_len] => [ref] => const [rows] => [Extra] => ) 
      Sollte bei [Extra] nicht etwa "using where" oder ähnliches stehen?

      Wie viele Daten bei dem großen Query transportiert werden, kann man ja meinem Query entnehmen. In diesem Fall 10 Felder. Im Falle meiner add() Methode benötige ich allerdings nur 3 davon. Einmal die product_id, um zu überprüfen ob das Produkt überhaupt existiert, und dazu noch die zwei Felder Min-/MaxSaleQty. Genau aus diesem Grund zweifele ich meinem universalen Query an.

      Was ich mir zusätzlich überlegt habe, ist, ob ich mir nicht über eine Transaction meine Abfrage zusammenbaue. Dann hätte ich in einer Transaction die von mir gewünschten Statements beisammen plus der Abhängigkeit (Existiert Produkt-ID nicht, müssen weitere Felder gar nicht erst abgefragt werden). Dazu müsste ich nur noch meine Tabellen auf InnoDB umstellen. Was ist davon zu halten?

      Kommentar


      • #4
        Das Ergebnis des Explain läßt sich so schwer lesen. Besser ist es das Ganze als sauber formatierte Tabelle auszugeben. Soweit ich sehe, ist aber an dem EXPLAIN-Ergebnis nichts zu meckern. Das in der Spalte "EXTRA" nichts steht, ist nicht schlimm, so eher gut.

        Da Du offensichtlich eher eine kleinere Datenmenge im "grossen" Query einliest, ist die große Abfrage wohl schneller als x kleine.

        Das Ganze in eine Transaktion zu packen ist sinnvoll, sofern Daten geändert (INSERT, UPDATE, DELETE) werden.

        Es spricht nichts gegen InnoDB.

        Grüße
        Thomas

        Kommentar


        • #5
          Hast du so arge performance Probleme bei dem Warenkorb? Kann ich mir nicht vorstellen. Du versuchst grade etwas zu optimieren was gar nicht optimiert werden muss!

          PS: ein großer Query ist in den meisten fällen schneller als mehrere kleine.

          Kommentar


          • #6
            Den try { ... } catch (...) { ... } - Block würde ich nicht in die Funktion packen, sonst hast du Probleme, die Fehlermeldungen aus der Funktion herauszubekommen, was man schon daran sieht, dass du die Meldung in eine Session-Variable ablegst.
            PHP-Code:
            try {
              
            $warenkorb = new Warenkorb();
              
              
            $warenkorb->hinzufuegen();
              
            $warenkorb->speichern();
            } catch (
            Exception $e) {
              echo 
            $e->getMessage();

            Außerdem kannst du innerhalb einer Funktion davon ausgehen, dass eine Variable, die du als Parameter deklariert hast, auch innerhalb der Funktion ansprechbar ist.
            Code:
            public function add($product_id, $quantity) {
            Ein
            Code:
            isset($quantity)
            wird daher überflüssig und du kannst
            Code:
            if (isset($quantity) && intval($quantity) != 0) {
              $quantity = intval($quantity);    
              // ...
            }
            besser in etwas wie
            Code:
            $quantity = intval($quantity);
            if ($quantity != 0) {
              // ...
            }
            ändern.
            [URL]http://hallophp.de[/URL]

            Kommentar


            • #7
              @ Asipak

              Vielen Dank für deine Anregungen. Ich werde es bei Gegebenheit einbauen. Jetzt muss ich erstmal für meine Prüfungen lernen ...

              @ erc

              Von Performance-Problemen spreche ich auch gar nicht. Die durchschnittliche Parse Time der Webseite liegt etwa bei < 0,02s (wobei die Parse-Time natürlich nicht alles ist. Die einzelnen Querys unter die Lupe zu nehmen wäre natürlich besser.) Dennoch erachte ich es als sinnvoll, schon im Vorfeld weitestgehend zu optimieren, um etwaige Performance-Probleme im Nachhinein zu vermeiden/verringern.

              Auch war ich mir nicht sicher, ob tatsächlich ein großer Query (bei dem ich viele Felder aus der Datenbank hole, aber nur ein paar davon in der Funktion benötige) besser ist als mehrere kleine Querys, die ich je nach Funktion absetze.

              Kommentar

              Lädt...
              X