【问题标题】:is there a tricky way to optimize this query有没有一种巧妙的方法来优化这个查询
【发布时间】:2010-07-14 15:42:14
【问题描述】:

我正在处理具有3008698 行的表

exam_date 是一个 DATE 字段。

但我运行的查询只想匹配月份部分。所以我要做的是:

select * from my_big_table where to_number(to_char(exam_date, 'MM')) = 5;

我认为这需要很长时间,因为该列上的功能。有没有办法避免这种情况并使其更快?除了更改表格?表中的exam_date 具有不同的日期值。比如 01-OCT-10 或 12-OCT-10...等等

【问题讨论】:

  • 你上面的 SQL 和 harpo 的 SQL 的计划会有所帮助。确保您的表格统计信息是最新的
  • 基本问题,但该表实际上是否有关于exam_date 的索引? (在进行范围检查时您的表现不同的事实表明确实如此)。 APC 关于全表扫描的评论很重要 - 如果您的数据均匀分布在 12 个月内,并且您需要返回 3008698 行的 1/12,则全表扫描可能是最好的 - 还有大量数据。加快全扫描速度的一种方法是查看 Oracle 的 /*+ PARALLEL */ 提示(它将全扫描划分到你的 CPU 上)——但需要重新组装结果的成本。

标签: oracle optimization date


【解决方案1】:

我不知道Oracle,但是做什么

WHERE exam_date BETWEEN first_of_month AND last_of_month

其中两个日期是常量表达式。

【讨论】:

  • 正在做:exam_date between To_date('11/01/2010','MM/DD/YYYY') and to_date('11/30/2010','MM/DD/YYYY') 实际上需要更长的时间...
【解决方案2】:
select * from my_big_table where MONTH(exam_date) = 5

哎呀.. Oracle 嗯?..

select * from my_big_table where EXTRACT(MONTH from exam_date) = 5

【讨论】:

  • +1 Oracle 有几个有效的日期处理方法,您应该在 WHERE 中使用它们,因为它们可以以奇怪的方式使用索引。
  • @learn_plsql 这有多快? Oracle 仍然需要进行全表扫描。您是否尝试过基于函数的索引?它可能有帮助,也可能没有帮助,因为数据最多有 12 个不同的值。
【解决方案3】:

请记住,由于您需要大约 1/12 的所有数据,因此 Oracle 执行全表扫描可能更有效。这可以解释为什么当你听从 harpo 的建议时性能会变差。

为什么?假设您的数据是每个数据库块(平均)适合 20 行,因此您总共有 3,000,000/20 = 150,000 个块。这意味着全表扫描将需要 150,000 次块读取。现在大约 1/12 的 3,000,000 行将用于第 05 个月。3,000,000/12 是 250,000。因此,如果您使用索引,那就是 250,000 次表读取——这忽略了也需要的索引读取。所以在这个例子中,全表扫描比索引搜索做的工作要少得多。

【讨论】:

  • 嗯,当我输入我的答案时,您发布了一个也以“记住”开头的答案,表达了完全相同的观点。伟大的思想和所有这些;)
【解决方案4】:

请注意,MONTH 只有十二个不同的值。因此,除非您有一组高度聚集的记录(例如,如果您使用分区),否则使用索引可能不一定是这种方式的最有效查询方式。

我没有发现使用 EXTRACT() 会导致优化器在我的日期列上使用常规索引,但是 YMMV:

SQL> create index big_d_idx on big_table(col3) compute statistics
  2  /

Index created.

SQL> set autotrace traceonly explain

SQL> select * from big_table
  2  where extract(MONTH from col3) = 'MAY'
  3  /

Execution Plan
----------------------------------------------------------
Plan hash value: 3993303771

-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           | 23403 |  1028K|  4351   (3)| 00:00:53 |
|*  1 |  TABLE ACCESS FULL| BIG_TABLE | 23403 |  1028K|  4351   (3)| 00:00:53 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(EXTRACT(MONTH FROM INTERNAL_FUNCTION("COL3"))=TO_NUMBER('M
              AY'))

SQL>

在这些场景中可以说服优化器使用索引的绝对是构建基于函数的索引:

SQL> create index big_mon_fbidx on big_table(extract(month from col3))
  2  /

Index created.

SQL> select * from big_table
  2  where extract(MONTH from col3) = 'MAY'
  3  /

Execution Plan
----------------------------------------------------------
Plan hash value: 225326446

-------------------------------------------------------------------------------------------
| Id  | Operation                   | Name          | Rows  | Bytes | Cost (%CPU)|Time    |
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |               | 23403 |  1028K|   475   (0)|00:00:06|
|   1 |  TABLE ACCESS BY INDEX ROWID| BIG_TABLE     | 23403 |  1028K|   475   (0)|00:00:06|
|*  2 |   INDEX RANGE SCAN          | BIG_MON_FBIDX |  9361 |       |   382   (0)|00:00:05|
-------------------------------------------------------------------------------------------


Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access(EXTRACT(MONTH FROM INTERNAL_FUNCTION("COL3"))=TO_NUMBER('MAY'))

SQL>

【讨论】:

    【解决方案5】:

    函数调用意味着 Oracle 将无法使用可能在列上定义的任何索引。

    要么删除函数调用(如 harpo 的回答),要么使用基于函数的索引。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多