2016-10-11 1 views
0

Ich habe eine Abfrage, die Website-Besuchsprotokolle aus einer Tabelle ruft. Ich schließe mich dann zwei weiteren Tabellen an, um alle Benutzerinformationen zu erhalten. An dieser Stelle ist die Abfrage in Ordnung.MySQL (PDO) Langsame Unterabfrage

Langsame Abfrage: Ich muss dann eine Unterabfrage verwenden, um die Besuchsprotokolle ab einem bestimmten Datum basierend auf einer Bedingung zu erhalten. Es ist diese Unterabfrage, die bewirkt, dass die gesamte Abfrage praktisch zum Stillstand kommt. Nach 30-40 Sekunden wird die Abfrage beendet.


Tabellen:

  • Die Tabellen sind InnoDB (zu MyISAM Wechsel machte keinen Unterschied zu Performance).
  • Tabelle 1 hat fast 1 m Datensätze. Tabelle2 hat ungefähr 250K. Tabelle 3 hat ungefähr 100K. Table4 hat ungefähr 500K.


Abfrage:

SELECT COUNT(*) AS visits , table1.userName, table2.userId, table2.col1, table2.col2, table2.col3, table2.col4, table3.col20 
    FROM table1 
    LEFT JOIN table2 ON table2.userName = table1.userName 
    LEFT JOIN table3 ON table3.col2 = table1.col2 
    WHERE table1.col1 = 'foo' 
    AND table1.Date > (
     SELECT max(a.VisitDate) FROM table4 a 
      WHERE a.userId = table2.userId AND a.col1 = 'bar' 
     ) 
    GROUP BY table1.userName, table1.Date 

Ich habe nicht diese Datenstruktur aufbauen und haben keine Möglichkeit, es zu ändern. Ich analysiere diese Abfrage in eine grundlegende PDO Funktion.

+1

Joins sind effizienter als Subqueries – nogad

+0

Run auf diese Abfrage EXPLAIN und die Ergebnisse auf Ihre Fragen hinzufügen –

+0

auch, wäre es sinnvoll sein, zu wissen, was Indizes, die Sie für die Tabellen haben –

Antwort

0

Sie können versuchen, einen Innen mit (sichtbar auf subselect)

SELECT 
     COUNT(*) AS visits 
    , table1.userName 
    , table2.userId 
    , table2.col1 
    , table2.col2 
    , table2.col3 
    , table2.col4 
    , table3.col20 
FROM table1 
LEFT JOIN table2 ON table2.userName = table1.userName 
LEFT JOIN table3 ON table3.col2 = table1.col2 
INNER JOIN (
    SELECT max(a.VisitDate) as max_visit_date FROM table4 a 
     WHERE a.userId = table2.userId AND a.col1 = 'bar' 
    ) t on table1.Date > t.max_visit_date 
GROUP BY table1.userName, table1.Date;