2013-09-25 20 views
5

我有2個表即可以簡化該結構:MySQL的有效的連接到相同的2個表

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

表2:

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

我想將描述加入到table1中,按照描述進行過濾,因此我只獲取其中description = abc的行,並過濾掉「重複」行,其中兩行重複(如果它們具有相同的值並且日期在6 mi內)彼此相互吻合。我所需的輸出表如下(假設abc是所需的描述過濾器)。

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

我想出了查詢:

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. 

不幸的是這個查詢需要一分鐘時間才能與我的數據集運行,並且不返回任何結果(雖然我認爲應該有結果)。有沒有更有效的方法來執行此查詢?有沒有一種方法來命名派生表並稍後在同一個查詢中引用它?另外,爲什麼我的查詢沒有返回結果?

在此先感謝您的幫助!

編輯: 我想保留幾個樣本中的第一個與相近的時間戳。

我的table1有610萬行,我的table2有30K,這讓我意識到table2只有一行描述「abc」。這意味着我可以事先查詢descr_id,然後使用該id來避免在大查詢中加入table2,使其效率更高。但是,如果我的table2的設置如上所述(這將是糟糕的數據庫設計,我承認)執行此類查詢的好方法是什麼?

+1

你希望保持第一幾個樣本有時間戳,還是最後一個,或者平均時間戳,或者是什麼?結果集中應該包含什麼時間戳來表示每個樣本的相鄰關係? –

+0

好的問題BTW +1這些表有多少記錄? –

回答

1

嘗試創建臨時表和加入的臨時表:您從數據庫斷開連接之後,所以沒有必要明確地刪除它們

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 

臨時表會被自動清除。

我本來有,但我不認爲它達到全部要求:

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' 

這在本質上是一樣的原始查詢,但另一個選擇可能是創建一個視圖和加入認爲這樣的:

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 

另外,如果您定期運行此查詢,您可以考慮加載從第一個查詢結果到一個臨時表,並做你的加入在這樣的臨時表:

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

請不要使用這個SQL反模式...非常糟糕的方式來做到這一點...因爲這可能會導致myisam磁盤基於表... –

+0

使用後會丟掉表是更好的做法嗎?還是應該臨時表不被使用? –

+1

臨時表應該避免它可能導致myisam磁盤看到這個http://dev.mysql.com/doc/refman/5.7/en/internal-temporary-tables.html它max_heap_table_size是小的它會發生 –

0

嘗試使用不存在從表1 T1 像 SELECT * 使用(DESCR_ID) 其中label = 'ABC' 加入表2 t2和不存在(從表1 T11選擇* 加入表2 T22使用(descr_id) 其中label ='abc'和t1。日期< t11.date和t1.date +間隔6分鐘> t11.date)

您可能需要仔細檢查(t1.date +期間6分鐘),語法