【OceanBase 诊断调优】—— 统计信息自动收集超时导致的估行不准 SQL 选择错索引

问题现象

发现业务 SQL 执行慢,对比历史执行计划发现索引有变化,优化器选择不优的索引,SQL 选择了索引 A 执行耗时久,手动选择索引耗时短效率很好,手动收集表的统计后优化器自动选对了索引。

问题原因

相同租户下的其他表收集统计信息超时影响客户 SQL 对应表统计信息没更新导致走错索引,手动收集统计信息后,优化器走对了索引。

关键信息

  1. 业务感知到 SQL 耗时增加,通过 dbms_xplan 获取逻辑计划进行分析,发现存在有表估行不准确的现象。

    # 1. 执行 SQL。
    # 2. 获取 plan_id, svr_ip, svr_port,tenant_id。
    
    select plan_id, svr_ip, svr_port,tenant_id, query_sql from oceanbase.v$OB_SQL_AUDIT where query_sql like "%sql_query%";
    select dbms_xplan.display_cursor(264240,'all','10.XX.XX.87', 2882, 1002);
    

    自动收集收集的是统计信息缺失或者统计信息过期的表,按照增量收集的方式进行收集,也就是只收集数据变化的分区,而不用重新收集整个表的统计信息判断需要收集表的的DML 距离上一次收集期间。

    增删改的总量不超过当前表数据量的10%,例如 INSERTS - LAST_INSERTS > 10% 或者 UPDATES - LAST_UPDATES > 10%。

  2. 查询统计信息收集任务发现有大量的表超时 -4012,目前自动收集统计信息的任务是租户下是串行的,相同租户其他表超时了,就可能导致这个表没有机会收集统计信息。

    ## -- 在 sys 租户中获取的所有租户信息,可以指定租户查询(推荐)。
    SELECT t_opt.tenant_id,
        t_opt.task_id,
        task_opt.start_time AS task_start_time,
        task_opt.end_time   AS task_end_time,
        d.database_name,
        t.table_name,
        t_opt.table_id,
        t_opt.ret_code,
        t_opt.start_time,
        t_opt.end_time,
        t_opt.memory_used,
        t_opt.stat_refresh_failed_list,
        t_opt.properties
    FROM   (
               SELECT task_id,
                      start_time,
                      end_time,
                      table_count
               FROM   oceanbase.__all_virtual_task_opt_stat_gather_history
               WHERE  type = 1
    --         AND    tenant_id = {tenant_id}
               AND    start_time > date_sub(Now(), interval 30 day)) task_opt
    JOIN   oceanbase.__all_virtual_table_opt_stat_gather_history t_opt
    JOIN   oceanbase.__all_virtual_table t
    JOIN   oceanbase.__all_virtual_database d
    WHERE  t_opt.ret_code != 0
    AND    task_opt.task_id = t_opt.task_id
    AND    t_opt.table_id = t.table_id
    AND    t.database_id = d.database_id
    AND    t_opt.table_id > 200000;
    

    使用该 SQL 查询语句示例如下图所示。

  3. 对于超时的大表需要手动收集处理一下,或者设置一下相关大表的策略。

    a. 设置合适的默认收集并行度避免影响业务,建议并行度控制 8 个以内。

    ## -- Oracle 或者 MySQL 业务租户相同。
    CALL DBMS_STATS.SET_TABLE_PREFS('database_name', 'table_name', 'degree', '8');
    

    b. 调整相关的自动收集任务在业务低峰期进行, 举例假如业务低峰是凌晨 2 点。

    ## -- MySQL业务租, 比如现在是 2024-03-07, 周四早上 11 点, 需要调整为从周五凌晨 2 点开始。
    CALL DBMS_SCHEDULER.SET_ATTRIBUTE('MONDAY_WINDOW', 'NEXT_DATE', '2024-03-11 02:00:00');
    
    ## -- Oracle 业务租户需要在对应的 sys 用户下执行, 比如现在是 2024-03-07, 周四早上 11 点, 需要调整为从周五凌晨 2 点开始。
    SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS';
    SET NLS_TIMESTAMP_FORMAT='YYYY-MM-DD HH24:MI:SS.FF';
    SET NLS_TIMESTAMP_TZ_FORMAT='YYYY-MM-DD HH24:MI:SS.FF TZR TZD';
    CALL DBMS_SCHEDULER.SET_ATTRIBUTE('MONDAY_WINDOW', 'NEXT_DATE', '2024-03-11 02:00:00');
    

    c. 如果在表的统计信息收集过程中,表收集很慢,可以选择关闭直方图的收集,因为现阶段收集直方图是最费时的操作,同时很多场景目前也还用不上直方图。

    CALL DBMS_STATS.SET_TABLE_PREFS('database_name', 
                              'table_name', 
                              'method_opt', 
                              'for all columns size 1');
    

    d. 如果上面的调整还是收集慢可以在业务低峰期可以考虑适当增加并行度,加速统计信息的收集。

问题的风险及影响

业务 SQL 执行慢。

影响租户

影响 OceanBase 数据库中的 SYS 租户和 Oracle 租户以及 MySQL 租户。

适用版本

OceanBase 数据库 V4.2.x 版本。

解决方法及规避方式

  • 解决方法:

    手动收集统计信息。

    CALL DBMS_STATS.GATHER_TABLE_STATS ('database_name', 'table_name',degree=>8,no_invalidate=>true)
    
  • 规避方式:

    临时规避可以写 HINT 调整索引,收集手动统计信息可以让优化器选对索引。

相关推荐
MrZhangBaby27 分钟前
SQL-leetcode—1158. 市场分析 I
java·sql·leetcode
小高不明2 小时前
仿 RabbitMQ 的消息队列2(实战项目)
java·数据库·spring boot·spring·rabbitmq·mvc
DZSpace2 小时前
使用 Helm 安装 Redis 集群
数据库·redis·缓存
张飞光2 小时前
MongoDB 创建集合
数据库·mongodb
Hello Dam2 小时前
接口 V2 完善:基于责任链模式、Canal 监听 Binlog 实现数据库、缓存的库存最终一致性
数据库·缓存·canal·binlog·责任链模式·数据一致性
张飞光2 小时前
MongoDB 创建数据库
数据库·mongodb·oracle
摘星怪sec3 小时前
【漏洞复现】|方正畅享全媒体新闻采编系统reportCenter.do/screen.do存在SQL注入
数据库·sql·web安全·媒体·漏洞复现
基哥的奋斗历程4 小时前
学到一些小知识关于Maven 与 logback 与 jpa 日志
java·数据库·maven
十二同学啊4 小时前
JSqlParser:Java SQL 解析利器
java·开发语言·sql
莫名有雪4 小时前
BUUCTF_Web([RCTF2015]EasySQL)二次注入+报错注入
sql