Sql 优化Oracle查询
在此查询上运行explain plan,我将获得完整的表访问权限 使用的两个表格是:Sql 优化Oracle查询,sql,oracle,optimization,Sql,Oracle,Optimization,在此查询上运行explain plan,我将获得完整的表访问权限 使用的两个表格是: user_role: 803507 rows cmp_role: 27 rows 查询: SELECT r.user_id, r.role_id, r.participant_code, MAX(status_id) FROM user_role r, cmp_role c WHERE r.role_id = c.role_id AND r
user_role: 803507 rows
cmp_role: 27 rows
查询:
SELECT
r.user_id, r.role_id, r.participant_code, MAX(status_id)
FROM
user_role r,
cmp_role c
WHERE
r.role_id = c.role_id
AND r.participant_code IS NOT NULL
AND c.group_id = 3
GROUP BY
r.user_id, r.role_id, r.participant_code
HAVING MAX(status_id) IN (SELECT b.status_id FROM USER_ROLE b
WHERE (b.ACTIVE = 1 OR ( b.ACTIVE IN ( 0,3 )
AND SYSDATE BETWEEN b.effective_from_date AND b.effective_to_date
))
)
如何更好地编写此查询,以便在适当的时间内返回结果。以下是索引:
idx 1 = role_id
idx 2 = last_updt_user_id
idx 3 = actv_id, participant_code, effective_from_Date, effective_to_date
idx 4 = user_id, role_id, effective_from_Date, effective_to_date
idx 5 = participant_code, user_id, roke_id, actv_cd
解释计划:
Q_PLAN
--------------------------------------------------------------------------------
SELECT STATEMENT
FILTER
HASH GROUP BY
HASH JOIN
TABLE ACCESS BY INDEX ROWID ROLE
INDEX RANGE SCAN N_ROLE_IDX2
TABLE ACCESS FULL USER_ROLE
TABLE ACCESS BY INDEX ROWID USER_ROLE
INDEX UNIQUE SCAN U_USER_ROLE_IDX1
FILTER
HASH GROUP BY
HASH JOIN
TABLE ACCESS BY INDEX ROWID ROLE
INDEX RANGE SCAN N_ROLE_IDX2
TABLE ACCESS FULL USER_ROLE
TABLE ACCESS BY INDEX ROWID USER_ROLE
INDEX UNIQUE SCAN U_USER_ROLE_IDX1
我没有足够的权限在桌面上运行统计数据 尝试了以下更改,但只缩短了1或2秒:
WITH CTE AS (SELECT b.status_id FROM USER_ROLE b
WHERE (b.ACTIVE = 1 OR ( b.ACTIVE IN ( 0,3 )
AND SYSDATE BETWEEN b.effective_from_date AND b.effective_to_date
))
)
SELECT
r.user_id, r.role_id, r.participant_code, MAX(status_id)
FROM
user_role r,
cmp_role c
WHERE
r.role_id = c.role_id
AND r.participant_code IS NOT NULL
AND c.group_id = 3
GROUP BY
r.user_id, r.role_id, r.participant_code
HAVING MAX(status_id) IN (select * from CTE)
首先是子查询
SELECT b.status_id FROM USER_ROLE b
WHERE (b.ACTIVE = 1
OR ( b.ACTIVE IN ( 0,3 )
AND SYSDATE BETWEEN b.effective_from_date AND b.effective_to_date )
)
除了全表扫描之外,没有其他方法可以获得该结果。
您可能缺少一个连接,但不知道您希望查询做什么,我们无法告诉您
其次,根据组id为3的cmp_角色记录的比例,以及与这些角色不匹配的用户_角色的比例,在那里进行完整扫描可能会更好。例如,如果27个cmp_角色记录中有3个在组3中,并且100000个用户_角色记录与这些cmp_角色记录匹配,那么对表进行一次扫描可能比执行100000个索引查找更有效。首先,您有子查询
SELECT b.status_id FROM USER_ROLE b
WHERE (b.ACTIVE = 1
OR ( b.ACTIVE IN ( 0,3 )
AND SYSDATE BETWEEN b.effective_from_date AND b.effective_to_date )
)
除了全表扫描之外,没有其他方法可以获得该结果。
您可能缺少一个连接,但不知道您希望查询做什么,我们无法告诉您
其次,根据组id为3的cmp_角色记录的比例,以及与这些角色不匹配的用户_角色的比例,在那里进行完整扫描可能会更好。例如,如果27个cmp_角色记录中有3个在组3中,并且100000个用户_角色记录与这些cmp_角色记录匹配,然后,对表进行一次扫描可能比进行100000次索引查找更有效。我认为以下方法会起作用。我本以为子查询只会计算一次,因为它不相关-似乎不是这样。我在sh演示模式中对sales表进行了类似的查询(简单)。我对它进行了修改,使用了具体化的CTE方法,它只运行了1秒,而不是18秒。有关方法,请参见下文。速度快了10倍
with cte as (
select /*+materialize*/ max(amount_sold) from sales)
select prod_id,sum(amount_sold) from
sales
group by prod_id
having max(amount_sold) in(
select * from cte)
/
因此,在您的例子中,您将子查询具体化为
with CTE as (
SELECT /*+ materialize */ b.status_id FROM USER_ROLE b
WHERE (b.ACTIVE = 1 OR ( b.ACTIVE IN ( 0,3 )
AND SYSDATE BETWEEN b.effective_from_date AND b.effective_to_date
))
)
)
然后在主查询中从CTE中选择。我认为以下方法会起作用。我原以为子查询只会被计算一次,因为它不相关-情况似乎不是这样。我在sh演示模式中对sales表尝试了类似的查询(简单)。我对它进行了修改,使用了具体化的CTE方法,它只运行了1秒,而不是18秒。有关方法,请参见下文。速度快了10倍
with cte as (
select /*+materialize*/ max(amount_sold) from sales)
select prod_id,sum(amount_sold) from
sales
group by prod_id
having max(amount_sold) in(
select * from cte)
/
因此,在您的例子中,您将子查询具体化为
with CTE as (
SELECT /*+ materialize */ b.status_id FROM USER_ROLE b
WHERE (b.ACTIVE = 1 OR ( b.ACTIVE IN ( 0,3 )
AND SYSDATE BETWEEN b.effective_from_date AND b.effective_to_date
))
)
)
然后从主查询中的CTE中进行选择,这样您的查询当前需要16.5秒,并且您希望它运行得更快。要做到这一点,你需要知道这16.5秒花在哪里。Oracle数据库的检测非常好,因此您可以非常详细地看到它在做什么。你可以查看我在OTN论坛上写的这个帖子: 不知道你的时间花在哪里,所有的努力都只是猜测 问候,,
Rob.因此,您的查询当前需要16.5秒,您希望它运行得更快。要做到这一点,你需要知道这16.5秒花在哪里。Oracle数据库的检测非常好,因此您可以非常详细地看到它在做什么。你可以查看我在OTN论坛上写的这个帖子: 不知道你的时间花在哪里,所有的努力都只是猜测 问候,,
Rob。我没有足够的权限运行统计数据。解释计划屏幕截图我想发布,但我没有足够的分数(10)要求tp发布图片:(我提供了解释计划我没有足够的权限运行统计数据。解释计划屏幕截图我想发布,但我没有足够的分数(10)要求tp发布图片:(我已经提供了explain planFull表扫描不一定是坏事。它可能是获取数据的最有效的方式。此查询是否花费太多时间运行?还有,有多少不同的ACTIVE值?是的,运行需要19秒,并产生39392行。有6个不同的ACTIVE值,范围从0到5在您需要向cte select添加/*+materialze*/hint之前,请参阅我提供的示例完整表扫描不一定是件坏事。它可能是获取数据的最有效方式。此查询是否花费太多时间运行?还有,有多少不同的ACTIVE值?是的,运行需要19秒,并产生39392行。t这里有6个不同的活动值,范围从0到5,正如我前面提到的,您需要向cte选择添加/*+Materialize*/hint。请参见我提供的示例。在我的案例中,这种方法的时间为四倍。我没有您的表,所以我不能确定。但是当我尝试对sh数据库(918843)进行类似的选择时记录cte查询在几秒钟内完成,而另一个查询需要18秒。在您的情况下,cte查询不可能是最坏情况下的四倍,它应该会产生最小的降级。您是否在提示名称或其他内容上键入?针对900000条记录运行的查询(您的情况)应该在5秒内运行。抱歉,早上我发布评论时一定是做错了什么。我刚刚尝试了一下,大约花了16.5秒。我用新的查询编辑了问题。请注意,您没有使用/*+materialize*/提示进行预验证:)现在我知道为什么在我的pl/sql开发人员中删除了它。添加该提示会使查询真正爬行。这种方法会使我的时间缩短四倍。我没有你的表,所以我不能确定。但是当我尝试类似的对sh数据库(918843)的选择时,会记录cte查询