2013-09-25 45 views
5

Tôi có 2 bảng có thể được đơn giản hóa để cấu trúc này:mysql hiệu quả tham gia của 2 bảng vào 2 bảng cùng

Bảng 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 | 
+----+----------+---------------------+-------+ 

Bảng 2:

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

Tôi muốn tham gia mô tả vào table1, lọc theo mô tả để tôi chỉ nhận các hàng có mô tả = abc và lọc ra các hàng "trùng lặp", trong đó hai hàng trùng lặp nếu chúng có cùng giá trị và ngày của chúng nằm trong vòng 9 dặm nutes của nhau. Bảng đầu ra mong muốn của tôi là dưới đây, (giả sử abc là bộ lọc mô tả mong muốn).

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

Truy vấn tôi đã đưa ra là:

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. 

Thật không may truy vấn này mất hơn một phút để chạy với dữ liệu của tôi, và trả về không có kết quả (mặc dù tôi tin rằng cần có kết quả). Có cách nào hiệu quả hơn để thực hiện truy vấn này không? Có cách nào để đặt tên cho một bảng có nguồn gốc và tham chiếu nó sau này trong cùng một truy vấn không? Ngoài ra, tại sao truy vấn của tôi không trả lại kết quả?

Cảm ơn bạn đã trợ giúp!

chỉnh sửa: Tôi muốn giữ lại phần đầu của một số mẫu có dấu thời gian gần nhau.

Bảng 1 của tôi có 6,1 triệu hàng, bảng 2 của tôi có 30K, điều này khiến tôi nhận ra rằng bảng 2 chỉ có một hàng cho mô tả "abc". Điều này có nghĩa là tôi chỉ có thể truy vấn descr_id trước, sau đó sử dụng id đó để tránh tham gia table2 trong truy vấn lớn, làm cho nó hiệu quả hơn nhiều. Tuy nhiên, nếu table2 của tôi đã được thiết lập như đã nêu ở trên (đó sẽ là thiết kế cơ sở dữ liệu nghèo, tôi thừa nhận) một cách tốt để thực hiện một truy vấn như vậy là gì?

+1

Bạn có hy vọng để giữ lại đầu tiên của một số mẫu có dấu thời gian gần nhau, hoặc cuối cùng của chúng, hoặc tính trung bình các dấu thời gian của chúng, hoặc cái gì? Dấu thời gian nào sẽ có trong resultset để biểu diễn từng bó mẫu của bạn ở gần nhau? –

+0

Câu hỏi hay BTW +1 có bao nhiêu bản ghi mà các bảng có? –

Trả lời

1

Hãy thử tạo bảng tạm thời và tham gia vào các bảng tạm thời:

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 

bảng tạm thời được tự động làm sạch sau khi bạn ngắt kết nối từ cơ sở dữ liệu của bạn do đó không cần phải thả chúng một cách rõ ràng.

tôi ban đầu đã có này, nhưng tôi không tin nó đạt được đầy đủ các yêu cầu:

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' 

Đây thực chất là giống như truy vấn ban đầu, tuy nhiên tuỳ chọn khác có thể là để tạo ra một cái nhìn và tham gia vào quan điểm như thế này:

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 

Ngoài ra, nếu bạn chạy truy vấn này một cách thường xuyên, bạn có thể xem xét tải các kết quả từ truy vấn đầu tiên bạn vào một bảng dàn dựng và thực hiện tham gia của bạn trên bảng dàn như thế này:

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

Xin vui lòng không sử dụng mô hình chống SQL này ... cách rất xấu để làm điều này ... bởi vì điều này có thể gây ra một bảng myisam dựa ... –

+0

Sẽ thả các bảng sau khi sử dụng được thực hành tốt hơn? Hoặc nên tạm thời không được sử dụng bảng? –

+1

bảng tạm thời nên tránh nó có thể dẫn đến đĩa myisam thấy http://dev.mysql.com/doc/refman/5.7/en/internal-temporary-tables.html nó max_heap_table_size là nhỏ nó sẽ xảy ra –

0

cố gắng sử dụng không tồn tại cái gì đó như chọn * từ table1 t1 tham gia table2 t2 sử dụng (descr_id) nơi label = 'abc' và không tồn tại (chọn * từ table1 t11 tham gia table2 T22 sử dụng (descr_id) nơi nhãn = 'abc' và t1.ngày < t11.date và t1.date + khoảng thời gian 6 phút> t11.date)

bạn có thể cần phải kiểm tra (t1.date + khoảng 6 phút) cú pháp tăng gấp đôi

Các vấn đề liên quan