2016-06-16 50 views
0

我有一个表,其中我跟踪事件及其发生日期。 在某些情况下,事件发生的日期为空(甚至是尚未发生,但已注册)日期,空值和索引

快速统计:所有事件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。也许这将有助于分析 执行计划: 所有的execution plan

+0

为什么不使用默认值(例如2033-01-01,您使用NVL动态填充)设置空日期值?这似乎是解决大部分问题的好方法。 –

+0

另一种解决方案可以将查询拆分为两部分 - 其中一个日期为空的部分,其自然会较慢(因为没有明显的过滤器并且它是大部分数据 - 因此索引不是选项),而另一个日期不为空,它将使用索引来查询日期特定的事件。 –

+0

不幸的是我不能影响表格填充的方式,所以我必须照原样工作。关于分成两行的 ,我只能使用一个sql查询,而我提供的上一部分是我在较大选择中使用的JOIN之一。所以这也无济于事。感谢您的建议 – user2858200

回答

1

首先建立索引后 - 你分析的指标?

假设你有 - 你没有提到你正在运行的查询类型。 如果查询参数正在搜索NULL - 我不会惊讶于优化器选择使用索引范围扫描的全表扫描。 因此,大部分记录集都有一个空日期值。

您也可以使用提示来强制使用索引 即。/* + index(events_table_idx)*/

但是您需要仔细查看性能统计信息以确定哪种方式是检索数据的最有效方式。

+0

在结果sql select中没有'where event_occurred_date is NULL'部分,它应该符合一般模式:当用户输入'*'时应该是 - 然后我应该跳过检查'event_occurred_date'(意思是,无论是否发生过日期,包括空值),当用户输入一个日期,那么它应该检查输入的日期。 是的,我试着指定索引提示,它仍然使用全表扫描,我认为这是比索引范围扫描更快。 – user2858200