2011-12-23 56 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