我需要帮助优化以下查询。这需要很长时间才能完成。这需要将近213秒。由于一些限制,我无法添加索引,必须与现有索引一起使用。
INSERT INTO temp_table_1
( USER_ID, role_id, participant_code, status_id )
WITH A AS
(SELECT USER_ID user_id,ROLE_ID, STATUS_ID,participant_code
FROM USER_ROLE WHERE participant_code IS NOT NULL), --1
B AS
(SELECT ROLE_ID
FROM CMP_ROLE
WHERE GROUP_ID = 3),
C AS (SELECT USER_ID FROM USER) --2
SELECT USER_ID,ROLE_ID,PARTICIPANT_CODE,MAX(STATUS_ID)
FROM A INNER JOIN B USING (ROLE_ID)
INNER JOIN C USING (USER_ID)
GROUP BY USER_ID,role_id,participant_code ;
--1 = query when ran alone takes 100+ seconds
--2 = query when ran alone takes 19 seconds
DELETE temp_table_1
WHERE ROWID NOT IN
( SELECT a.ROWID
FROM temp_table_1 a,
USER_ROLE b
WHERE a.status_id = b.status_id
AND ( b.ACTIVE IN ( 1 ) OR ( b.ACTIVE IN ( 0,3 )
AND SYSDATE BETWEEN b.effective_from_date AND b.effective_to_date ))
);
编写查询的人似乎首先尝试将所有内容放入临时表,然后从临时表中删除记录。剩下的就是实际的结果。
不能这样做,不需要删除吗?我们只是得到了所需的结果,因为这样可以节省时间吗?
答案 0 :(得分:2)
这是一个天真地结合上述两个查询的查询,因此请确保检查并比较两种方法的输出。
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.active in (0,1,3)
and r.participant_code is not null
and sysdate between r.effective_from_date and r.effective_to_date
and c.group_id = 3
group by
r.user_id, r.role_id, r.participant_code;
没有必要使用临时表,然后删除记录以获得所需的结果。虽然,可能有其使用的原因,也许表现?
此外,由于USER
可以从USER_ID
获得,因此查询和加入USER_ROLES
表格似乎是不必要的。我在上面的查询中省略了它。希望这能为你提供一个良好的开端。
答案 1 :(得分:0)
在现有代码中删除之后,这应该在语义上等同于临时表中的左边的集合。虽然我同意AR,但不需要User表,除非它包含的user_id比user_role少。否则它不会以任何方式限制集合。如果User包含的user_id比user_role多,则不会更改结果集。 User_role是此查询中的主要驱动程序,具有来自cmp_role表的小限制。
select a.user_id,
a.role_id,
a.participant_code,
a.status_id
from (select a.user_id,
a.role_id,
a.participant_code,
max(status_id) status_id
from user_role a,
(select role_id
from cmp_role
where group_id = 3
) b
where a.participant_code is not null
and a.active in (0, 1, 3)
and sysdate between a.effective_from_date and a.effective_to_date
and a.role_id = b.role_id
group by a.user_id,
a.role_id,
a.participant_code
) a
user c
where a.user_id = c.user_id;
如果性能仍然很差,则可能会查看用于限制数据的某些字段的索引(user_role.role_id,user_role.participant_code,user_role.active,user_role.effective_from_date,user_role.effective_to_date)。
当然,需要一个解释计划或跟踪来全面了解Oracle在根据您的数据和结构执行此查询时所做的工作。
答案 2 :(得分:0)
让我们指出一些显而易见的事情。
- 1 =单独运行时的查询需要100多秒
- 2 =单独运行时查询需要19秒
USER表上的全表扫描不应该花费19秒。 USER_ROLE表上的全表扫描不应超过100秒,即使它有数千万行。当然,如果你真的有两千万用户,那么这些时间稍微不那么不合理,但仍然不能接受。
您需要了解为什么系统需要这么长时间才能进行简单的查找。 EXPLAIN PLAN希望我们理解连接,但这不会解决您的核心问题:为什么检索USER_ROLE数据需要这么长时间?这是一个复杂的观点吗?它有数以亿计的查询吗?您是否有PARTICIPANT_CODE的索引对此查询没有帮助?
使用这些表的其他查询怎么样?它们也有问题吗?如果是这样,您需要进行更多调查。无论是系统花了太长时间做某事还是等待某些资源。您需要做的是针对此查询运行10046跟踪并确定时间的位置。此跟踪将报告您的会话的等待事件。这将为您提供一些有关进展的正确信息。它比猜测要好得多。
自从9i以来,Oracle已经公开了Wait Interface。罗杰施拉格写了一篇相当不错的介绍。 Read it now。 (如果你是10g或更高,你也应该阅读his follow-up article)。