2011-12-23 55 views
2

我有2張桌子。表「Accs」包含900萬行(3列:acc_id,月份,年份)。 首先,我需要提取包含的賬號, 部分條目,然後在這些記錄中找到完全匹配,如果不記錄 - 那麼第一部分匹配如何優化下一個oracle查詢?

WITH t AS (
    SELECT a.acc_id, 
     t1.as, 
     t1.cust, 
     t1.curr, 
     t1.code, 
     t1.depart, 
     t1.sdate, 
     t1.stype, 
     t1.amount, 
     t1.s_id 
    FROM table1 t1 
    LEFT JOIN Accs a 
    ON SUBSTR(a.acc_id,7,12)=t1.curr||LPAD(t1.code,4,'0')||LPAD(t1.depart,3,'0') 
    WHERE t1.sdate='20.11.2011' AND t1.stype='A' AND a.month=11 ANd a.year=2011) 
SELECT MAX(t.s_id), 
     (CASE WHEN t.as='000000' 
      THEN (CASE WHEN ac2.acc_id IS NOT NULL THEN ac2.acc_id ELSE t.acc_id END) 
      ELSE t.cust||t.curr||LPAD(t.code,4,'0')||LPAD(t.depart,3,'0') END) acc_id 
FROM t 
LEFT JOIN (SELECT t.acc_id FROM t) ac2 
ON SUBSTR(ac2.acc_id,1,6)='000'||LPAD(t.depart,3,'0') 
GROUP BY  
     (CASE WHEN t.as='000000' 
      THEN (CASE WHEN ac2.acc_id IS NOT NULL THEN ac2.acc_id ELSE t.acc_id END) 
      ELSE t.cust||t.curr||LPAD(t.code,4,'0')||LPAD(t.depart,3,'0') END) 

這個查詢需要較長時間。我是否正確?

+0

我懷疑你可以加快速度。很多連接都是在計算結果上完成的,這意味着索引不能使用。 – 2011-12-23 05:44:47

+0

有沒有其他更快的方法來做同樣的事情? – DmitryB 2011-12-23 05:52:52

+3

將這些計算出的字段存儲在派生字段中(這會使某些字符非規格化),但確實允許使用索引。 – 2011-12-23 05:53:55

回答

2

首次嘗試

不能真正對其進行測試,而無需實際的表結構和數據,但我做了一些小改動,有時會產生很大的影響。

首先,我將with部分中的LEFT JOIN更改爲INNER JOIN。由於您在WHERE子句中使用的值爲a,因此無論如何它都可以用作inner join,而且速度通常要快很多,尤其是對於大量的數據和適當的索引。

我將內部CASE更改爲NVL,因爲這基本上就是它的功能。不知道這是否會加快速度。

將字符串連接從外部查詢移至with部分。

這些只是很小的變化,可能會從沒有到相當一些效果。至少你可以在改變表結構本身之前嘗試這些,儘管無論如何這可能是一個好主意。

WITH t AS 
(
    SELECT 
    a.acc_id, 
    t1.as, 
    t1.cust, 
    t1.curr, 
    t1.code, 
    t1.depart, 
    t1.sdate, 
    t1.stype, 
    t1.amount, 
    t1.s_id, 
    t1.cust || t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0') as groupfield 
    FROM 
    table1 t1 
    INNER JOIN Accs a 
     ON SUBSTR(a.acc_id, 7, 12) = t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0') 
    WHERE 
    t1.sdate = '20.11.2011' AND t1.stype = 'A' AND a.month = 11 ANd a.year = 2011 
) 
SELECT 
    MAX(t.s_id), 
    (CASE WHEN t.as = '000000' THEN 
    NVL(ac2.acc_id, t.acc_id) 
    ELSE 
    t.groupfield 
    END) acc_id 
FROM 
    t 
    LEFT JOIN t ac2 on ac2 
    ON SUBSTR(ac2.acc_id, 1, 6) = '000' || LPAD(t.depart, 3, '0') 
GROUP BY  
    (CASE WHEN t.as = '000000' THEN 
    NVL(ac2.acc_id, t.acc_id) 
    ELSE 
    t.groupfield 
    END) 

第二次嘗試

看多一點到你的查詢後,我不知道,如果你不能只是做它,而不是使用with單/簡單的查詢。我認爲首先內部加入Accs,然後再加入Accs再加上額外的條件,你真的是一個好方法。

SELECT 
    MAX(t1.s_id) AS s_id, 
    CASE WHEN t.as = '000000' THEN 
     NVL(a2.acc_id, a.acc_id) 
    ELSE 
     t1.cust || t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0') 
    END AS acc_id 
    FROM 
    table1 t1 
    INNER JOIN Accs a 
     ON SUBSTR(a.acc_id, 7, 12) = t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0') 
     AND a.month = 11 AND a.year = 2011 
    LEFT JOIN Accs a2 
     ON SUBSTR(a2.acc_id, 7, 12) = t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0') 
     AND a2.month = 11 AND a2.year = 2011 
     AND SUBSTR(a2.acc_id, 1, 6) = '000' || LPAD(t1.depart, 3, '0') 
    WHERE 
    t1.sdate = '20.11.2011' AND t1.stype = 'A' 
    GROUP BY 
    CASE WHEN t.as = '000000' THEN 
     NVL(a2.acc_id, a.acc_id) 
    ELSE 
     t1.cust || t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0') as groupfield 
    END AS acc_id 
+0

根據Marc B的建議,我將「acc_id」字段分爲兩個字段。關於「Accs」表的「Where」的條件 - 我把它放在一個子查詢中。 – DmitryB 2011-12-23 11:06:37

0

你可以嘗試創建一個基於函數的索引像這樣的:

create index xxx on accs (SUBSTR(a.acc_id,7,12)); 
+0

這是我做的第一件事,但沒有幫助。 – DmitryB 2011-12-23 10:56:05