1

下面是我使用聚合函数的查询。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')
4

2 回答 2

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并改用后者。

于 2013-04-16T10:30:07.717 回答
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 TABLE ACCESS FULL TABLE DAVE.TEST_TABLE 成本:621 字节:9,923,914 基数:763,378

然后一个corpId 109,650 ...

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

计划 SELECT STATEMENT ALL_ROWSCost:265 字节:26 基数:1
3 SORT AGGREGATE 字节:26 基数:1
2 TABLE ACCESS BY INDEX ROWID TABLE DAVE.TEST_TABLE 成本:265 字节:3,310,138 基数:127,313
1 INDEX RANGE SCAN INDEX_NEX DAVE.TABLE 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 Bytes: 35 Cardinality: 1
3 SORT AGGREGATE Bytes: 35 Cardinality: 1
2 TABLE ACCESS BY INDEX ROWID TABLE DAVE.TEST_TABLE Cost: 265 Bytes: 871,360 Cardinality: 24,896
1 INDEX RANGE SCAN INDEX DAVE.TEST_TABLE 213 基数:3,054

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

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

create index test_table_nui_3 on test_table(corpId, incoming_date);

Plan SELECT STATEMENT ALL_ROWSCost: 15 Bytes: 35 Cardinality: 1
3 SORT AGGREGATE Bytes: 35 Cardinality: 1
2 TABLE ACCESS BY INDEX ROWID TABLE DAVE.TEST_TABLE 成本: 15 Bytes: 871,360 Cardinality: 24,896
1 INDEX RANGE SCAN INDEX_3 Cost: DAVE.TEST_TABLE_N 3 基数:14

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

于 2013-04-16T12:22:50.883 回答