对此查询运行解释计划我正在获取全表访问权。
使用的两个表是:
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)
答案 0 :(得分:3)
首先你有子查询
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 )
)
除了全表扫描之外,您无法执行任何操作来获得该结果。 你可能错过了一个联接,但不知道你希望你的查询做什么,我们无法告诉你。
其次,根据group_id为3的cmp_role记录的比例,以及user_role与这些角色匹配的比例,最好在那里进行全面扫描。例如,如果27个cmp_role记录中有3个在第3组中,并且100,000个user_role记录与那些cmp_role记录匹配,那么对表执行单次扫描比执行100,000次索引查找更有效。
答案 1 :(得分:0)
答案 2 :(得分:0)
我认为以下方法会起作用。我认为子查询只会被评估一次,因为它没有相关性 - 这似乎不是这样的。我在sh演示中对销售表尝试了类似的查询(简单)架构。我将其修改为使用物化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
))
)
)
并在主查询中选择FROM CTE
答案 3 :(得分:0)
所以你有一个目前需要16.5秒的查询,你希望它运行得更快。要做到这一点,你需要知道花费16,5秒的位置。 Oracle数据库配备非常好,因此您可以非常详细地了解它正在做什么。您可以查看我在OTN论坛上写的这个帖子:
http://forums.oracle.com/forums/thread.jspa?messageID=1812597
不知道你的时间花在哪里,所有的努力都只是猜测......
此致 罗布。