【问题标题】:why does the optimizer choose the higher cost execution plan?为什么优化器会选择成本更高的执行计划?
【发布时间】:2016-03-05 09:20:36
【问题描述】:

这对我来说是一个反复出现的问题。我有一段时间运行良好的语句,一段时间后优化器决定选择另一个执行计划。当我查询一个(复合)主键时,甚至会发生这种情况。

当我在 dba_hist_sql_plan 中查找执行计划时,它显示使用主键索引的查询成本为 20,而执行全表扫描的查询成本为 270。

plan_hash_value Operation        Options              Cost  Search_Columns

2550672280  0   SELECT STATEMENT                       20
2550672280  1   PARTITION HASH   SINGLE                20
2550672280  2   TABLE ACCESS     BY LOCAL INDEX ROWID  20
2550672280  3   INDEX            RANGE SCAN            19                1

3908080950  0   SELECT STATEMENT                      270
3908080950  1   PARTITION HASH  SINGLE                270
3908080950  2   TABLE ACCESS    FULL                  270

我已经注意到优化器只使用主键索引中的第一列,然后进行范围扫描。但我真正的问题是:为什么优化器会选择成本更高的执行计划?并不是同时使用两个执行计划,我注意到一个快照中的一个切换,然后它会保持这样几个小时/天。所以这不可能是绑定偷看的问题。

我们当前的解决方案是我打电话给我们的 DBA,他会刷新语句缓存。但这并不是真正可持续的。

编辑: SQL 看起来像这样: select * from X where X.id1 = ?和 X.id2 = ?和 X.id3 = ? (id1,id2,id3) 是表上的复合主键(具有唯一索引)。

【问题讨论】:

  • 可能有很多原因。其中一些是有效的。最常见的一种是当 exec。计划适用于其他一些模式。另一个原因可能是动态采样或性能基准。
  • SQL 在哪里?你看过自适应光标共享吗?
  • SQL 很简单。比如“select * from x where x.id1 = ? and x.id2 = ? and x.id3 = ?”
  • 考虑到自适应游标共享:由于我正在从复合主键中查询确切的 3 列,因此它不会是倾斜直方图的问题。我的结果集中必须只有一行或没有行。但我猜自适应游标共享可能是一个问题,因为优化器决定只查找索引中的第一列然后进行范围扫描的奇怪行为。我可能不得不解决这个问题
  • 计划是否可能不同,因为某些东西偶尔会阻止索引访问?例如,是否定期删除和重建索引? (这是一件愚蠢的事情,但它确实发生了。)

标签: oracle oracle11g sql-execution-plan sql-tuning


【解决方案1】:

显然优化器没有正确显示类型转换的成本。此问题的根本原因是日期值的类型映射不正确。虽然数据库中的列是 DATE 类型,但 JDBC 类型是错误的 java.sql.Timestamp。要将 DATE 列与 Timestamp 搜索参数进行比较,表中的所有值都需要首先传输到 Timestamp。这是额外的成本并使索引无法使用。

【讨论】:

    【解决方案2】:

    也许它与 Oracle 11g 上的一个错误有关。
    错误 18377553:基数估计差,直方图和值 > 32 字节

    当你的数据是这样的:

    AAAAAAAAAAAAAAAAAAAAmyvalue
    AAAAAAAAAAAAAAAAAAAAsomeohtervalue
    AAAAAAAAAAAAAAAAAAAAandsoon
    B1234
    

    直方图效果不佳。

    解决方案是禁用主键上的直方图,一切都会顺利开始。

    【讨论】:

    • 非常有趣的错误。我们的复合主键由(按此顺序)组成:1)来自序列的 id,最大值:~700K,分布大致相等 2)代表 2000 年到 2018 年之间一天的日期。在大多数情况下,我们有 365 到 3650 个不同的日期一个id的天数。 3) 表示该行何时被逻辑删除的日期,因此在所有行的约 95% 中,这是代表“我们的”无限未来的日期。
    • 并且日期是 7 个字节?所以我们没有任何大于 32 字节的值。我会理解优化器是否只选择前 2 列进行搜索,因为在 95% 的情况下,他只会得到 1 行。但是在第一列之后停止很奇怪
    【解决方案3】:

    最有可能的集群因子和索引的 blevel 可能非常高。通过查询 dba_indexes 检查 blevel。如果 blevel 大于 3,请尝试重建索引。

    还要检查为主键创建的索引是否唯一。根据计划,它使用范围扫描而不是唯一扫描。该索引很可能不是唯一的。

    【讨论】:

    • 性能不佳的索引可以解释为什么全表扫描优于索引扫描。但这不应该反映在成本上,并且仍然使用最低成本的计划吗?
    • 索引是唯一的。我理解它的方式:范围扫描是优化器仅通过第一列的索引的结果。 blevel 为 2,clustering_factor 对这个表来说是个大问题,变化很大。
    猜你喜欢
    • 2017-08-10
    • 1970-01-01
    • 2011-01-24
    • 2020-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-24
    • 1970-01-01
    相关资源
    最近更新 更多