优化oracle查询
我很难理解这个问题。执行过程大约需要200多秒。我还粘贴了执行计划优化oracle查询,oracle,optimization,Oracle,Optimization,我很难理解这个问题。执行过程大约需要200多秒。我还粘贴了执行计划 SELECT user_id , ROLE_ID , effective_from_date , effective_to_date , participant_code , ACTIVE FROM CMP_USER_ROLE E WHERE ACTIVE =
SELECT
user_id ,
ROLE_ID ,
effective_from_date ,
effective_to_date ,
participant_code ,
ACTIVE
FROM
CMP_USER_ROLE E
WHERE
ACTIVE = 0
AND (SYSDATE BETWEEN effective_from_date AND effective_to_date
OR TO_CHAR(effective_to_date,'YYYY-Q') = '2010-2')
AND participant_code = 'NY005'
AND NOT EXISTS
( SELECT 1 FROM CMP_USER_ROLE r
WHERE r.USER_ID= E.USER_ID
AND r.role_id = E.role_id
AND r.ACTIVE = 4
AND E.effective_to_date
<= ( SELECT MAX(last_update_date)
FROM CMP_USER_ROLE S
WHERE S.role_id = r.role_id
AND S.role_id = r.role_id
AND S.ACTIVE = 4 ))
统计数字:
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
3433602 consistent gets
0 physical reads
0 redo size
58149 bytes sent via SQL*Net to client
1260 bytes received via SQL*Net from client
148 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2199 rows processed
首先要分析您的表:
EXEC dbms_stats.gather_table_stats('YOUR_SCHEMA', 'CMP_USER_ROLE');
你还有同样的执行计划吗
执行计划中的
Time
列看起来好像您的查询对于Oracle optimizer来说没有那么昂贵。尝试在查询上运行EXPLAIN plan,看看它是否正在进行表扫描
我猜这一条款会有问题:
OR TO_CHAR(effective_to_date,'YYYY-Q') = '2010-2')
我认为在WHERE子句中调用函数会迫使Oracle扫描每一行,因为它必须在每一列上计算该函数,以查看该行是否是结果集的一部分。这样会使索引无效
更好的解决方案是对索引列值进行搜索,而不需要函数调用对其求值。我建议使用“x和y之间的日期列”,其中x和y是季度的开始和结束日期。确保DATE_列上有索引。嗯,我受到了攻击 无论如何,以下是您需要解决的问题:
3433602 consistent gets
三百万个逻辑IOs会占用很多时间,所以你需要做的就是减少这个数字
您的查询包含对同一个表的三组访问。每个访问都由一个索引读取和一个表读取组成。从这一点来看,您的统计数据似乎相当准确(查询返回699415行,NUM_rows
=697608)
调谐是一项复杂的活动,需要考虑很多因素。我们可以很容易地花半天的时间来检查这一个查询可能出现的所有错误
例如,您是否收集索引和表的统计数据(在早期版本的Oracle中,默认情况下不收集索引统计数据)?如果您有统计数据,那么这些索引的聚类因子是什么?所有索引访问都是扫描,因此聚类因素是相关的
我们想要的是一个较低的聚类因子,因为这意味着索引必须做较少的工作才能从表中获取行。如果聚类因子更接近于索引中坏的条目数,而如果聚类因子更接近于表中的块数,则是好的。唉,考虑到你所经历的狮子数量,我的钱花在了糟糕的集群因素上。所以你需要从索引中获取更多的信息
查看查询,最外层投影中的列用于查询和/或子查询的WHERE子句中。尽管如此,您使用的是三个不同的索引,它们都不提供满足条件所需的所有信息(因此需要额外的表读取和后续筛选)。在这些情况下,一种非常有效的策略是构建一个包含所有必要列的超级索引
create index N_USER_ROLE_IDX23 on user_role
( active
, role_id
, user_id
, participant_code
, effective_from_date
, effective_to_date
, last_update_date )
这将导致ACTIVE和ROLE_ID,因为这些列在所有三组条件中都使用。(顺便提一下,你的第三个问题是:
WHERE S.role_id = r.role_id
AND S.role_id = r.role_id
不管怎么说,这个索引的要点是它满足了所有三个WHERE子句和最终投影,因此它根本不需要触摸表格。因此,它可以显著减少一致GET的数量 一个问题可能是子查询中的双重连接(倒数第二行)。删除
和S.role\u id=r.role\u id
,看看这是否加快了速度。:)没有注意到这一点。但这并没有多大帮助。表上现有的索引是什么?我也这么认为。因为函数是在每个get上完成的。但怎样才能避免这种情况呢。我是否应该按日期搜索季度而不是使用函数/@deming:将替换为=
并在日期“2010-01-01”和日期“2010-03-31”之间截断(生效日期)
。。。对不起,日期弄错了。更好的是,effect\u to\u date>=日期“2010-04-01”和effect\u to\u date
您可以为此表达式添加基于函数的索引。太好了。我没有特权。bolllock如果从cmp\u user\u role选择COUNT(*)
返回的值与从用户\u table\u name='cmp\u user\u role'
所在的用户\u table中选择num\u行的值大致相同,请重试。您是否有权执行分析表cmp\u user\u role计算统计数据
?上述两个查询如何?第一个查询=699415。第二个查询=697608。cmp_user_role实际上是一个指向user_role的视图。所以在第二个查询中,我必须执行table\u name='USER\u ROLE'
WHERE S.role_id = r.role_id
AND S.role_id = r.role_id