Code前端首页关于Code前端联系我们

Oracle 根据 to_date(文字) 格式使用或忽略索引列

terry 2年前 (2023-09-26) 阅读数 44 #数据库

使用索引列作为过滤器并将其放置在“两个文字之间”。 (该列位于索引的第二个位置,这实际上使执行速度变慢;我稍后会讨论)。让我困惑的是,Oracle (11.2.0.3.0) 根据提供给 to_date 的值的格式和格式字符串来使用或忽略指定索引:

这会忽略索引:

  1. SQL> SELECT *
  2. 2 FROM gprs_history_import gh
  3. 3 其中 start_call_date_time 之间
  4. 4 to_date('20140610 000000','yyyymmdd hh24miss') AND
  5. 5 to_date('2 0140610 235959','yy yymmdd hh24小姐')
  6. 6 /
  7. 实施计划
  8. --------------------- ------------ -- -- -----------------
  9. 计划哈希值:990804809
  10. ------------------------------------------ ----- --- ------------------------------------------------- ----------
  11. |身份 |运营|名称 |行|字节 |成本(% CPU)|时间 |开始|停止 |
  12. ---------- -------------------------------- -- - ------------ ------------------------------- ------ - ---------
  13. | 0 |选择语句 | | 350 | 350 219K| 242K (1)| 00:56:42 | 00:56:42 | |
  14. | 1 |仅分区范围| 42 | 42 74 | 74 74 |
  15. | 2 |分区列表全部| | 350 | 350 219K| 242K (1)| 00:56:42 | 00:56:42 1 | 3 |
  16. |* 3 | | 219K| 242K (1)| 00:56:42 | 00:56:42 220 | 220 222 |
  17. ---------------------------- ------------- -- ---- --------------------------- ------------- ------ ---- ----------
  18. 谓词信息(通过操作ID标识):
  19. ----------------------------- -
  20. 3 - 过滤器("START_CALL_DATE_TIME" 从 gprs_history_import gh
  21. 3 中选择 *
  22. 2,其中 start_call_date_time 之间
  23. 4 to_date('20140610 ','yyyymmdd ') AND
  24. 5 to_date('20140610 235959',' yyyymmdd hh24miss')
  25. 6 /
  26. 执行计划
  27. --------------- - ----- -------------- -------------------
  28. 计划哈希值:464458373
  29. ------------------------------------------ ----- --- ------------------------------------------------ ---------- --- -------------
  30. |身份 |运营|名称 |行|字节 |成本(% CPU)|时间 |开始|停止 |
  31. -------------------------------------------------------- --- ------------------------------------------ -------- ----------------------------
  32. | 0 |选择语句 | | 350 | 350 219K | 219K 2795K (1)| 10:52:15 | 10:52:15 | |
  33. |* 1 |过滤器| | | | | | | |
  34. | 2 |分区范围迭代器 | 10:52:15 | 10:52:15关键| 74 |
  35. | 3 |分区列表全部| | 350 | 350 219K| 2795K (1)| 10:52:15 | 10:52:15 1 | 3 |
  36. | 4 |指数RIDEID| GPRS_HISTORY_IMPORT | GPRS_HISTORY_IMPORT | 350 | 350 219K| 2795K (1)| 10:52:15 | 10:52:15关键| 222 |
  37. |* 5 |索引跳过扫描 | GPRS_HISTORY_IMPORT_IDX1 | 1 | | 2795K (1)| 10:52:15 | 10:52:15关键| 222 |
  38. ------------------------------------------------------------ ------------------------------------------ -------- ---------------------------
  39. 谓词信息(通过操作ID标识):
  40. -------------------------------------------- - --- -----------
  41. 1 - 过滤器(TO_DATE('20140610','yyyymmdd ')=TO_DATE('20140610','yyyymmdd ') AND "START_CALL_DATE_TIME"=TO_DATE('20140610','syyyy-mm-dd hh24 : mi:ss' ))

((1) 中的过滤器看起来有点奇怪,就像 Oracle 不理解这个表达式一样)

这也不适用于这个(我删除了尾随空格):

  1. SQL > 选择 *
  2. 2 来自 gprs_history_import gh
  3. 3 其中 start_call_date_time 之间
  4. 4 to_date('20140610','yyyymmdd') 和
  5. 5 to_date('20140610 235959','syyyy-mm-dd hh24:mi:s ) )

在空格两边加上引号不包括索引的使用。

什么给出了?

解决方法

好的 - 我会尝试一下,主要是从可用信息中减去:为什么 Oracle 选择不同的执行计划?

在您的第二个查询中,似乎存在不寻常的日期格式,优化器不知道结果日期的值是什么。您将看到过滤谓词:

1 - filter(TO_DATE('20140610 ′,'yyyymmdd') 全表扫描不一定是需要一个糟糕的计划...使用索引并不总是更快!
> 查询计划中的成本永远不会与实际执行时间或性能直接相关 - 它是一个内部指标,用于比较同一查询的不同计划(因此您无法比较不同查询的成本,例如查询 1、2 和3)

基本上,如果从表中返回大量行,在许多情况下执行不带索引访问的全表扫描会快得多,特别是在某些分区上执行时! – 表扫描仅访问与日期范围匹配的相关性 – 因此仅针对相关日期并返回该分区其中的所有行。这比查询每行的索引,然后通过索引访问检索行要快得多...尝试解析查询 - 分区上的全表扫描速度应该快 3 倍,并且 IO 少得多。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门