在列值上使用trunc() 将阻止使用该列上的索引(除非它是基于函数的索引)。最好使用日期范围,涵盖您感兴趣的一整天。将时间偏移量添加到start_date 也会影响索引;并且'10-Feb-2020' 是一个字符串而不是日期,因此您正在强制进行隐式转换——这绝不是一个好主意。你也不需要distinct 和union 一样(不像union all),无论如何都会消除重复。
我建议以这样的方式作为起点:
select car_no, start_date
from tab_1
where source_point = end_point
and start_date >= date '2020-02-10' - actual_arrival_time * interval '1' minute
and start_date < date '2020-02-11' - actual_arrival_time * interval '1' minute
union
select car_no, start_date
from tab_2
where event_code='TD'
and actl_time_of_arrvl >= date '2020-02-10'
and actl_time_of_arrvl < date '2020-02-11'
actual_arrival_time * interval '1' minute 提供与ACTUAL_ARRIVAL_TIME END/1440 相同的效果;第一个是间隔数据类型,第二个是一天的一小部分,但两者都将分钟数表示为可以添加到日期值的值。
我正在使用仍然是硬编码的日期文字。如果您真的在使用参数,您可以将interval '1' day 添加到您想要的日期,而不是一天后硬编码。无论哪种方式,都会在第一个日期的午夜或之后查找值,并在第二个日期的午夜 before 查找值 - 这涵盖了当天所有可能的时间。
由于在范围计算中引用另一列值的可变性,第一个分支仍然无法真正正确使用索引,但如果您知道 actual_arrival_time 在 24 小时内,您可以帮助它更严格的限制:
select car_no,start_date
from tab_1
where source_point = end_point
and start_date >= date '2020-02-10'
and start_date < date '2020-02-10' + interval '2' day -- depending on allowed ranges
and start_date + actual_arrival_time * interval '1' minute >= date '2020-02-10'
and start_date + actual_arrival_time * interval '1' minute < date '2020-02-10' + interval '1' day
union
select car_no, start_date
from tab_2
where event_code='TD'
and actl_time_of_arrvl >= date '2020-02-10'
and actl_time_of_arrvl < date '2020-02-10' + interval '1' day
这里start_date >= date '2020-02-10' 为索引提供了搜索的下限(假设actual_arrival_time 不能为负数,这似乎是合理的); start_date < date '2020-02-10' + interval '2' day 给出一个上限。上限取决于允许的值,尤其是actual_arrival_time。
您的问题不清楚tab1.start_date 是否总是午夜,因此您可以将检查的第一部分简化为精确的日期匹配而不是范围。但是然后查看actual_arrival_time 可能就没有必要了......如果start_date 实际上总是午夜并且actual_arrival_time 被限制在0 到1440 之间,那么它可能很简单:
select car_no,start_date
from tab_1
where source_point = end_point
and start_date >= date '2020-02-10'
and start_date < date '2020-02-10' + interval '1' day
union
...
就像第二个分支一样。但是您尝试处理它的方式表明情况可能并非如此,您只需要尽可能缩小初始索引搜索范围,然后再根据确切时间进行过滤。我怀疑actual_arrival_time 可能代表几天,甚至几周或几个月;所以回到以前的版本,
and start_date < date '2020-02-10' + interval '2' day -- depending on allowed ranges
将扩展到您期望看到的最大值;或者可能完全省略。
您需要查看执行计划以了解它实际上在做什么,可能是针对整体查询和联合的每个分支。
如果您要经常这样做,可能值得将计算值 start_date + actual_arrival_time * interval '1' minute 添加到 tab1 作为虚拟列,并为其编制索引。