LEFT JOIN ohne JOIN

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

  • LEFT JOIN ohne JOIN

    Hi,

    ich komme wieder mal mit einem Problem zu euch was ich alleine nicht lösen kann.

    Situation: 2 Tabellen, eine Tabelle schließt die andere Tabelle aus.

    Code:
    SELECT 
    t1.wert 
    
    FROM 
    tab1 t1
    
    LEFT JOIN tab2 t2
    ON t2.wert = t1.wert
    
    WHERE 
    t2.wert IS NULL
    Da nun aber leider diese Art Query auf unserem NDB Cluster ca 600ms benötigt sind wir dazu über gegangen das ganze in "alter" Notation zu schreiben:
    Code:
    SELECT 
    t1.wert 
    
    FROM tab1 t1, tab2 t2
    
    WHERE 
    t1.wert = t2.wert
    Was komischerweise schneller ist... zumindest bei normalen joins.

    Nun meine Frage: Wie kann ich in der "alten" Noatation einen LEFT JOIN abbilden?

    Dank euch schonmal

  • #2
    Hallo,

    die "alte" Notation ist ein Cross Join (der durch die Where-Klausel sowas wie ein Inner Join wird) und damit etwas ganz anderes als ein Left (Outer) Join ist. Es gibt also keine sinnvolle Möglichkeit, einen Left Join mit einem Cross Join nachzubauen (es würde mit Union und einer auf Null-Werte angepassten Where-Klausel gehen, was aber noch unperformanter ist)

    Wenn auf dem System der Left Join deiner Meinung nach zu langsam ist, kannst du es ja mal mit einem Right Join probieren und die Tabellen andersrum referenzieren.

    Edit: hast du einen Index auf die Spalte wert? Wenn nicht, ist das der Grund dafür, dass es so langsam ist.

    Gruß,

    Amica
    Zuletzt geändert von AmicaNoctis; 18.11.2009, 16:23.
    [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


    • #3
      Zitat von prego Beitrag anzeigen
      Hi,

      ich komme wieder mal mit einem Problem zu euch was ich alleine nicht lösen kann.

      Situation: 2 Tabellen, eine Tabelle schließt die andere Tabelle aus.

      Code:
      SELECT 
      t1.wert 
      
      FROM 
      tab1 t1
      
      LEFT JOIN tab2 t2
      ON t2.wert = t1.wert
      
      WHERE 
      t2.wert IS NULL
      Da nun aber leider diese Art Query auf unserem NDB Cluster ca 600ms benötigt sind wir dazu über gegangen das ganze in "alter" Notation zu schreiben:
      Code:
      SELECT 
      t1.wert 
      
      FROM tab1 t1, tab2 t2
      
      WHERE 
      t1.wert = t2.wert
      Was komischerweise schneller ist... zumindest bei normalen joins.

      Nun meine Frage: Wie kann ich in der "alten" Noatation einen LEFT JOIN abbilden?

      Dank euch schonmal
      Das erste ist ein LEFT JOIN, das zweite ein INNER JOIN (mit fürchterlicher Theta-Style Schreibweise). INNER JOINs sind gewöhnlich schneller als LEFT JOINs, hat also nix mit deiner Schreibweise zu tun.

      Kommentar


      • #4
        Ich dachte es mir fast das es nicht funktioniert in dieser Schreibweise. Dummes NDB

        Indizes sind gesetzt und werden laut explain auch benutzt.

        Ich mach es jetzt so das ich erst alle Werte aus tab1 selecte und danach in php die Werte aus tab2 aus dem Ergebnisarray entferne. Danach noch ein array_slice zum blättern da ich ja limit nicht verwenden kann.

        Macht das ganze in 120ms, im Gegensatz zu ca. 700ms des left joins. SQL_CACHE_SELECT hilft leider nicht da es sich um eine Statistiktabelle handelt wie recht häuft einen Insert bekommt.

        Danke euch trotzdem allen.

        Kommentar


        • #5
          Zitat von prego Beitrag anzeigen
          Ich dachte es mir fast das es nicht funktioniert in dieser Schreibweise. Dummes NDB

          Indizes sind gesetzt und werden laut explain auch benutzt.

          Ich mach es jetzt so das ich erst alle Werte aus tab1 selecte und danach in php die Werte aus tab2 aus dem Ergebnisarray entferne. Danach noch ein array_slice zum blättern da ich ja limit nicht verwenden kann.

          Macht das ganze in 120ms, im Gegensatz zu ca. 700ms des left joins. SQL_CACHE_SELECT hilft leider nicht da es sich um eine Statistiktabelle handelt wie recht häuft einen Insert bekommt.

          Danke euch trotzdem allen.
          Dann schau dir doch mit EXPLAIN an, wo der Flaschenhals ist.

          MySQL :: MySQL 5.1 Referenzhandbuch :: 7.2.1 EXPLAIN-Syntax (Informationen über ein SELECT erhalten)

          Kommentar


          • #6
            Code:
            EXPLAIN SELECT SQL_CALC_FOUND_ROWS 
            
            t1.wert
            
            FROM 
            tab1 t1 
            
            LEFT JOIN tab2 t 2
            ON t1.wert = t2.wert
            
            WHERE 
            DATE_SUB(curdate(), interval 30 day) < t1.day AND 
            t2.wert IS NULL 
            
            GROUP BY t1.wert
            
            ORDER BY t1.wert 
            
            LIMIT 0,150
            ergibt:

            (sorry fürs scrollen)
            Code:
            +----+-------------+-------+--------+---------------+---------+---------+----------------+------+--------------------------------------------------------------------+
            | id | select_type | table | type   | possible_keys | key     | key_len | ref            | rows | Extra                                                              |
            +----+-------------+-------+--------+---------------+---------+---------+----------------+------+--------------------------------------------------------------------+
            |  1 | SIMPLE      | t1    | range  | day           | day     | 3       | NULL           |   10 | Using where with pushed condition; Using temporary; Using filesort |
            |  1 | SIMPLE      | t2    | eq_ref | PRIMARY       | PRIMARY | 130     | t2.wert        |    1 | Using where; Not exists                                            |
            +----+-------------+-------+--------+---------------+---------+---------+----------------+------+--------------------------------------------------------------------+

            Hmm, mit pushed condition kann ich leider nichts anfangen. t1.day hat einen eigenstehenden index. Der PrimaryKey setzt sich aus drei Spalten zusammen von denen day auch einen ist. In t2 ist wert der Primärschlüssel. Sonst keine.

            Kommentar


            • #7
              dreh mal die Berechnung um, die Spalte Berechnen, nicht die Konstante curdate

              hier => DATE_SUB(curdate(), interval 30 day) < t1.day

              außerdem ist der Index nicht richtig korrekt, wenn er filesort und temporary nutzt
              TBT

              Die zwei wichtigsten Regeln für eine berufliche Karriere:
              1. Verrate niemals alles was du weißt!


              PHP 2 AllPatrizier II Browsergame

              Kommentar


              • #8
                Zitat von TBT Beitrag anzeigen
                dreh mal die Berechnung um, die Spalte Berechnen, nicht die Konstante curdate
                Warum? Erstens ist curdate keine Konstante, sondern eine Funktion und zweitens kann das DBMS diese Berechnung cachen, was es nicht könnte, wenn man die Spalte berechnen würde. Finde die Variante des TO daher auch sinnvoll. Wenn du das anders siehst, wäre ich an Belegen dafür interessiert.
                [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


                • #9
                  Zitat von AmicaNoctis Beitrag anzeigen
                  Warum? Erstens ist curdate keine Konstante, sondern eine Funktion und zweitens kann das DBMS diese Berechnung cachen, was es nicht könnte, wenn man die Spalte berechnen würde.
                  Der MySQL Query Cache greift nicht bei variablen Werten wie NOW(), CURRENT_DATE(), usw.

                  Deshalb sollte man Datum und Zeit wenn möglich als String übergeben um die beste Leistung zu erzielen.

                  Kommentar


                  • #10
                    Ok, stimmt, trotzdem gehört meiner Meinung nach die Berechnung auf die Seite der Nichtspalte, sofern das möglich ist. Also z. B.

                    Code:
                    set @date = curdate();
                    select * from t1
                    where @date - interval 30 day < t1.day;
                    Ok, das Beispiel hinkt etwas, weil man die Berechnung dann ja gleich mit in die Zuweisung übernehmen könnte.
                    [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


                    • #11
                      Hi,

                      das Datum übergebe ich mittlerweile komplett als String: '2009-10-19' < t1.day - fällt also aus


                      Zitat von TBT Beitrag anzeigen
                      außerdem ist der Index nicht richtig korrekt, wenn er filesort und temporary nutzt
                      Das hier würde mich interessieren.

                      Es wird t1.wert gegrouped und geordered, t1.wert ist teil des primary key's. Aber, explain beschwert sicht ja garnicht über t1.wert sondern über t1.day und selbst da benutzt er den vorhanden Index.

                      t2.wert ist einzige Spalte im primary key von t2.

                      Wo fehlt denn der Index oder wo ist er denn falsch? Ich steig noch nicht ganz durch.

                      Kommentar

                      Lädt...
                      X