在Oracle SQL中执行日期查询的最快方法是什么?

时间:2018-01-07 07:57:07

标签: sql oracle query-optimization

我们有一个6B行表,在检索数据时给我们带来了挑战。

我们的查询在执行...

时立即返回值
as_completed

这种即时结果正是我们所需要的。我们现在想过滤以接收特定年份的值 - 但是我们添加的那一刻......

SELECT * WHERE Event_Code = 102225120

...查询需要10分钟才能开始返回任何值。

Another SO post提到索引在拉动多行而不是单个行时不一定有助于查询日期。还有其他方法,如使用TRUNC或BETWEEN,或指定YYYY-MM-DD格式的日期时间进行比较。

值得注意的是,我们没有选择向数据库添加索引,因为它是供应商的数据库。

添加日期过滤查询并使Oracle能够以最快的方式开始流式传输结果的方法是什么?

5 个答案:

答案 0 :(得分:1)

  

另一篇SO帖子提到索引在拉动多行而不是单行时必然有助于查询日期

这个问题与你的问题完全不同。首先,您的上述声明适用于任何数据类型,而不仅仅是日期。此词很多也与表格中的记录数量有关。如果优化程序确定查询将返回表中所有记录的很多,那么它可能会确定对表的完整扫描比使用索引更快。在您的情况下,这会转换为表中所有记录中2017年的记录数量?此计算为您提供查询的基数,然后您可以了解索引是否更快。

现在,如果您决定索引会更快,基于上述内容,下一步就是知道如何构建索引。为了使优化器使用索引,它必须与您正在使用的条件匹配。您没有比较查询中的日期,而只是比较年份部分。因此,此查询不会使用日期列的索引。您需要在年份部分创建索引,因此请使用相同的条件来创建索引。

  

我们没有选择将索引添加到数据库,因为它是供应商的数据库。

如果无法修改数据库,则无法优化查询。您需要与供应商交谈并获得修改数据库的权限,或要求他们为您添加索引。

答案 1 :(得分:1)

函数也会导致所涉及的记录数量变慢。不确定基于功能的索引是否可以帮助您,但您可以尝试。

您是否曾尝试在表格中添加年份列?如果没有,请尝试添加年份列并使用以下代码进行更新。

UPDATE table
   SET year = EXTRACT(YEAR FROM PERFORMED_DATE_TIME);

这需要时间。

但在此之后,您可以运行以下查询。

 SELECT * 
   FROM table 
  WHERE Event_Code = 102225120 AND year = 2017;

另外,请尝试考虑Table Partitioned这个大数据。首先,请参阅下面的链接,

link:https://oracle-base.com/articles/8i/partitioned-tables-and-indexes

答案 2 :(得分:0)

你的问题有点模糊恕我直言:

  

但是我们添加的那一刻......       和提取(年度来自PERFORMED_DATE_TIME)= 2017年   ...查询需要10分钟才能开始返回任何值。

你的意思是

SELECT * WHERE Event_Code = 102225120

很快,但是

SELECT * WHERE Event_Code = 102225120 AND EXTRACT(YEAR FROM PERFORMED_DATE_TIME) = 2017

很慢???

对于初学者,我同意Mitch Wheat,你应该尝试在2017年1月1日到2017年12月31日之间使用PERFORMED_DATE_TIME而不是年份(字段)= 2017.即使你有一个索引在球场上,后者几乎无法利用它,而第一种方法将大大受益。

我也希望你想要更具体而不仅仅是“给我2017年的全部时间”,因为返回超过1B行绝对不会很快。

接下来,如果您无法对数据库进行更改,您是否能够在另一个数据库中维护“阴影”?这将要求您在另一个数据库中创建一个包含所有日期值和原始表的PK的表,并查询这些表以查找相关的PK值,然后将这些值重新连接到原始表以查找所需的任何内容。最大的问题是你需要保持阴影与原始表同步。如果您知道原始表只在一夜之间更改,您可以在早上合并更改并查询整天。如果应用程序是“实时(ish)”,那么如果没有一些聪明的想法,这可能是行不通的......是的,你初始加载的6B值会相当沉重=)

答案 3 :(得分:0)

这可能是有用的(因为你避免了函数(上下文切换的原因),如果你的日期字段有索引,可以使用它):

with 
dt as
(
select
        to_date('01/01/2017', 'DD/MM/YYYY') as d1,    
        to_date('31/01/2017', 'DD/MM/YYYY') as d2    
       from dual
),  
   dates as
(
select 
        dt.d1 + rownum -1 as d
from dt
connect by dt.d1 + rownum -1 <= dt.d2
)
select *
from your_table, dates
where  dates.d = PERFORMED_DATE_TIME

答案 4 :(得分:-1)

将日期文字移动到RHS:

AND PERFORMED_DATE_TIME >= date '2017-01-01' 
AND PERFORMED_DATE_TIME < date '2018-01-01'

但如果PERFORMED_DATE_TIME没有(未公开的)适当的索引,查询就不会更快。

在第三方数据库中创建索引的一个选项是在索引中编写脚本,然后在任何供应商升级之前运行脚本以删除您添加的任何索引。如果索引很重要,请要求供应商将其添加到数据库设计中。