GoldenDB慢SQL优化指南

也可通过# EXPLAIN 完全指南 结合一起阅读

1. 引言

GoldenDB是一款分布式数据库,在处理大规模数据时,慢SQL可能会导致系统性能下降、响应时间变长,甚至影响业务正常运行。本指南旨在帮助您理解慢SQL的原因、如何分析慢SQL,以及如何进行优化,使您能够更轻松地应对慢SQL问题。

2. 慢SQL的定义与识别

2.1 什么是慢SQL

慢SQL是指执行时间超过设定阈值的SQL语句。在GoldenDB中,通常认为执行时间超过1秒的SQL语句为慢SQL。

2.2 如何识别慢SQL

  1. 查看慢查询日志

    • CN节点慢日志:记录了SQL的执行总时间、执行计划时间等信息
    • DN节点慢日志:记录了具体的SQL语句、执行时间、扫描行数等信息
  2. 监控告警

    • OMM页面的"执行线程阻塞"告警
    • 慢SQL数量增加的告警
  3. 关键指标监控

    • PlanTreeExecTime:执行计划树耗时
    • DB connection_id duration:DB执行时间
    • Rows_examined:扫描行数

3. 慢SQL的常见原因

3.1 未使用索引

  • 现象:SQL执行时进行全表扫描,Rows_examined值极大
  • 原因:WHERE条件中的列没有创建索引
  • 影响:需要扫描大量数据,执行时间长

3.2 SQL写法不当

  • 现象:返回大结果集,执行时间长
  • 原因
    • 使用SELECT *查询所有列
    • 查询范围过大,没有限制返回行数
    • 条件选择性差,过滤效果不好
    • 复杂的JOIN操作,没有合适的索引
    • 子查询嵌套过深

3.3 统计信息过时

  • 现象:执行计划不合理
  • 原因:表的统计信息过时,优化器选择了错误的执行计划
  • 影响:即使有索引,也可能选择全表扫描

3.4 锁等待

  • 现象:SQL执行时间主要消耗在锁等待上
  • 原因:并发更新同一记录导致锁竞争
  • 影响:SQL执行被阻塞,响应时间变长

3.5 分布式环境特有的问题

  • 现象:跨分片查询,执行时间长
  • 原因
    • 数据分布不均匀
    • 跨分片JOIN操作
    • 大量数据在网络传输
  • 影响:网络开销大,执行时间长

4. 慢日志分析方法

4.1 CN慢日志分析

CN慢日志包含两部分:

  1. 整体执行情况:记录了SQL的总执行时间、各阶段耗时等
  2. 子语句执行情况:记录了执行计划中子语句的执行情况

关键字段分析

字段

说明

分析要点

TotalExecTime

语句执行的总时间

了解整体执行耗时

PlanTreeExecTime

执行计划树的总时间

占总时间的比例,判断是否为执行计划问题

DB connection_id duration

DB侧执行时间

如果该值较大,说明问题出在DB侧

sqltoRoute

语句从执行线程下发到路由线程的耗时

超过100us说明路由线程积压

TaskWait

语句加入到执行队列中到真正开始执行的等待时间

时间长说明队列积压

workerdelay

listener将task放入队列,到worker开始执行的时间

时间长说明有其他语句占用了worker线程

worker

空闲worker线程被唤醒后处理task的时间

时间长且num大说明结果集大

restoExec

路由线程或worker线程将结果处理后给执行线程发消息的时间

时间长说明执行线程消息积压

4.2 DN慢日志分析

DN慢日志记录了SQL在数据节点的执行情况:

字段

说明

分析要点

Query_time

查询执行时间

了解DB侧执行耗时

Lock_time

锁等待时间

时间长说明存在锁竞争

Rows_sent

返回行数

与Rows_examined对比,判断查询效率

Rows_examined

扫描行数

数值过大说明可能未使用索引

4.3 执行计划分析

使用EXPLAIN命令分析SQL的执行计划:

EXPLAIN SELECT * FROM order_info WHERE order_status = 2 AND create_time > '2026-04-01';

关键关注:

  • type:查询类型,ALL表示全表扫描,range表示范围查询,ref表示索引查找
  • possible_keys:可能使用的索引
  • key:实际使用的索引
  • rows:估计需要扫描的行数
  • filtered:过滤后的行数占比
  • Extra:额外信息,如Using indexUsing where

4.4 检查表结构与索引

使用SHOW CREATE TABLE命令查看表结构和索引:

SHOW CREATE TABLE order_info\G

检查WHERE条件中的列是否有相应的索引,以及索引的设计是否合理。

5. 优化策略

5.1 索引优化

  • 创建合适的索引:根据SQL的WHERE条件创建索引
  • 复合索引:对于多个条件的查询,创建复合索引
  • 索引顺序:将选择性高的列放在索引前面
  • 覆盖索引:创建包含查询所需列的索引,减少回表操作
  • 删除冗余索引:定期清理不必要的索引,减少维护成本

示例:

-- 创建复合索引
CREATE INDEX idx_order_status_create_time ON order_info(order_status, create_time);

-- 创建覆盖索引
CREATE INDEX idx_user_id_amount ON order_info(user_id, amount);

5.2 SQL写法优化

问题

优化前

优化后

使用SELECT *

SELECT * FROM order_info WHERE ...

SELECT id, order_no, amount FROM order_info WHERE ...

查询范围过大

WHERE create_time > '2026-04-01'

WHERE create_time > '2026-04-15' LIMIT 1000

条件选择性差

WHERE order_status = 2

WHERE order_status = 2 AND user_id = xxx

复杂子查询

SELECT * FROM (SELECT * FROM order_info WHERE ...) t WHERE ...

SELECT * FROM order_info WHERE ... AND ...

隐式类型转换

WHERE id = '123'

WHERE id = 123

函数操作索引列

WHERE DATE(create_time) = '2026-04-15'

WHERE create_time BETWEEN '2026-04-15 00:00:00' AND '2026-04-15 23:59:59'

5.3 统计信息更新

定期更新表的统计信息,帮助优化器选择更好的执行计划:

-- 更新表统计信息
ANALYZE TABLE order_info;

-- 优化表
OPTIMIZE TABLE order_info;

5.4 分布式环境优化

  • 合理分片:根据业务特点选择合适的分片键,确保数据分布均匀
  • 避免跨分片查询:尽量在单个分片内完成查询操作
  • 批量操作:将多个小查询合并为批量操作,减少网络开销
  • 使用绑定变量:减少SQL解析开销,提高执行效率

5.5 紧急处理措施

当遇到慢SQL导致系统性能下降时:

  1. 定位阻塞SQL

    grep "exec sql too long" dbproxy*
    
    
  2. Kill阻塞链路

    kill connection $dialogid;
    
    
  3. 临时优化SQL:限制返回行数

    SELECT * FROM order_info WHERE order_status = 2 AND create_time > '2026-04-01' LIMIT 1000;
    
    

6. 最佳实践

6.1 开发规范

  • 索引规范

    • 根据SQL编写需求创建合适索引
    • 避免创建过多索引,影响写入性能
    • 定期检查索引使用情况
  • SQL编写规范

    • 避免使用 SELECT *
    • 使用分页查询限制返回行数
    • WHERE条件列要有索引
    • 避免在索引列上进行函数操作
    • 使用绑定变量,减少SQL解析开销
  • 评审流程

    • DDL变更前进行SQL性能评审
    • 新功能上线前进行性能测试
    • 定期Review慢SQL列表

6.2 日常维护

  • 定期分析:定期分析慢查询日志,优化慢SQL
  • 索引维护:定期检查索引使用情况,删除冗余索引
  • 统计信息:定期执行 ANALYZE TABLE 更新统计信息
  • 表结构优化:根据业务发展调整表结构和索引

6.3 监控与告警

  • 慢SQL监控:监控 EXEC** process run too long 日志出现频率
  • 执行时间监控:监控 PlanTreeExecTimeDB connection_id duration
  • 全表扫描监控:监控 Rows_examined 过大的SQL
  • 锁等待监控:监控锁等待时间过长的SQL
  • 分布式查询监控:监控跨分片查询的执行情况

7. 案例分析

7.1 案例背景

现象

  • 执行线程阻塞告警触发
  • 业务查询响应时间从毫秒级飙升至数十秒
  • DN节点CPU使用率飙升至80%+

分析

  1. 查看慢日志发现SQL:select * from order_info where order_status = 2 and create_time > '2026-04-01'
  2. 执行计划显示全表扫描,Rows_examined: 5823671
  3. 检查表结构发现order_statuscreate_time列无索引
  4. CN慢日志显示DB connection_id duration: 38450000us,说明问题出在DB侧

解决方案

  1. 创建复合索引:CREATE INDEX idx_order_status_create_time ON order_info(order_status, create_time);
  2. 优化SQL写法,避免使用SELECT *SELECT id, order_no, amount FROM order_info WHERE order_status = 2 AND create_time > '2026-04-01'
  3. 限制返回行数:SELECT id, order_no, amount FROM order_info WHERE order_status = 2 AND create_time > '2026-04-01' LIMIT 1000

效果

  • 执行计划变为范围查询,仅扫描15万行
  • SQL执行时间从38秒降至毫秒级
  • 系统性能恢复正常

7.2 案例分析:跨分片查询优化

现象

  • 跨分片JOIN查询执行时间长
  • 网络传输数据量大

分析

  1. SQL:SELECT o.id, o.order_no, u.username FROM order_info o JOIN user_info u ON o.user_id = u.id WHERE o.create_time > '2026-04-01'
  2. 订单表和用户表分别在不同分片
  3. 执行计划显示需要在所有分片上执行查询,然后在CN节点进行JOIN

解决方案

  1. 调整分片策略,将相关表放在同一分片
  2. 或者创建本地索引,减少跨分片数据传输
  3. 优化SQL,减少返回数据量:SELECT o.id, o.order_no, u.username FROM order_info o JOIN user_info u ON o.user_id = u.id WHERE o.create_time > '2026-04-01' LIMIT 100

效果

  • 执行时间从10秒降至1秒以内
  • 网络传输数据量减少90%

8. 总结

慢SQL优化是GoldenDB性能管理的重要组成部分。通过合理的索引设计、SQL写法优化、定期维护和监控,可以有效避免和解决慢SQL问题,提高系统性能和稳定性。

记住以下关键点:

  • WHERE条件列必须创建索引,避免全表扫描
  • 避免使用SELECT *和过大的查询范围
  • 定期更新统计信息,确保优化器选择正确的执行计划
  • 注意分布式环境的特殊性,合理设计分片策略
  • 建立完善的监控和告警机制,及时发现和处理慢SQL
  • 制定开发规范,从源头避免慢SQL