2015-08-01 13 views
7

Oracle veritabanında bir tablom var. TYPEA ve TYPEB: şema İki farklı TYPE's sahip(self) zaman aralıklarına göre katıl

create table PERIODS 
( 
    ID NUMBER, 
    STARTTIME TIMESTAMP, 
    ENDTIME TIMESTAMP, 
    TYPE VARCHAR2(100) 
) 

olduğunu. Bağımsız başlangıç ​​ve bitiş zamanlarına sahipler ve üst üste binebilirler. Bulmak istediğim, 'un başladığı, TYPEA'un belirli bir periyodu içinde tamamen içerildiği veya sona erdiği dönemlerdir. İşte

WITH mydata 
    AS (SELECT 100             ID, 
       To_timestamp('2015-08-01 11:00', 'YYYY-MM-DD HH24:MI') STARTTIME, 
       To_timestamp('2015-08-01 11:20', 'YYYY-MM-DD HH24:MI') ENDTIME, 
       'TYPEA'            TYPE 
     FROM dual 
     UNION ALL 
     SELECT 110             ID, 
       To_timestamp('2015-08-01 11:30', 'YYYY-MM-DD HH24:MI') STARTTIME, 
       To_timestamp('2015-08-01 11:50', 'YYYY-MM-DD HH24:MI') ENDTIME, 
       'TYPEA'            TYPE 
     FROM dual 
     UNION ALL 
     SELECT 120             ID, 
       To_timestamp('2015-08-01 12:00', 'YYYY-MM-DD HH24:MI') STARTTIME, 
       To_timestamp('2015-08-01 12:20', 'YYYY-MM-DD HH24:MI') ENDTIME, 
       'TYPEA'            TYPE 
     FROM dual 
     UNION ALL 
     SELECT 105             ID, 
       To_timestamp('2015-08-01 10:55', 'YYYY-MM-DD HH24:MI') STARTTIME, 
       To_timestamp('2015-08-01 11:05', 'YYYY-MM-DD HH24:MI') ENDTIME, 
       'TYPEB'            TYPE 
     FROM dual 
     UNION ALL 
     SELECT 108             ID, 
       To_timestamp('2015-08-01 11:05', 'YYYY-MM-DD HH24:MI') STARTTIME, 
       To_timestamp('2015-08-01 11:15', 'YYYY-MM-DD HH24:MI') ENDTIME, 
       'TYPEB'            TYPE 
     FROM dual 
     UNION ALL 
     SELECT 111             ID, 
       To_timestamp('2015-08-01 11:15', 'YYYY-MM-DD HH24:MI') STARTTIME, 
       To_timestamp('2015-08-01 12:25', 'YYYY-MM-DD HH24:MI') ENDTIME, 
       'TYPEB'            TYPE 
     FROM dual), 
    typeas 
    AS (SELECT starttime, 
       endtime 
     FROM mydata 
     WHERE TYPE = 'TYPEA'), 
    typebs 
    AS (SELECT id, 
       starttime, 
       endtime 
     FROM mydata 
     WHERE TYPE = 'TYPEB') 
SELECT id 
FROM typebs b 
     join typeas a 
     ON (b.starttime BETWEEN a.starttime AND a.endtime) 
      OR (b.starttime BETWEEN a.starttime AND a.endtime 
        AND b.endtime BETWEEN a.starttime AND a.endtime) 
      OR (b.endtime BETWEEN a.starttime AND a.endtime) 
ORDER BY id; 

Bu prensipte çalışıyor görünüyor (bazı örnek verilerle) Ben şimdiye kadar geldi budur, sorgunun sonuç yukarıda yüzden seçer

 ID 
---------- 
     105 
     108 
     111 

olduğunu İlk TYPEA döneminde başlayan veya biten üç dönem TYPEB.

sorun (tablo yaklaşık 200k giriş vardır ve zaten bu boyutta yukarıdaki sorgu hem TYPEA ve TYPEB girişlerinin sayısı olarak benim için çok şaşırtıcı olan --- oldukça yavaş oldukça düşük olduğunu 1-2k olduğunu

Bu tür bir kendi kendine katılımı gerçekleştirmenin daha verimli bir yolu var mı? Sorgumda başka bir şey mi özledim?

+0

tablo 200.000 satır var, sadece iki farklı 'type' değeri var, ancak her' type' sadece 1.000-2.000 satır var. Bu, tablodaki ~ 196,000 satırın 'type' için 'NULL' olduğunu ima eder mi? Bir ayarlama sorusu soruyorsanız, aldığınız sorgu planını ve hangi dizinlerin kullanılabilir olduğunu kaydeder misiniz? –

+0

Tablo, çoğu bu sorgu için benim için uygun olmayan bir türü olan 200k satırları vardır. – Erik

+0

@JustinCave bu bir ayarlama sorusu olabilir, ancak belki de bu sorguyu ayarlamadan çok daha hızlı hale getirecek bazı özelliklerden habersiz olabilirim. – Erik

cevap

1

Belki bir cami (ayrıca kendi performans testlerini yapmak daha iyi, beni bana sor neden ya inanmıyorum, oracle sonunda en kısıtlayıcı koşullar yazmak gerekir):

SELECT 
    p.id 
FROM 
    periods p 
WHERE 
    EXISTS(SELECT * FROM periods q WHERE 
     (p.startTime BETWEEN q.startTime AND q.endTime 
     OR p.endTime BETWEEN q.startTime AND q.endTime 
     OR p.startTime < q.startTime AND p.endTime > q.endTime -- overlapping correction, remove if not needed 
    ) AND q.type = 'TYPEA' 
    ) AND p.type = 'TYPEB' 
ORDER BY 
    p.id 
; 
+0

VE q.type = 'TYPEA' alt sorgunun içinde olmalıdır – Bulat

+1

İçerde, belki parantezler garip görünüyor, ancak daha çok girinti üzerinde duruyorum. – maraca