【问题标题】:How to optimize oracle query?如何优化oracle查询?
【发布时间】:2017-06-15 09:01:16
【问题描述】:

以下查询在 oracle 11g 中大约需要 45 秒

select count(cap.ISHIGH),ms.SID,ms.NUM from CDetail cap,MData ms  
where cap.MDataID_FK=ms.MDataID_PK and trunc(cap.CREATEDTIME) between trunc(sysdate-10) and trunc(sysdate)
group by ms.SID,ms.NUM ;

解释计划:

    -------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                        | Name                   | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
    -------------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                 |                        |   766K|    32M|       | 94421   (1)| 00:18:54 |
    |   1 |  HASH GROUP BY                   |                        |   766K|    32M|    41M| 94421   (1)| 00:18:54 |
    |*  2 |   HASH JOIN                      |                        |   766K|    32M|    21M| 85716   (1)| 00:17:09 |
    |   3 |    VIEW                          | VW_GBC_5               |   766K|    13M|       | 73348   (1)| 00:14:41 |
    |   4 |     HASH GROUP BY                |                        |   766K|    13M|    98M| 73348   (1)| 00:14:41 |
    |*  5 |      FILTER                      |                        |       |       |       |            |          |
    |   6 |       TABLE ACCESS BY INDEX ROWID| CDetail         |  3217K|    58M|       | 63738   (1)| 00:12:45 |
    |*  7 |        INDEX RANGE SCAN          | IDX_CPCTYDTLTRNCCRTDTM |  3365K|       |       | 14679   (1)| 00:02:57 |
    |   8 |    TABLE ACCESS FULL             | MData       |   871K|    22M|       |  9665   (1)| 00:01:56 |
    -------------------------------------------------------------------------------------------------------------------
     
    Predicate Information (identified by operation id):
    ---------------------------------------------------
     
       2 - access("ITEM_1"="MS"."MDataID_PK")
       5 - filter(TRUNC(SYSDATE@!-10)<=TRUNC(SYSDATE@!))
       7 - access(TRUNC(INTERNAL_FUNCTION("CREATEDTIME"))>=TRUNC(SYSDATE@!-10) AND 
                  TRUNC(INTERNAL_FUNCTION("CREATEDTIME"))<=TRUNC(SYSDATE@!))

table MData contains around 900,000 rows and table CDetail contains 23,000,000 rows.

Should I introduce any new index or any other way to optimize the above query.

编辑 3. IDX_CPCTYDTLTRNCCRTDTM 是 trunc(CREATEDTIME) 上的功能索引 编辑:1

explain plan :for full table scan using hint /+full(Cdetail)/

---------------------------------------------------------------------------------------------------
| Id  | Operation              | Name             | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |                  |   780K|    33M|       |   160K  (2)| 00:32:01 |
|   1 |  HASH GROUP BY         |                  |   780K|    33M|    42M|   160K  (2)| 00:32:01 |
|*  2 |   HASH JOIN            |                  |   780K|    33M|    22M|   151K  (2)| 00:30:15 |
|   3 |    VIEW                | VW_GBC_5         |   780K|    13M|       |   138K  (2)| 00:27:46 |
|   4 |     HASH GROUP BY      |                  |   780K|    14M|   230M|   138K  (2)| 00:27:46 |
|*  5 |      FILTER            |                  |       |       |       |            |          |
|*  6 |       TABLE ACCESS FULL| CDetail   |  7521K|   136M|       |   120K  (2)| 00:24:02 |
|   7 |    TABLE ACCESS FULL   | MData |   890K|    22M|       |  9666   (1)| 00:01:56 |
---------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - access("ITEM_1"="MS"."MDataID_PK")
   5 - filter(TRUNC(SYSDATE@!-10)<=TRUNC(SYSDATE@!))
   6 - filter(TRUNC(INTERNAL_FUNCTION("CREATEDTIME"))>=TRUNC(SYSDATE@!-10) AND 
              TRUNC(INTERNAL_FUNCTION("CREATEDTIME"))<=TRUNC(SYSDATE@!))

【问题讨论】:

  • 您应该在CDetailMData 之间的连接列上添加索引,即MDataID_FKMDataID_PK 列。这应该会加快加入速度。
  • @TimBiegeleisen。为什么您认为该索引会有所帮助?
  • @BobC 好吧,无论是否有后续聚合,都必须执行连接,索引不会让这种情况更快发生吗?
  • @TimBiegeleisen。查看执行计划(现在我知道它是基于估计,但我们目前没有其他诊断可继续);时间花在哪里?它主要是操作 6 中的 TABLE ACCESS BY ROWID。这并不奇怪 - 我们正在执行大约 300 万个单块 IO。也许全面扫描会更有效? (这是一个修辞问题)。我想通过扫描 CDETAIL 表来查看执行情况,然后看看它是如何执行的。
  • @BobC 与63738 相比,21M 是什么意思?同意,全表扫描不会从索引中受益。

标签: oracle performance indexing query-optimization


【解决方案1】:
  1. 感谢您分享解释计划;这是一个好的开始。然而,带有解释计划的事情是它给你估计,而不是实际。如果可以的话,你能得到一个 SQL Monitor 报告吗?这将向您显示实际的基数并显示查询花费的时间。

  2. 日期过滤器需要大约 3M 行(ID 的 6 和 7)?那准确吗?

  3. IDX_CPCTYDTLTRNCCRTDTM 索引的定义是什么?它是基于函数的吗?

  4. 只是为了验证我的想法,你能否添加以下提示,运行查询并再次获取解释计划。

    select /*+ full(cap) */ ...

【讨论】:

  • 2.是的,3M 行是准确的。对于 3 和 4,我已经编辑了我的问题
  • @VarshaGadekar。使用全盘扫描查询需要多长时间?
  • 使用全表扫描查询耗时 30 秒
  • @VarshaGadekar。好的,另一组问题。 1. 最终查询检索到多少行?您是通过 sqlplus 假脱机吗? 2. 你有资源(CPU 和 IO 带宽)来使用并行性吗? 3. 您可能要考虑对 CDETAIL 表进行分区,但您必须重新编写查询,以免在日期列上使用 TRUNC(),这并不难。
  • 1.查询返回 779,937 行,我使用的是 sql developer 而不是 sqlplus 2。我不能使用并行度
猜你喜欢
  • 1970-01-01
  • 2015-02-26
  • 2011-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多