【发布时间】:2011-02-15 12:44:55
【问题描述】:
我正在尝试在 Oracle 8i 服务器(旧的,我知道)上运行以下 PL/SQL:
select
-- stuff --
from
s_doc_quote d,
s_quote_item i,
s_contact c,
s_addr_per a,
cx_meter_info m
where
d.row_id = i.sd_id
and d.con_per_id = c.row_id
and i.ship_per_addr_id = a.row_id(+)
and i.x_meter_info_id = m.row_id(+)
and d.x_move_type in ('Move In','Move Out','Move Out / Move In')
and i.prod_id in ('1-QH6','1-QH8')
and d.created between add_months(trunc(sysdate,'MM'), -1) and sysdate
;
然而,执行速度非常慢。由于服务器在每晚午夜左右关闭,因此通常无法及时完成。
执行计划如下:
SELECT STATEMENT 1179377
NESTED LOOPS 1179377
NESTED LOOPS OUTER 959695
NESTED LOOPS OUTER 740014
NESTED LOOPS 520332
INLIST ITERATOR
TABLE ACCESS BY INDEX ROWID S_QUOTE_ITEM 157132
INDEX RANGE SCAN S_QUOTE_ITEM_IDX8 8917
TABLE ACCESS BY INDEX ROWID S_DOC_QUOTE 1
INDEX UNIQUE SCAN S_DOC_QUOTE_P1 1
TABLE ACCESS BY INDEX ROWID S_ADDR_PER 1
INDEX UNIQUE SCAN S_ADDR_PER_P1 1
TABLE ACCESS BY INDEX ROWID CX_METER_INFO 1
INDEX UNIQUE SCAN CX_METER_INFO_P1 1
TABLE ACCESS BY INDEX ROWID S_CONTACT 1
INDEX UNIQUE SCAN S_CONTACT_P1 1
如果我更改以下 where 子句:
and d.created between add_months(trunc(sysdate,'MM'), -1) and sysdate
转为静态值,如:
and d.created between to_date('20110101','yyyymmdd') and sysdate
执行计划变为:
SELECT STATEMENT 5
NESTED LOOPS 5
NESTED LOOPS OUTER 4
NESTED LOOPS OUTER 3
NESTED LOOPS 2
TABLE ACCESS BY INDEX ROWID S_DOC_QUOTE 1
INDEX RANGE SCAN S_DOC_QUOTE_IDX1 3
INLIST ITERATOR
TABLE ACCESS BY INDEX ROWID S_QUOTE_ITEM 1
INDEX RANGE SCAN S_QUOTE_ITEM_IDX4 4
TABLE ACCESS BY INDEX ROWID S_ADDR_PER 1
INDEX UNIQUE SCAN S_ADDR_PER_P1 1
TABLE ACCESS BY INDEX ROWID CX_METER_INFO 1
INDEX UNIQUE SCAN CX_METER_INFO_P1 1
TABLE ACCESS BY INDEX ROWID S_CONTACT 1
INDEX UNIQUE SCAN S_CONTACT_P1 1
几乎立即开始返回行。
到目前为止,我已经尝试用绑定变量替换动态日期条件,以及使用从对偶表中选择动态日期的子查询。到目前为止,这些方法都没有帮助提高性能。
因为我对 PL/SQL 比较陌生,所以我无法理解执行计划中出现如此巨大差异的原因。
我还尝试将查询作为 SAS 的传递来运行,但为了测试执行速度,我一直在使用 SQL*Plus。
编辑:
为了澄清,我已经尝试使用如下绑定变量:
var start_date varchar2(8);
exec :start_date := to_char(add_months(trunc(sysdate,'MM'), -1),'yyyymmdd')
使用以下 where 子句:
and d.created between to_date(:start_date,'yyyymmdd') and sysdate
返回 1179377 的执行成本。
如果可能,我还想避免绑定变量,因为我不相信我可以从 SAS 传递查询中引用它们(尽管我可能错了)。
【问题讨论】:
-
这些表的优化器统计信息是最新的吗?定义了索引和外键等。无法从您的计划中真正看出,但可能是它无法为输出集计算出正确的基数,然后选择嵌套循环
-
@MikeyByCrikey - 查询设置为使用索引,但不幸的是我没有权限分析数据库/表统计信息。
标签: performance oracle date