我们对 created_at 字段进行时间范围查询,绝大多数时候执行计划都正确进行了分区裁剪,只扫描了相关的几个分区,速度很快。但在少数情况下(无明显规律),完全相同的SQL 在不同的OBServer节点上执行, EXPLAIN 显示其执行计划变成了对所有分区的全表扫描,导致查询超时。
已进行的排查:
统计信息:已确认表的统计信息是较新的(近期收集过)。
执行计划绑定:我们尝试过使用 OUTLINE 进行执行计划绑定,强制其走分区裁剪,但绑定有时会因集群重启或版本升级而失效,维护成本高。
观察:该现象似乎与查询条件中 created_at 的常量值有关。当我们使用 BETWEEN ‘2024-05-01’ AND ‘2024-05-02’ 时正常,但某些具体的日期值(如 = ‘2024-05-15 10:00:00’ )在特定节点上会触发全扫。
核心疑问:
OceanBase 的优化器在什么情况下会对一个明确的分区键等值/范围查询“放弃”分区裁剪?是否有内部阈值(比如,当优化器评估某个分区内数据量“过小”或成本计算出现偏差时)?
这种现象是否与 OceanBase 的分区剪枝功能在某些边缘条件下,优化器成本估算不准确有关?我们应如何更精准地诊断(例如,是否有类似 EXPLAIN FORMAT = JSON 或特定的 GV$ 视图可以看到更详细的剪枝决策过程)?
除了执行计划绑定,是否有更优雅的解决思路(例如,调整优化器相关 hint、系统参数,或通过更具体的索引设计来规
3 个赞
论坛小助手
#8
在 OceanBase 4.x 中,对分区表进行范围查询时,执行计划“突然”选择全分区扫描而非分区裁剪的情况可能与优化器的成本估算和查询条件有关。具体原因如下:
-
优化器成本估算不准确:
- 优化器在生成执行计划时会根据统计信息和查询条件评估成本。如果统计信息不够准确或某些边缘条件导致优化器误判,可能会选择全分区扫描。
- 特定的查询条件(如
= '2024-05-15 10:00:00')可能在某些节点上被优化器认为全扫描成本更低,从而选择全扫描。
-
内部阈值和边缘条件:
- 优化器可能存在内部阈值,当评估某个分区内数据量“过小”或成本计算出现偏差时,可能会放弃分区裁剪。
- 这种情况通常发生在统计信息不完整或不准确的边缘条件下。
-
诊断方法:
- 使用
EXPLAIN FORMAT = JSON 查看更详细的执行计划信息,了解优化器的决策过程。
- 查询
GV$SQL_PLAN 视图,查看具体的执行计划和优化器的决策细节。
- 检查
GV$SQL_PLAN_MONITOR 视图,监控执行计划的实时运行情况。
-
解决思路:
-
调整优化器相关 hint:使用
/*+ INDEX(@table_name @index_name) */ 强制使用特定索引,或使用 /*+ NO_INDEX_FFS(@table_name @index_name) */ 禁止全索引扫描。
-
调整系统参数:可以通过调整
optimizer_features_enable、_optimizer_index_cost_adj 等参数来影响优化器的行为。
-
更具体的索引设计:确保分区键和查询条件匹配,创建局部索引以提高查询性能。
-
定期更新统计信息:确保统计信息是最新的,可以定期运行
ANALYZE TABLE 语句。
通过上述方法,可以更精准地诊断和解决执行计划选择全分区扫描的问题。
具体信息可参考以下文档:
- 指定分区查询数据
- 使用 OceanBase 数据库分区表进行水平拆分
- SQL 调优典型场景和案例
- OceanBase 数据库性能的影响因素