问题现象
SQL 查询计划索引选择错误,计划突变,执行响应时间飙升,CPU 使用率 100%,系统响应慢。
问题原因
造成索引选择错误的主要原因是增量合并收集的统计信息出现了非常大的偏差,SQL 查询中的列的 NULL 值个数远超过了表的行数,导致选择率计算的时候认为列的谓词过滤性很好,选择了错误的索引,从而导致计划发生突变。针对 OceanBase 数据库 V3.x 版本,统计信息的收集是做在合并当中;由于默认情况下都是增量合并,这就会导致随着时间的拉长,增量合并的次数越来越多,对于删除、修改比较频繁的表,其增量收集的统计信息可能会越来越不准,从而潜在导致在某个时间会因为统计信息偏差过大而导致计划发生突变。从 OceanBase 数据库 V4.x 版本已经将合并收集统计信息解耦,合并不再收集统计信息。
关键信息
合并收集统计信息异常、SQL 计划突变。
问题的风险及影响
统计信息误差太大,会潜在导致相关 SQL 查询计划发生突变,使得 SQL 执行性能急剧下降,CPU 使用率 100% 的风险,造成业务 RT 飙升,系统响应慢等问题。
影响租户
影响 OceanBase 数据库中的 SYS 租户和 Oracle 租户以及 MySQL 租户。
适用版本
OceanBase 数据库 V3.x 版本。
解决方法及规避方式
解决方法:
通过 OCP 白屏尝试去绑定旧的
outline计划,看看能否绑定成功,绑定失败转步骤 2。通过 SQL ID 直接创建相关的预期的执行计划
outline hint信息(比如索引选择,join算法、join顺序等hint),绑定失败转步骤 3。CREATE OUTLINE {outline_name} ON {SQL_ID} USING HINT /*+ .... */;在 sys 租户根据
tenant id、该查询涉及的所有表的table id、column id信息查询__all_virtual_column_statistic统计信息null值的个数,如下查询结果中的null值个数超过表的行数则说明合并收集的统计信息出现异常。SELECT column_id, sum(num_null) FROM oceanbase.__all_virtual_column_statistic WHERE tenant_id = {tenant_id} AND table_id = {table_id} AND column_id IN {column_id_list} AND num_distinct > 0 GROUP BY column_id;如果合并收集的统计信息是异常的,应急可以考虑先手动收集统计信息(OceanBase 数据库 V3.2/V3.3 版本支持),手动收集之后会重新生成计划,新生成的计划会优先手动收集统计信息,但是需要注意的是,应急完成之后,由于手动收集的统计信息不会自动更新,在后续的业务低峰期,需要订正合并收集的统计信息,然后将手动收集的统计信息清除,避免后续不更新。
增量收集的异常统计信息,只能通过设置该表下一次合并时使用全量合并进行校正,同时全量合并订正完合并收集的统计信息之后,需要重新设置回该表的合并方式为增量合并。
### 设置下次合并方式table使用全量合并。 ALTER TABLE {table_name} SET PROGRESSIVE_MERGE_NUM = 1;### 设置下次合并方式 table 使用增量合并。 ALTER TABLE {table_name} SET PROGRESSIVE_MERGE_NUM = 0;如果上述方式没法解决问题,请收集提供如下列表信息提供给 OceanBase 数据库技术支持团队。
原始查询 SQL,计划突变前后的计划形态,当前 SQL 查询的
explain extended计划信息。查询 SQL 中涉及到的表信息,索引信息等。
查询 SQL 中涉及到的表的统计信息,sys 租户通过
table id查询__all_virtual_column_statistic、__all_virtual_column_stat_v2、__all_virtual_table_stat_v2。查询 SQL 其中一次执行的
TRACE ID对应的 OBServer log 日志信息。查询 SQL 的
SQL AUDIT执行信息(如果存在)。
规避方式:
通过如下 SQL 定期巡检合并收集的统计信息中存在 null 值个数超过行数的表。
SELECT tenant_id, table_id, column_id FROM (SELECT tenant_id, table_id, column_id, sum(num_null) as null_cnt FROM oceanbase.__all_virtual_column_statistic WHERE num_distinct > 0 GROUP BY tenant_id, table_id, column_id) column_stat where null_cnt > ( SELECT sum(row_count) FROM __all_virtual_tenant_partition_meta_table tab_stat WHERE tab_stat.tenant_id = column_stat.tenant_id AND tab_stat.table_id = column_stat.table_id AND replica_type = 0 AND role = 1 AND status = 'REPLICA_STATUS_NORMAL');针对合并收集统计信息有问题的表,设置下次合并该表进行全量合并,从而订正合并收集的统计信息,合并收集的统计信息订正之后,重新设置该表的合并方式为增量合并。