查询需要更长的时间来执行

时间:2018-04-16 08:31:53

标签: oracle subquery

是否有任何方法可以减少从查询中获取结果所需的时间? 请帮忙。提前谢谢!

select status, count(distinct id)
from emp
where id >=
      ( select min(id)
        from emp
        where id >= (select max(id-200000) from emp)
           and trunc(join_date) >= '01-Mar-2018')
group by status;

2 个答案:

答案 0 :(得分:3)

使用分析函数 - 这将只执行一次表扫描(而您的查询有三个表/索引扫描):

SELECT status,
       COUNT( DISTINCT id )
FROM   (
  SELECT status,
         id,
         MIN( CASE WHEN join_date >= DATE '2018-03-01' THEN id END ) OVER () AS min_id
  FROM   (
    SELECT status,
           id,
           join_date,
           MAX( id ) OVER () AS max_id
    FROM   emp
  )
  WHERE  id >= max_id - 20000
)
WHERE  id >= min_id
GROUP BY status;

此外,您可以使用日期文字(而不是依赖于使用NLS_DATE_FORMAT会话参数将字符串隐式转换为日期),并且您不需要使用TRUNC()函数(因为这可能会阻止Oracle在join_date列上使用索引,而是需要基于函数的索引。

答案 1 :(得分:0)

重要的是要知道id是否是主键(通常是具有该名称的列)。如果不是,你肯定需要一个id的索引才能执行(我也想知道该列的用途是什么)。如果id是主键,则不需要distinct,因为值无论如何都是唯一的。

select min(id)子选择是多余的,因为您已经找到max(id - 200000),因此您不需要知道大于该值的第一个min(id)。您可以单独使用> =(添加日期的条件)。顺便说一句,我会写max(id) - 200000代替;在一些数据库上,它可能会更好。

日期比较可能有问题。你应该在join_date上尝试一个索引,如果你还没有索引,但trunc可能会阻止它被使用,所以最好删除它并进行比较的另一面使用TO_TIMESTAMPTO_DATE根据需要生成相应的文字,将时间设置为午夜。

但是由于时区等原因,比较时间戳可能会出现问题。我需要了解更多有关您的设置的信息,以了解这是否可能是一个问题。