查询优化(使用联接而不是子查询)

  • 本文关键字:查询 查询优化 sql
  • 更新时间 :
  • 英文 :


我需要这个查询的帮助。我需要提高查询的执行时间。有什么建议可以改进和优化它吗?我认为子查询是其中最有问题的部分。知道如何更改它并使其更快吗?

select pro.ID,lt.TASK_ID,lt.ACTIVITY_NAME, lt.CREATION_TIME as START_TIME, lt.END_TIME, lum.USERNAME, to_char((lt.END_TIME-lt.CREATION_TIME),'dd.MM.yyyy HH24:mm:ss')  AS TASK_DURATION
from pdw_lsw_tracking_point tp, pdw_lsw_tracking_point_value tpv, pdw_tg_processtable pro, pdw_lsw_task lt, pdw_lsw_user_mappings lum
where  tp.tracking_point_id=tpv.tracking_point_id
and pro.task_id = tpv.task_id
and lt.functional_task_id=tpv.task_id
and lt.SYSTEM_USER_ID = TO_CHAR(lum.USER_ID) AND lt.SYSTEM_ID = lum.SYSTEM_ID
and tp.TRACKING_GROUP_ID=tpv.TRACKING_GROUP_ID
and pro.ID IN (select pro.ID  from  pdw_tg_processtable pro where step=13 and time_stamp between  '01.03.21' and  '08.03.21')
group by pro.ID,lt.TASK_ID,lt.ACTIVITY_NAME, lt.CREATION_TIME, lt.END_TIME, lum.USERNAME
order by pro.ID,lt.CREATION_TIME;
select pro.ID, lt.TASK_ID, lt.ACTIVITY_NAME, lt.CREATION_TIME as START_TIME, lt.END_TIME, lum.USERNAME, to_char((lt.END_TIME-lt.CREATION_TIME),'dd.MM.yyyy HH24:mm:ss')  AS TASK_DURATION
from pdw_lsw_tracking_point tp, 
JOIN pdw_lsw_tracking_point_value as tpv ON tp.tracking_point_id=tpv.tracking_point_id
JOIN pdw_tg_processtable as pro ON pro.task_id = tpv.task_id
JOIN pdw_lsw_task as lt ON lt.functional_task_id=tpv.task_id
JOIN pdw_lsw_user_mappings as lum ON lum.SYSTEM_ID = lt.SYSTEM_ID 
where lt.SYSTEM_USER_ID = TO_CHAR(lum.USER_ID) 
and tp.TRACKING_GROUP_ID=tpv.TRACKING_GROUP_ID
and pro.ID IN (select pro.ID  from  pdw_tg_processtable pro where step=13 and time_stamp between  '01.03.21' and  '08.03.21')
group by pro.ID,lt.TASK_ID,lt.ACTIVITY_NAME, lt.CREATION_TIME, lt.END_TIME, lum.USERNAME
order by pro.ID,lt.CREATION_TIME;

您使用的是一种古老的联接语法,没有明显的原因。要做的第一件事是清理它,并使用1992年标准SQL中引入的正确联接(INNER JOIN ... ON(。

然后有三件事会立即引起人们的注意:

  1. 有时在user_id上使用TO_CHAR,有时不使用。该列应以相同的方式(即使用相同的数据类型(存储在不同的表中。如果不是这样的话,访问可能会变得非常慢,因为可能不会使用索引
  2. 您在不使用聚合函数的情况下GROUP BY。这意味着你SELECT DISTINCT,只是有点模糊。这就引出了一个问题:为什么必须删除重复项?它们是如何产生的?你可能会用不恰当的连接自己制作它们吗?处理过大的中间结果并稍后删除重复项是一项成本高昂的操作
  3. 一个名为id的列应该是表的主键。那么,为什么要使用子查询来选择ID,而只是根据ID再次从同一个表中进行选择呢?你会得到完全相同的行。直接应用标准即可

仔细一看,您的查询中有两次表pdw_lsw_tracking_point_value,但您并没有真正使用它。tpvtask_id上连接,以链接prolt,但您也可以直接在task_id上连接prolttptracking_point_idtracking_group_id上加入,但随后不再使用tp

固定了user_id数据类型后,您可以得到以下内容:

select 
pro.id,
lt.task_id,
lt.activity_name,
lt.creation_time as start_time,
lt.end_time,
lum.username,
lt.end_time - lt.creation_time as task_duration
from pdw_tg_processtable pro 
join pdw_lsw_task lt on lt.functional_task_id = pro.task_id
join pdw_lsw_user_mappings lum on lum.system_id = lt.system_id
and lum.user_id = lt.system_user_id
where pro.step = 13 and pro.time_stamp between date '2021-03-01' and date '2021-03-21'
order by pro.id, lt.creation_time;

你想要这些索引:

create idx1 on pdw_tg_processtable (step, time_stamp, task_id, id);
create idx2 on pdw_tg_processtable (time_stamp, step, task_id, id);
create idx3 on pdw_lsw_task (functional_task_id, system_id, system_user_id);
create idx4 on pdw_lsw_user_mappings (system_id, system_user_id, username);
create idx5 on pdw_lsw_user_mappings (system_user_id, system_id, username);

(其中,您只需要idx1或idx2以及idx4或idx5。不过我不知道是哪一个。将它们全部创建并稍后删除未使用的。(

尝试修改您的子查询:

and exists
(select pt.ID
from pdw_tg_processtable pt
where step=13
and time_stamp between '01.03.21' and '08.03.21'
and pt.id = pro.ID)

最新更新