2013-09-25 11 views
5

mam 2 tabele, które mogą być uproszczone do tej struktury:mysql wydajny sprzężeniu 2 tabelach tych samych 2 tabelach

Tabela 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 | 
+----+----------+---------------------+-------+ 

Tabela 2:

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

Chcę dołączyć do opisu do tabeli1, filtrować według opisu, więc otrzymuję tylko wiersze gdzie opis = abc, i odfiltrowuję "duplikaty" wierszy, gdzie dwa wiersze są duplikatami, jeśli mają tę samą wartość, a ich daty są w granicach 6 mil nutes siebie. Moja pożądana tabela wyjściowa znajduje się poniżej (zakładając, że abc jest pożądanym filtrem opisu).

+----+----------+---------------------+-------+-------------+ 
| 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   | 
+----+----------+---------------------+-------+-------------+ 

Zapytanie wymyśliłem to:

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. 

Niestety zapytanie trwa ponad minutę do uruchomienia z moim zbiorze i Brak wyników wyszukiwania (chociaż uważam, że nie powinno być wyniki). Czy istnieje skuteczniejszy sposób wykonania tego zapytania? Czy istnieje sposób nazywać wyprowadzoną tabelę i odwoływać się do niej później w tym samym zapytaniu? Dlaczego moje zapytanie nie zwraca żadnych wyników?

Z góry dziękujemy za pomoc!

edytuj: Chciałbym zachować pierwszą z kilku próbek ze zbliżonymi znacznikami czasowymi.

Moja tabela1 ma 6,1 miliona wierszy, mój stół 2 ma 30K, co uświadamia mi, że tabela 2 będzie miała tylko jeden wiersz dla opisu "abc". Oznacza to, że mogę po prostu zapytać o descr_id wcześniej, a następnie użyć tego identyfikatora, aby w ogóle uniknąć dołączania do tabeli 2 w dużym zapytaniu, co znacznie usprawnia proces. Jednak jeśli mój table2 został skonfigurowany tak, jak opisano powyżej (co byłoby kiepskim projektem bazy danych, przyznaję), jaki jest dobry sposób na wykonanie takiego zapytania?

+1

Czy chcąc zachować pierwsza kilka próbek ze zbliżonymi znacznikami czasu lub ostatnią z nich, lub uśredniając ich sygnatury czasowe, lub co? Jaki znacznik czasu powinien znajdować się w zestawie wyników, aby reprezentować każdą pęczek próbek jest blisko siebie? –

+0

Ładne pytanie BTW +1 Ile rekordów ma tabel? –

Odpowiedz

1

Spróbuj tworzenia tabel tymczasowych i łączenia na tabelach tymczasowych:

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 

tabele tymczasowe są automatycznie czyszczone po odłączeniu od swojej bazy, więc nie ma potrzeby, aby je wyraźnie spadnie.

pierwotnie miał to, ale nie wierzę, że osiąga pełne wymagania:

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' 

To jest w zasadzie taka sama jak oryginalnego zapytania, jednak inna opcja może być utworzyć widok i dołącz na widok tak:

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 

Ponadto, jeśli uruchomić tę kwerendę w sposób regularny, można rozważyć ładowanie wyników z pierwszego zapytania do tabeli tymczasowej i robi swoje dołączyć na stole pomostowym tak:

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

Proszę nie używaj tego antyseptycznego kodu SQL ... bardzo źle to zrobić ... ponieważ może to spowodować tabelę opartą na dysku myisam ... –

+0

Czy upuszczenie tabel po użyciu byłoby lepszą praktyką? A może tabele tymczasowe nie powinny być w ogóle używane? –

+1

tabeli tymczasowej należy unikać może spowodować dysk myisam zobacz ten http://dev.mysql.com/doc/refman/5.7/en/internal-temporary-tables.html max_heap_table_size jest mały to się stanie –

0

spróbuje użyć nie istnieje coś select * z tabela1 t1 dołączyć Table2 t2 użyciu (descr_id) gdzie label = 'abc' i nie istnieje (select * z Tabela1 t11 dołączyć Table2 T22 using (descr_id) gdzie label = "abc" i t1.data < t11.date i t1.date + przedział 6 minut> t11.date)

może trzeba dokładnie sprawdzić (t1.date + przedział 6 minuta) składni

Powiązane problemy