SQL优化选对执行计划,查询速度提升1000倍 | OceanBase 应用实践

作者:爱可生数据库高级工程师任仲禹,擅长故障分析和性能优化。

本文通过一个案例,分享使用OceanBase时,SQL走错执行计划,而导致慢SQL的排查方法论。

案例背景

在使用OceanBase 3.2.3 版本的过程中,项目组反映某个 SELECT 语句在指定时间内的查询响应速度异常缓慢,其耗时远超正常情况的1000倍以上。具体细节如下:

  • 慢 SELECT
SELECT COUNT(*) AS TOT_CNT FROM renzy WHERE (ACCT_NO = '6222620117273900882') AND LAWENF_NTIST_TP_CD NOT LIKE '12%' AND LAWENF_NTIST_TP_CD NOT LIKE '05%' AND EMRG_STPY_SRC_CD != 'JZ05' AND ACCTG_DT >= '1900-01-01' AND ACCTG_DT <= '2025-03-31' ;
  • 关键表结构、记录数信息如下
-- 脱敏处理
show create table renzy\G                  
*************************** 1. row ***************************
       Table: renzy
Create Table: CREATE TABLE `renzy` (
  `ID` char(18) COLLATE utf8mb4_bin NOT NULL COMMENT ,
...
  `ACCT_NO` char(40) COLLATE utf8mb4_bin NOT NULL COMMENT ,
...
  `ACCTG_DT` date DEFAULT NULL COMMENT ,
...
  PRIMARY KEY (`ID`),
...
  KEY `renzy_I2` (`ACCT_NO`) BLOCK_SIZE 16384 LOCAL,
...
  KEY `renzy_I5` (`ACCTG_DT`, `ENQ_INST_CD`, `BLON_INST_CD`, `EMRG_STPY_SRC_CD`) BLOCK_SIZE 16384 LOCAL,
...
) DEFAULT CHARSET = utf8mb4;
1 row in set (0.01 sec)

MySQL > SELECT COUNT(*) AS TOT_CNT FROM renzy WHERE (ACCT_NO = '6222620117273900882');
+---------+
| TOT_CNT |
+---------+
|       1 |
+---------+
1 row in set (0.02 sec)

MySQL > SELECT COUNT(*) AS TOT_CNT FROM renzy WHERE ACCTG_DT >= '1900-01-01' AND ACCTG_DT <= '2025-03-31';
+----------+
| TOT_CNT  |
+----------+
| 25432155 |
+----------+
1 row in set (12.42 sec)

MySQL > SELECT COUNT(*) AS TOT_CNT FROM renzy;                                                            
+----------+
| TOT_CNT  |
+----------+
| 25435024 |
+----------+
1 row in set (10.65 sec)

排查过程

正常执行不慢

MySQL > select * from (SELECT COUNT(*) AS TOT_CNT FROM renzy WHERE (ACCT_NO = '6222620117273900882') AND LAWENF_NTIST_TP_CD NOT LIKE '12%' AND LAWENF_NTIST_TP_CD NOT LIKE '05%' AND EMRG_STPY_SRC_CD != 'JZ05' AND ACCTG_DT >= '1900-01-01' AND ACCTG_DT <= '2025-03-31') as orginal limit 2000; select last_trace_id();
+---------+
| TOT_CNT |
+---------+
|       1 |
+---------+
1 row in set (0.02 sec)

以下是执行计划,从中可见,索引I2是最高效的选择,它在进行等值匹配时仅需要执行一次回表操作。

*************************** 1. row ***************************
Query Plan: ========================================================
|ID|OPERATOR        |NAME               |EST. ROWS|COST|
--------------------------------------------------------
|0 |LIMIT           |                   |1        |92  |
|1 | SCALAR GROUP BY|                   |1        |92  |
|2 |  TABLE SCAN    |renzy(renzy_I2)|1        |92  |
========================================================
...
Outline Data:
-------------------------------------
  /*+
      BEGIN_OUTLINE_DATA
      INDEX(@"SEL$2" "gabsdb.renzy"@"SEL$2" "renzy_I2")
      END_OUTLINE_DATA
  */
...
renzy:table_rows:25419080, physical_range_rows:1, logical_range_rows:1, index_back_rows:1, output_rows:0, est_method:local_storage, optimization_method=cost_based, avaiable_index_name[renzy_I2,renzy_I5], pruned_index_name[renzy_I1,renzy_I3,renzy_I4,renzy_I6], unstable_index_name[renzy], estimation info[table_id:1105009185965290, (table_type:1, version:0-1699898410195654-1699898410195654, logical_rc:1, physical_rc:1), (table_type:7, version:1699898401860480-1699898401860480-1699898433101378, logical_rc:0, physical_rc:0), (table_type:7, version:1699898433101378-1699904137032515-1699905915658079, logical_rc:0, physical_rc:0), (table_type:5, version:1699898433101378-1699904137032515-1699905915658079, logical_rc:0, physical_rc:0), (table_type:0, version:1699905915658079-1699905915658079-9223372036854775807, logical_rc:0, physical_rc:0)]
...

通过 OCP 的 SQL 诊断获取慢 SQL 的 plan_id,检查慢 SQL 实际命中的 plan。

MySQL [oceanbase]> select * from gv$plan_cache_plan_stat where plan_id=7288229 \G                                                                         
*************************** 1. row ***************************
...
              plan_id: 7288229
...
            statement: select * from (SELECT COUNT(*) AS TOT_CNT FROM renzy WHERE (ACCT_NO = ?) AND LAWENF_NTIST_TP_CD NOT LIKE ? AND LAWENF_NTIST_TP_CD NOT LIKE ? AND EMRG_STPY_SRC_CD != ? AND ACCTG_DT >= ? AND ACCTG_DT <= ?) as orginal limit 2000
            query_sql: select * from (SELECT COUNT(*) AS TOT_CNT FROM renzy WHERE (ACCT_NO = '6222620117273900882') AND LAWENF_NTIST_TP_CD NOT LIKE '12%' AND LAWENF_NTIST_TP_CD NOT LIKE '05%' AND EMRG_STPY_SRC_CD != 'JZ05' AND ACCTG_DT >= '' AND ACCTG_DT <= '') as orginal limit 2000
       special_params: 2000
          param
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值