是否有任何方法可以减少从查询中获取结果所需的时间? 请帮忙。提前谢谢!
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;
答案 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_TIMESTAMP
或TO_DATE
根据需要生成相应的文字,将时间设置为午夜。
但是由于时区等原因,比较时间戳可能会出现问题。我需要了解更多有关您的设置的信息,以了解这是否可能是一个问题。