2013-09-25 8 views
5

I 2 Tabellen, die auf diese Struktur vereinfacht werden kann:mysql effizient verbinden von zwei Tabellen mit den gleichen zwei Tabellen

Tabelle 1:

+----+----------+---------------------+-------+ 
| id | descr_id |  date   | value | 
+----+----------+---------------------+-------+ 
| 1 |  1 | 2013-09-20 16:39:06 |  1 | 
+----+----------+---------------------+-------+ 
| 2 |  2 | 2013-09-20 16:44:06 |  1 | 
+----+----------+---------------------+-------+ 
| 3 |  3 | 2013-09-20 16:49:06 |  5 | 
+----+----------+---------------------+-------+ 
| 4 |  4 | 2013-09-20 16:44:06 | 894 | 
+----+----------+---------------------+-------+ 

Tabelle 2:

+----------+-------------+ 
| descr_id | description | 
+----------+-------------+ 
|  1 | abc   | 
+----------+-------------+ 
|  2 | abc   | 
+----------+-------------+ 
|  3 | abc   | 
+----------+-------------+ 
|  4 | DEF   | 
+----------+-------------+ 

Ich möchte die Beschreibung in Tabelle1, Filter nach Beschreibung, so dass ich nur Zeilen mit Beschreibung = abc, und filtern Sie "doppelte" Zeilen, wo zwei Zeilen Duplikate sind, wenn sie den gleichen Wert haben und ihre Daten sind innerhalb von 6 Meilen nuten voneinander. Meine gewünschte Ausgabetabelle ist unten (angenommen, abc ist der gewünschte Beschreibungsfilter).

+----+----------+---------------------+-------+-------------+ 
| id | descr_id |  date   | value | description | 
+----+----------+---------------------+-------+-------------+ 
| 1 |  1 | 2013-09-20 16:39:06 |  1 | abc   | 
+----+----------+---------------------+-------+-------------+ 
| 3 |  3 | 2013-09-20 16:49:06 |  5 | abc   | 
+----+----------+---------------------+-------+-------------+ 

Die Abfrage kam ich mit ist:

select * 
    from (
     select * 
      from table1 
      join table2 using(descr_id) 
     where label='abc' 
     ) t1 
    left join (
     select * 
      from table1 
      join table2 using(descr_id) 
     where label='abc' 
     ) t2 on(t1.date<t2.date and t1.date + interval 6 minute > t2.date) 
where t1.value=t2.value. 

Leider ist diese Abfrage dauert länger als eine Minute mit meinen Daten-Set zu laufen, und liefert keine Ergebnisse (obwohl ich glaube, es sollte die Ergebnisse sein). Gibt es eine effizientere Möglichkeit, diese Abfrage durchzuführen? Gibt es eine Möglichkeit, eine abgeleitete Tabelle zu benennen und später in derselben Abfrage zu referenzieren? Warum gibt meine Abfrage keine Ergebnisse zurück?

Vielen Dank im Voraus für Hilfe!

edit: Ich möchte die erste von mehreren Proben mit engen Zeitstempeln beibehalten.

Meine Tabelle1 hat 6,1 Millionen Zeilen, meine Tabelle2 hat 30K, was mir klar macht, dass Tabelle2 nur eine Zeile für die Beschreibung "abc" hätte. Das bedeutet, dass ich vorher nur nach descr_id fragen kann, dann benutze diese ID, um zu vermeiden, dass table2 in der großen Abfrage überhaupt mitwirkt, was es viel effizienter macht. Wenn jedoch meine Tabelle2 wie oben beschrieben eingerichtet wurde (was ein schlechter Datenbankentwurf wäre, gebe ich zu), was ist eine gute Möglichkeit, eine solche Abfrage durchzuführen?

+1

Hoffen Sie, die erste zu behalten mehrere Samples mit nahe beieinander liegenden Zeitstempeln, oder die letzten von ihnen, oder die Mittelung ihrer Zeitstempel, oder was? Welcher Zeitstempel sollte in der Ergebnismenge enthalten sein, um jeden Haufen Ihrer Proben dicht beieinander zu repräsentieren? –

+0

Nette Frage BTW +1 wie viele Datensätze haben die Tabellen? –

Antwort

1

Versuchen temporäre Tabellen erstellen und verbinden auf den temporären Tabellen:

CREATE TEMPORARY TABLE t1 AS (select * 
      FROM table1 
      JOIN table2 USING(descr_id) 
     WHERE label='abc') 

CREATE TEMPORARY TABLE t2 AS (select * 
      FROM table1 
      JOIN table2 USING(descr_id) 
     WHERE label='abc') 

SELECT * 
FROM t1 
LEFT JOIN t2 on(t1.date<t2.date and t1.date + interval 6 minute > t2.date) 
WHERE t1.value=t2.value 

Temporäre Tabellen werden automatisch bereinigt, nachdem Sie aus Ihrer Datenbank trennen, so gibt es keine Notwendigkeit, sie explizit zu fallen ist.

Ich hatte ursprünglich, aber ich glaube es nicht, die allen Anforderungen erreicht:

SELECT t1.id, 
     t1.descr_id, 
     t1.date, 
     t1.value, 
     t2.description 
FROM table1 t1 
JOIN table2 t2 ON t1.descr_id = t2.descr_id 
WHERE t2.description = 'abc' 

Dies resultierte im Wesentlichen die gleiche wie die ursprüngliche Abfrage ist jedoch könnte eine weitere Option sein, um eine Ansicht zu erstellen und kommen auf die Ansicht wie folgt aus:

CREATE VIEW v1 AS 
SELECT * FROM table1 JOIN table2 USING(descr_id) WHERE label='abc' 

CREATE VIEW v2 AS 
SELECT * FROM table1 JOIN table2 USING(descr_id) WHERE label='abc' 

SELECT * 
FROM v1 
LEFT JOIN v2 on(v1.date<v2.date and v1.date + interval 6 minute > v2.date) 
WHERE v1.value=v2.value 

auch, wenn Sie diese Abfrage auf regelmäßig ausführen, können Sie die Ergebnisse Ihrer ersten Abfrage in eine Staging-Tabelle betrachten zu laden und Ihre auf dem Staging-Tabelle wie folgt verbinden tun:

INSERT INTO staging 
(SELECT * 
     FROM table1 
     JOIN table2 USING(descr_id) 
     WHERE label='abc') 

SELECT * 
    FROM staging s1 
    LEFT JOIN staging s2 on(s1.date<s2.date and s1.date + interval 6 minute > s2.date) 
    WHERE s1.value=s2.value 

TRUNCATE TABLE staging 
+0

Bitte verwenden Sie nicht diese SQL-Anti-Muster ... sehr schlechte Möglichkeit, dies zu tun ... weil dies eine myisam-basierte Tabelle verursachen kann ... –

+0

Würden die Tabellen nach dem Gebrauch besser sein? Oder sollten temporäre Tabellen überhaupt nicht verwendet werden? –

+1

temporäre Tabelle sollte vermeiden, es könnte dazu führen, dass die Myisam-Festplatte siehe http://dev.mysql.com/doc/refman/5.7/en/internal-temporary-tables.html es max_heap_table_size ist zu klein, es wird passieren –

0

versuchen, nicht zu verwenden, existiert etwas wie select * von table1 t1 table2 t2 mit (descr_id) verbinden wo label = 'abc' und nicht existiert (select * von table1 t11 table2 t22 beitreten mit (descr_id) wobei label = 'abc' und t1.Datum < t11.date und t1.date + Intervall 6 Minuten> t11.date)

Sie die (t1.date verdoppeln müssen prüfen + Intervall 6 Minuten) Syntax