使用Oracle聚合函数时查询性能

时间:2013-04-16 10:24:50

标签: performance oracle function aggregate

以下是我使用聚合函数的查询。 where子句很简单,在corpId和incoming_date上有索引。 如果我只是获取所有行/计数,则查询所花费的时间少于一秒。但是,当我使用聚合函数时,查询大约需要4分钟。 我使用的是oracle 11i,where子句检索的总行数大约是64000.最近也收集了表和索引统计信息,并且表中没有添加新行。

请建议提高速度。

SELECT
sum(paid_amt) totalamount
FROM test_table e
WHERE  e.corpId =6
AND e. incoming_date >= to_date('01-12-2012','dd-mm-yyyy')
AND e. incoming _date <= to_date('09-01-2013','dd-mm-yyyy')

2 个答案:

答案 0 :(得分:3)

在索引中加入paid_amt

CREATE INDEX
        ix_testtable_cord_date_paid
ON      test_table (corpId, incoming_date, paid_amt)

如果您只有(corpId, incoming_date)的索引,并尝试像这样测试速度:

SELECT  COUNT(*)
FROM    test_table
WHERE   e.corpId = 6
        AND e.incoming_date >= to_date('01-12-2012','dd-mm-yyyy')
        AND e.incoming_date <= to_date('09-01-2013','dd-mm-yyyy')

您没有查询索引之外的任何内容,因此只需INDEX (RANGE SCAN)即可满足查询。

只要添加不在索引中的任何内容(在您的情况下为paid_amt),查询就需要使用其他TABLE ACCESS (BY INDEX ROWID)来从表中检索记录。

它是嵌套循环中的随机查找,并且速度很慢,尤其是当您的表记录很大(有很多字段或长字段)时。

优化器甚至可能认为此访问方法的效率低于FULL SCAN,而是使用后者。

答案 1 :(得分:0)

我重新创建了这样的场景......

CREATE TABLE test_table 
  ( id integer
  , corpId integer
  , paid_amt number(10,2)
  , incoming_date DATE );

ALTER TABLE test_table
add CONSTRAINT test_table_pk PRIMARY KEY (id);

create index test_table_nui_1 on test_table(corpId);

create index test_table_nui_2 on test_table(incoming_date);

create sequence test_table_seq;

insert into test_table
  select test_table_seq.nextval
       ,MOD(test_table_seq.currval,6)
       ,MOD(test_table_seq.currval,10) + 1
       ,sysdate - MOD(test_table_seq.currval,200) 
  from all_objects, user_objects;  

all_objects和user_objects之间的笛卡尔联接只是一个快速插入记录加载的黑客攻击。 (在这种情况下为657,000行)

首先选择所有657,000 ...

select sum(paid_amt)
from test_table;

计划 SELECT STATEMENT ALL_ROWSCost:621字节:13基数:1
    2 SORT AGGREGATE字节:13基数:1
        1表访问全表DAVE.TEST_TABLE成本:621字节:9,923,914基数:763,378

然后是一个公司的109,650 ......

select sum(paid_amt)
from test_table
where corpId = 5;

计划 SELECT STATEMENT ALL_ROWSCost:265字节:26基数:1
    3分类总分字数:26基数:1
        2通过INDEX ROWID表进行访问表DAVE.TEST_TABLE成本:265字节:3,310,138基数:127,313
            1 INDEX RANGE SCAN INDEX DAVE.TEST_TABLE_NUI_1费用:213基数:3,054

最后20,836行按日期限制......

SELECT sum(paid_amt) totalamount
FROM test_table e
WHERE  e.corpId = 5
AND e. incoming_date >= to_date('01-12-2012','dd-mm-yyyy')
AND e. incoming_date <= to_date('09-01-2013','dd-mm-yyyy')

计划 SELECT STATEMENT ALL_ROWSCost:265字节:35基数:1
    3 SORT AGGREGATE字节:35基数:1
        2按INDEX ROWID表进行访问表DAVE.TEST_TABLE成本:265字节:871,360基数:24,896
            1 INDEX RANGE SCAN INDEX DAVE.TEST_TABLE_NUI_1费用:213基数:3,054

所有3个查询都是快速的(即<0.5秒)

另一种方法是删除nui_1和nui_2,并在两列上创建组合索引。然后在我的数据库上运行31毫秒

create index test_table_nui_3 on test_table(corpId, incoming_date);

计划 SELECT STATEMENT ALL_ROWSCost:15字节:35基数:1
    3 SORT AGGREGATE字节:35基数:1
        2通过INDEX ROWID表进行访问表DAVE.TEST_TABLE成本:15字节:871,360基数:24,896
            1 INDEX RANGE SCAN INDEX DAVE.TEST_TABLE_NUI_3费用:3基数:14

这表明聚合函数不是问题,但您的索引可能是。最好的办法是检查你的解释计划。