【问题标题】:Making use of an index on a VARCHAR2 field where the VARCHAR2 is a date在 VARCHAR2 是日期的 VARCHAR2 字段上使用索引
【发布时间】:2017-03-08 04:13:56
【问题描述】:

我有一个包含 LETTER_SENT 日期字段的 Oracle 表。 LETTER_SENT 是一个 varchar2 字段,是一个 yyyymmdd 的文本字符串(所以 20140708 表示这封信是在 2014 年 7 月 8 日发送的)。注意:这不是我的表,我只有对 SELECT 的授权,所以我不能将它强制为 yyyymmdd 日期。

我经常需要查找在某个日期范围内发送的信件。通常,我会在 WHERE IN('开始日期',...,'结束日期')​​。根据我对 SQL 的了解,这样做不会以任何不会影响索引使用的方式修改字段(而转换为日期或数字然后进行比较会影响索引)。

性能方面,这很好。但是,有时我的日期范围非常大,并且在 WHERE 语句中有一个庞大的 IN、...OR IN、... OR IN 子句就像罪恶一样丑陋。

当日期是索引 varchar2 时,是否还有另一种语法上更漂亮但仍然有效的方法来在 where 子句(date_begin 和 date_end 之间的日期)中进行日期比较?

【问题讨论】:

  • 你试过letter_sent >= '20160101' and letter_sent <= '20160430'吗?我想知道包含此类数字的索引字符串如何提取数据。也许它是高性能的——我不知道。只是好奇你是否尝试过。
  • @zedfoxus 这工作得更好 - 我不敢相信我忘记了这个工作!请将此作为答案发布,以便我可以投票并接受它,我的头说我忘记了这个。
  • Tom Kyte 有一个非常令人信服的会议演示(我曾在 OTN 上的一个线程中看到一个链接) - 他展示了具体示例,说明应该对日期进行编码的 VARCHAR2 列上的索引如何表现得非常糟糕与正确的 DATE 列上的索引相比 - 完全相同的数据(除了该列的不同数据类型)。不要使用VARCHAR2 作为日期;这是 100 多个绝佳理由之一。
  • 这是一个非常简单的例子。想象一下有两个日期。优化器将尝试生成行数的基数估计。当存储为 VARCHAR2 时。 20170101 - 20161230 是 8871。实际上该值应该是 1。
  • @Joe 我已经添加了我的答案,还包括了其他评论者提供的相同建议 - 使用日期字段而不是 varchar2 以获得长期有效性。

标签: sql oracle


【解决方案1】:

执行此操作的正确方法是使用 DATE 数据类型而不是 VARCHAR2() 存储 LETTER_SENT。在语法、索引的使用、结果的正确性、优化器统计信息和最终的性能方面,你会做得更好。

【讨论】:

  • 相信我,我知道 - 这不是我的桌子:/。我不知道为什么表创建者选择这样做。我将编辑原件以反映这一点。无论如何,投票让以后来的任何人都知道如何不这样做:)
  • @乔。我高度鼓励您回到表格创建者那里解决这个问题。因此,我已经数不清升级的次数了。此外,由于类型转换,您将隐式禁用 Oracle 优化。如果创作者拒绝;去找他们的经理!!
  • 我会向他们提及,但我不希望有任何改变。大公司行动缓慢,没有任何改变。
【解决方案2】:

由于您在 varchar2 字段上有一个索引,我相信您将能够使用这样的查询:

select * from tablename
where letter_sent >= '20160101' and letter_sent <= '20160430'

文本可以按顺序处理,您可以通过使用索引获得期望的结果。

从长远来看,将letter_sent_date 创建为日期字段,使用来自letter_sent 的数据更新此字段,然后弃用letter_sent 将是有效的。您将受益于使用以日期为中心的函数,例如 year(letter_sent_date),而不是需要将 varchar2 字段转换为日期然后应用函数。

【讨论】:

  • @Joe - 还有无数其他好处。想象一下,如果日期为 varchar2 数据类型,那么确定后续信件是否在 10 个工作日内发出是多么容易!
  • 很高兴知道为什么答案会遭到反对。我想知道这个答案是否可以改进。
  • 因鼓励“不良行为”而被否决。客户应使用正确的数据类型。请参阅下面的答案。另请参阅我上面的评论/示例,了解为什么这很糟糕。
  • @BobC 明白了。我很感激。我的目的是在知道 OP 的情况后立即提供救济,并在我的最后一段中建议使用日期数据类型。我非常感谢您的评论,并将继续记住它。
猜你喜欢
  • 2019-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-29
  • 2019-06-29
  • 2011-07-28
  • 2020-06-23
相关资源
最近更新 更多