【发布时间】:2016-06-16 09:01:22
【问题描述】:
我有一张桌子,我可以在其中跟踪事件及其发生日期。 在某些情况下,事件发生日期为空(甚至尚未发生,但已注册)
快速统计:所有事件 390k 行,其中 252k 具有空日期
所以我在根据用户请求提取数据时遇到问题: 1. 用户可能想要尚未发生的拉取事件; (用户输入 *) 2. 用户可以拉取超过特定日期发生的事件; 3. 用户可以拉取超过特定日期发生的事件+尚未发生的事件;
我正在构建动态 sql 查询,类似于
select
even_id,
event_registered_date,
event_name,
event_occurred_date
from
events_table
where
NVL(event_occurred_date, to_date('2033-01-01','yyyy-mm-dd')) >= coalesce(to_date(replace(:p1, '*', NULL),'yyyy-mm-dd'),event_occurred_date,to_date('2033-01-01','yyyy-mm-dd'))
...--other filter conditions are here
这个sql最耗费成本的部分是日期过滤器。我尝试创建基于函数的索引trunc(event_occurred_date),甚至包括空值trunc(NVL(event_occurred_date,to_date('2033-01-01','yyyy-mm-dd'))),它仍然使用全表扫描。
我确信有更巧妙的方法可以解决这个问题,但我就是看不到。 提前致谢
添加: 我刚刚与表所有者交谈,他们告诉我,在任何给定时间,至少有一半的事件对于 event_occurred_date 将具有 nulls。也许这将有助于分析 执行计划是:
【问题讨论】:
-
您为什么不使用默认值设置您的空日期值(例如 2033-01-01 您正在使用 NVL 动态填充)?这似乎是解决您大多数问题的好方法。
-
另一种解决方案可以将查询分为两部分 - 一个日期为空的部分,这自然会更慢(因为没有明显的过滤器并且它是大部分数据 - 所以索引不是一个选项)和另一个日期不为空的地方,它将使用索引来查询日期特定事件。
-
不幸的是,我无法影响表格的填充方式,所以我必须按原样工作。关于分成两行,我只能使用一个 sql 查询,而我提供的上部部分是我在更大的选择中使用的 JOIN 之一。所以这也无济于事。谢谢你的建议
-
有了空值的比例,你的第一个和第三个场景无论如何都不会从索引中受益——全表扫描会更快,因为无论如何你都必须检索这么多的表块。 (除非其他条件可以使用索引,这无论如何都没有实际意义)。第二种情况可能会受益于该列上的简单索引,但如果是这样,单独查询可能会更简单 - 这可行吗?其他条件是否更具选择性和索引列?
-
关于拆分成两行,我只能使用一个 sql 查询,而我提供的部分上部是我在更大的选择中使用的 JOIN 之一(它们有 PK 索引,它们的成本是最小(小于 3)。
标签: sql oracle performance