2013-09-25 22 views
5

aynı 2 tablolara 2 tabloları birleştirmeMySQL Bu yapı basitleştirilebilir 2 tablolar

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

Tablo 2:

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

Ben açıklama tablo1 içine katılmak istiyorum, açıklama ile filtre sadece bu yüzden ben sadece tanımları = abc satırları almak ve "çift" satırları filtrelemek, iki satır aynı değere sahip ve yinelenen tarihler 6 mi birbirinin nutes. İstenilen çıktı tablosum aşağıdadır (abc istenen açıklama filtresi olduğu varsayılarak).

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

ben ile geldi sorgusu:

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. 

Ne yazık ki bu sorgu benim veri kümesi ile çalıştırmak için bir dakika boyunca sürer ve (ı sonuçları olması gerektiğini düşünüyoruz rağmen) sonuç verir. Bu sorguyu gerçekleştirmenin daha verimli bir yolu var mı? Türetilmiş bir tabloyu adlandırmanın ve daha sonra aynı sorguda başvurmanın bir yolu var mı? Ayrıca, sorgum neden sonuç döndürmüyor?

Yardım için şimdiden teşekkür ederiz!

düzenleme: Yakın örnek zaman damgaları ile birkaç örnek ilk tutmak istiyorum.

Tablo1'de 6,1 milyon satır var, benim table2'm 30K var, bu da tablo2'nin "abc" açıklaması için yalnızca bir satır olacağını anlamamı sağlıyor. Bu, daha önce descr_id için sorgulayabildiğim anlamına gelir, daha sonra tabloyu büyük sorguda birleştirmekten kaçınmak için o kimliği kullanır ve daha verimli hale getirir. Ancak, benim tablo2 yukarıda belirtildiği gibi ayarlandıysa (ki bu zayıf veritabanı tasarımı olurdu, itiraf ediyorum) bu tür bir sorguyu gerçekleştirmenin iyi bir yolu nedir?

+1

Eğer ilk korumak için umut var birbirine yakın zaman damgalarıyla veya sonuncusuyla veya bunların zaman damgalarının ortalamasıyla birkaç örnek veya ne? Numunelerinizin her bir grubunu birbirine yakın olarak temsil etmek için sonuç kümesinde ne zaman damgası olmalıdır? –

+0

Güzel soru BTW +1 tabloların kaç kayıt var? –

cevap

1

deneyin geçici tablolar oluşturma ve geçici tablolarda katılmadan: bunları açıkça düşmesi gerek yoktur böylece veritabanından bağlantısını kestikten sonra

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 

Geçici tablolar otomatik olarak temizlenir.

Başlangıçta bu vardı, ama tam gereksinimlerini elde inanmıyorum: ancak başka bir seçenek bir görünüm oluşturmak ve üzerinde katılmak için olabilir, Bu aslında orijinal sorgu olarak aynıdır

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' 

böyle görünümü: düzenli olarak bu sorguyu çalıştırırsanız Ayrıca

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 

, bir evreleme tabloya ilk sorgudan sonucu yüklenirken ve sizin böyle evreleme masaya katılmak yapıyor düşünebilirsiniz:

kullanmak
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

Lütfen bu SQL anti pattern'i kullanmayın ... Bunu yapmak için çok kötü bir yol ... çünkü bu bir myisam disk tabanlı tabloya neden olabilir ... –

+0

Kullanımdan sonra tabloları düşürmek daha iyi bir uygulama mıdır? Yoksa geçici tablolar hiç kullanılmamalıdır? –

+1

geçici tablo myisam diski ile sonuçlanmasından sakınılmalıdır. Http://dev.mysql.com/doc/refman/5.7/en/internal-temporary-tables.html max_heap_table_size küçük olsun –

0

denemeyeceğim (tablo2 T22 katılmak tablo1 t11 dan * seçmek Varlığından değil şey tablo1 t1 den * Belirli gibi (DESCRJD'ye) label = 'abc' kullanarak table2 t2 katılmak varsa ve (descr_id) öğesinin kullanıldığı etiket = 'abc' ve t1.tarih < t11.date ve t1.date + aralık 6 dakika> t11.date)

sen (t1.date + aralık 6 dakika) sözdizimi kontrol etmeniz gerekebilir