繁体   English   中英

在选择语句中对前几个月的数据使用 BETWEEN 与在 Oracle 中使用与 TO_CHAR 进行比较有什么好处?

[英]Is there a benefit to using BETWEEN in a select statement for a previous months data vs using a comparison with TO_CHAR in Oracle?

我正在修改 Oracle 中的一个查询,其中需要上个月的数据。 目前,该查询有一个 where 子句,其中包含以下内容:

...
...
...
WHERE cust_dt BETWEEN TO_DATE('05-01-2022','mm-dd-yyyy) AND TO_DATE('05-31-2022', 'mm-dd-yyyy')

我正在修改查询,以便不需要每月手动更改开始日期和结束日期来运行查询。 在做了一些研究之后,我想出了以下几点:

...
...
...
WHERE TO_CHAR(cust_dt, 'MM-YYYY') = TO_CHAR(add_months(sysdate, -1), 'MM-YYYY')

我得到的结果是我想要的,但我很好奇在给定更大的数据集的情况下哪个查询在性能方面会更好。 我在网上看到的所有帖子都使用了 BETWEEN,所以我想知道这是否有某种原因。

就调优、测试、性能等方面的查询而言,我是一个完全的新手。 实际的查询本身相当复杂,有几个连接,所以性能很重要。 目前,我只有少量的测试数据可以使用,所以我只能做些什么来找到最好的结果。

所以回到我的问题,哪个查询最好? 使用 BETWEEN 的那个,还是使用 TO_CHAR 的那个?

我建议不要使用您的两个查询之一。 第一个查询存在检查硬编码日期范围的问题。 这通常是应尽可能避免的风险。 第二个查询进行了从 date 到 char 的不必要转换,这可能会很慢。

您可以只使用常见的日期函数来获取上个月的数据。 根据您的描述,您的参考日期是当前日期,即sysdate。

为了排除由于时间导致的错误比较,您可以使用函数TRUNC从日期中删除时间。

函数ADD_MONTHS可用于返回一个月。

函数LAST_DAY可用于查找该月的最后一天。

把这些放在一起,你可以使用这样的 where 子句:

WHERE cust_dt BETWEEN ADD_MONTHS(TRUNC(sysdate,'mm'),-1) AND 
LAST_DAY(ADD_MONTHS(TRUNC(sysdate,'mm'),-1));

这将快速安全地执行,并避免不必要的转换或硬编码日期。 最后一点:考虑将上述查询更改为...

WHERE cust_dt BETWEEN ADD_MONTHS(TRUNC(sysdate,'mm'),-1)
AND TRUNC(sysdate,'MM')-INTERVAL '0.001' SECOND;

...取决于您是否需要上个月的最后一天。 请在此处查看差异并尝试: db<>fiddle

WHERE TO_CHAR(cust_dt, 'MM-YYYY') = TO_CHAR(add_months(sysdate, -1), 'MM-YYYY')

不会在cust_dt列上使用索引; 相反,您需要在TO_CHAR(cust_dt, 'MM-YYYY')上创建一个单独的基于函数的索引

WHERE cust_dt BETWEEN TO_DATE('05-01-2022', 'mm-dd-yyyy')
                  AND TO_DATE('05-31-2022', 'mm-dd-yyyy')

将在cust_dt列上使用索引。

然而,在 Oracle 中,一个DATE数据类型由 7 个字节组成,分别代表:世纪、世纪年、月、日、小时、分钟和秒。 总是有这些组件(但通常用于访问数据库的客户端应用程序将默认仅显示日期组件而不显示时间组件 - 但时间组件仍然存在)。

这意味着您的查询将找到cust_dt介于2022-05-01 00:00:002022-05-31 00:00:00之间的值。 它不会匹配cust_dt介于2022-05-31 00:00:012022-05-31 23:59:59之间的值。

所以回到我的问题,哪个查询最好?

两者都不。

您想要(如果您对日期进行硬编码):

WHERE cust_dt >= TO_DATE('05-01-2022', 'mm-dd-yyyy')
AND   cust_dt <  TO_DATE('06-01-2022', 'mm-dd-yyyy')

或者(如果您正在动态查找日期):

WHERE cust_dt >= ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -1)
AND   cust_dt <  TRUNC(SYSDATE, 'MM')

它将使用cust_dt上的索引并匹配该月的整个范围。

db<> 在这里摆弄

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM