最佳实践—如何限流慢SQL

本文涉及的产品
云原生数据库 PolarDB 分布式版,标准版 2核8GB
简介: 本文介绍了如何对慢SQL进行有效限流。

在数据库会话或者慢日志中发现大量慢SQL,大量占用数据库资源,同时活跃会话数、CPU使用率、IOPS、内存使用率等监控指标一项或者多项处于高位。分析后发现这些慢SQL不属于核心业务,是优化不足的烂SQL,为保障核心业务的稳定运行,此时我们需要对其进行限流。

相关限流语法,请参见SQL限流

SQL限流的运维操作步骤

  1. 实例会话页面或使用如下语句发现慢SQL。
select *
  from information_schema.processlist
 where COMMAND!= 'SLEEP'
   and TIME>= 1000
 order by TIME DESC;
  1. 分析慢SQL,请参见如何分析及优化慢SQL
  2. 创建限流规则,可使用SQL命令,或者实例会话里SQL限流功能上的白屏化操作。
  3. 从以下几方面观察限流规则效果。
  • 监控指标恢复情况;
  • 业务侧反馈;
  • show ccl_rules查看每个限流规则的限流情况的统计信息;
  • 查看会话和SQL日志。
  1. 创建索引、修改SQL、增加资源等。
  2. 关闭限流规则,使用DROP CCL_RULE或者CLEAR CCL_RULES语句。

如下案例说明了如何对发现的慢SQL进行限流,您可以参照案例中的限流规则,修改后使用。

案例1: 慢SQL属于同一个SQL模版

某DBA收到了数据库资源某指标处于高位的报警,查看数据库慢日志和会话后均发现有如下的慢SQL:


+--------+---------------+---------------------+--------------------+---------+------+-------+----------------------------------------------+-----------------+
| ID     | USER          | HOST                | DB                 | COMMAND | TIME | STATE | INFO                                         | SQL_TEMPLATE_ID |
+--------+---------------+---------------------+--------------------+---------+------+-------+----------------------------------------------+-----------------+
| 951494 | userxxxxxxxxx | 222.0.0.1:33830     | analy_db           | Query   |   40 |       | select * from bmsql_oorder where `o_id` > 12 | 65c92c88        |
| 952468 | userxxxxxxxxx | 222.0.0.1:33517     | analy_db           | Query   |   43 |       | select * from bmsql_oorder where `o_id` > 10 | 65c92c88        |
| 953468 | userxxxxxxxxx | 222.0.0.1:33527     | analy_db           | Query   |   43 |       | select * from bmsql_oorder where `o_id` > 23 | 65c92c88        |
| 954468 | userxxxxxxxxx | 222.0.0.1:33537     | analy_db           | Query   |   43 |       | select * from bmsql_oorder where `o_id` > 25 | 65c92c88        |
| 955468 | userxxxxxxxxx | 222.0.0.1:33547     | analy_db           | Query   |   43 |       | select * from bmsql_oorder where `o_id` > 27 | 65c92c88        |
+--------+---------------+---------------------+--------------------+---------+------+-------+----------------------------------------------+-----------------+

可见,这些慢SQL属于同一个SQL模版(模版ID为65c92c88):


select * from bmsql_oorder where `o_id` > ?

bmsql_oorder为一个数据量较大的表,而且列o_id上没有索引,显然这个一个未经优化的SQL,占尽了数据库资源影响了其他重要SQL的正常执行。这是一个非常适合利用模版ID去做SQL限流的场景。

创建限流规则

  • 如果这个SQL模版的SQL不应该在当时执行,而且应该在业务低峰期执行,则我们可以创建SQL限流规则不让它执行:
CREATE CCL_RULE `KILL_CCL`       //限流规则名称为KILL_CCL
    ON `analy_db`.`*`              //&匹配analy_db下的所有表上执行的SQL
  TO 'userxxxxxxxxx'@'%'         //&匹配来自userxxxxxxxxx用户的SQL
    FOR SELECT                     //&匹配是SELECT类型的SQL语句
  FILTER BY TEMPLATE '65c92c88'  //&匹配模版ID
  WITH MAX_CONCURRENCY = 0;      //设置单节点并发度为0,不允许匹配到的SQL执行
  • 客户端再次执行这类SQL的时候将会返回报错信息:
ERROR 3009 (HY000): [13172dbaf2801000][10.93.159.222:3029][analy_db]Exceeding the max concurrency 0 per node of ccl rule KILL_CCL
  • 如果允许这个SQL模版的SQL少量执行,只要不占尽数据库资源就行,则我们可以在创建限流规则的时候设置一定的并发度:
CREATE CCL_RULE `KILL_CCL_2`       //限流规则名称为KILL_CCL
    ON `analy_db`.`*`              //&匹配analy_db下的所有表上执行的SQL
  TO 'userxxxxxxxxx'@'%'         //&匹配来自userxxxxxxxxx用户的SQL
    FOR SELECT                     //&匹配是SELECT类型的SQL语句
  FILTER BY TEMPLATE '65c92c88'  //&匹配模版ID 65c92c88
  WITH MAX_CONCURRENCY = 2;      //允许单个节点可以同时有两个这样的SQL在执行
  • 也可使用实例会话页面里的SQL限流功能,进行如下操作:8..png
  • 如果希望这个SQL模版的SQL执行的时候可以慢,但尽量不要出错,则可以设置等待队列和等待超时时间(默认为600秒):


CREATE CCL_RULE `QUEUE_CCL_2`       //限流规则名称为KILL_CCL
    ON `analy_db`.`*`              //&匹配analy_db下的所有表上执行的SQL
  TO 'userxxxxxxxxx'@'%'         //&匹配来自userxxxxxxxxx用户的SQL
    FOR SELECT                     //&匹配是SELECT类型的SQL语句
  FILTER BY TEMPLATE '65c92c88'  //&匹配模版ID
  WITH MAX_CONCURRENCY = 2, WAIT_QUQUE_SIZE=20, WAIT_TIMEOUT=500; //单节点并发度为2,单节点等待队列长度为20,等待超时时间为500秒

创建完后,可以通过show ccl_rules指令查询各个限流规则的实际效果,比如当前匹配到某个限流规则的正在执行的SQL的数量、被限流报错的SQL数量、总匹配成功次数等。如果想放开被限流SQL,比如在增加了某个索引后,被限流SQL的执行效率变高了,则可以通过drop ccl_rule命令来关闭指定限流规则,或者使用clear ccl_rules来关闭所有的限流规则。

当然上面的SQL也可以通过关键字来限流,将SQL语句上的关键字做拆分,我们得到关键字列表:

  • select
  • from
  • bmsql_oorder
  • where
  • `o_id`

创建限流规则:


CREATE CCL_RULE `KILL_CCL`       //限流规则名称为KILL_CCL
    ON `analy_db`.`*`              //&匹配analy_db下的所有表上执行的SQL
  TO 'userxxxxxxxxx'@'%'         //&匹配来自userxxxxxxxxx用户的SQL
    FOR SELECT                     //&匹配是SELECT类型的SQL语句
  FILTER BY KEYWORD('select','from','bmsql_oorder','where','`o_id`')  //&匹配模版ID
  WITH MAX_CONCURRENCY = 0;      //设置单节点并发度为0,不允许匹配到的SQL执行

在能获取到模版ID(在SQL日志、explain命令、会话中)的情况下,我们还推荐使用更精准的基于模版ID的限流。

也可使用实例会话页面里的SQL限流功能,操作如下:

案例2: 慢SQL都是同一个SQL

某DBA收到了数据库资源某指标处于高位的报警,查看数据库慢日志和会话后均发现有如下的慢SQL:


+--------+---------------+---------------------+--------------------+---------+------+-------+---------------------------------------------------+-----------------+
| ID     | USER          | HOST                | DB                 | COMMAND | TIME | STATE | INFO                                              | SQL_TEMPLATE_ID |
+--------+---------------+---------------------+--------------------+---------+------+-------+---------------------------------------------------+-----------------+
| 951494 | userxxxxxxxxx | 222.0.0.1:33830     | analy_db           | Query   |   40 |       | select * from bmsql_oorder where o_carrier_id = 2 | 438b00e4        |
| 952468 | userxxxxxxxxx | 222.0.0.1:33517     | analy_db           | Query   |   43 |       | select * from bmsql_oorder where o_carrier_id = 2 | 438b00e4        |
| 953468 | userxxxxxxxxx | 222.0.0.1:33527     | analy_db           | Query   |   43 |       | select * from bmsql_oorder where o_carrier_id = 2 | 438b00e4        |
| 954468 | userxxxxxxxxx | 222.0.0.1:33537     | analy_db           | Query   |   43 |       | select * from bmsql_oorder where o_carrier_id = 2 | 438b00e4        |
| 955468 | userxxxxxxxxx | 222.0.0.1:33547     | analy_db           | Query   |   43 |       | select * from bmsql_oorder where o_carrier_id = 2 | 438b00e4        |
+--------+---------------+---------------------+--------------------+---------+------+-------+---------------------------------------------------+-----------------+

bmsql_oorder中的符合o_carrier_id = 2条件的有较多记录,导致了慢SQL,如果使用模版ID限流,则会影响o_carrier_id不是2的SQL语句,如果使用关键字限流则会影响类似如下的正常SQL:


select * from bmsql_oorder where o_carrier_id = 2 limit 1;
select * from bmsql_oorder where o_carrier_id = 2 and o_c_id = 1;

限流具体的SQL,可以使用模版ID加关键字的方法,创建如下限流规则:


CREATE CCL_RULE `KILL_CCL`       //限流规则名称为KILL_CCL
    ON `analy_db`.`*`              //&匹配analy_db下的所有表上执行的SQL
  TO 'userxxxxxxxxx'@'%'         //&匹配来自userxxxxxxxxx用户的SQL
    FOR SELECT                     //&匹配是SELECT类型的SQL语句
  FILTER BY TEMPLATE '438b00e4'  //&匹配模版ID 438b00e4
  FILTER BY KEYWORD('o_carrier_id','2')  //&匹配参数关键字
  WITH MAX_CONCURRENCY = 0;      //设置单节点并发度为0,不允许匹配到的SQL执行

如果使用PolarDB-X的CN内核版本为5.4.11以上,且该SQL不在prepare模式下执行,还可以使用如下高阶语法进行限流:


CREATE CCL_RULE `KILL_CCL`       //限流规则名称为KILL_CCL
    ON `analy_db`.`*`              //&匹配analy_db下的所有表上执行的SQL
  TO 'userxxxxxxxxx'@'%'         //&匹配来自userxxxxxxxxx用户的SQL
    FOR SELECT                     //&匹配是SELECT类型的SQL语句
  FILTER BY QUERY 'select * from bmsql_oorder where o_carrier_id = 2'  //&匹配SQL语句
  WITH MAX_CONCURRENCY = 0;      //设置单节点并发度为0,不允许匹配到的SQL执行

案例3: 慢SQL集包含多个SQL模版

某DBA收到了数据库资源某指标处于高位的报警,查看数据库慢日志和会话后均发现有如下的慢SQL:


+--------+---------------+---------------------+--------------------+---------+------+-------+---------------------------------------------------+-----------------+
| ID     | USER          | HOST                | DB                 | COMMAND | TIME | STATE | INFO                                              | SQL_TEMPLATE_ID |
+--------+---------------+---------------------+--------------------+---------+------+-------+---------------------------------------------------+-----------------+
| 951494 | userxxxxxxxxx | 222.0.0.1:33830     | analy_db           | Query   |   40 |       | select * from bmsql_oorder where o_carrier_id = 2 | 438b00e4        |
| 952468 | userxxxxxxxxx | 222.0.0.1:33517     | analy_db           | Query   |   43 |       | select * from bmsql_order_line where ol_o_id = 2  | 57a572f9        |
| 953468 | userxxxxxxxxx | 222.0.0.1:33527     | analy_db           | Query   |   43 |       | select * from bmsql_new_order where no_w_id = 2   | de6eefdb        |
+--------+---------------+---------------------+--------------------+---------+------+-------+---------------------------------------------------+-----------------+

此种情况较为复杂,如果一条明显执行效率很高的SQL也成了慢SQL,则不排除是由于网络抖动或者服务节点异常等原因导致运行效率降低从而产生大批量的慢SQL,也可能是由于真正的烂SQL完全耗尽了资源,导致原本正常的SQL也成了慢SQL,需要通过SQL分析具体原因,不在本文的讨论范围内。假设已经确定了需要限流的慢SQL,我们则可以针对每个模版ID创建一个限流规则。但随着限流规则增加,匹配效率会略有降低,当PolarDB-X的CN内核版本为5.4.11以上时,我们推荐使用多模版限流:


CREATE CCL_RULE `KILL_CCL`       //限流规则名称为KILL_CCL
    ON `analy_db`.`*`              //&匹配analy_db下的所有表上执行的SQL
  TO 'userxxxxxxxxx'@'%'         //&匹配来自userxxxxxxxxx用户的SQL
    FOR SELECT                     //&匹配是SELECT类型的SQL语句
  FILTER BY TEMPLATE('438b00e4','57a572f9','de6eefdb')  //&匹配中其中一个模版ID,则该匹配项算匹配成功
  WITH MAX_CONCURRENCY = 0;      //设置单节点并发度为0,不允许匹配到的SQL执行

如果确定会话中的慢SQL是都是需要限流的烂SQL,且PolarDB-X的CN内核版本为5.4.11以上时,可以开启慢SQL限流。也可以使用实例会话页面里的SQL限流功能,进行如下操作:9..png

总结

SQL限流为应急措施,可在数据库由于烂SQL导致效率降低的时候,起到快速恢复的作用。对烂SQL进行限流后,用户需要将注意力集中在如何优化烂SQL上,并在合适的时机清空SQL限流规则。

相关实践学习
快速体验PolarDB开源数据库
本实验环境已内置PostgreSQL数据库以及PolarDB开源数据库:PolarDB PostgreSQL版和PolarDB分布式版,支持一键拉起使用,方便各位开发者学习使用。
相关文章
|
28天前
|
SQL 开发框架 .NET
ASP.NET连接SQL数据库:详细步骤与最佳实践指南ali01n.xinmi1009fan.com
随着Web开发技术的不断进步,ASP.NET已成为一种非常流行的Web应用程序开发框架。在ASP.NET项目中,我们经常需要与数据库进行交互,特别是SQL数据库。本文将详细介绍如何在ASP.NET项目中连接SQL数据库,并提供最佳实践指南以确保开发过程的稳定性和效率。一、准备工作在开始之前,请确保您
133 3
|
4月前
|
SQL 存储 监控
SQL数据库安装指南:步骤详解与最佳实践
安装和配置SQL数据库可能是一个复杂的过程,但通过遵循本文提供的详细步骤和最佳实践,您可以确保数据库的成功安装和高效运行。无论您是初学者还是经验丰富的数据库管理员,掌握SQL数据库的安装和管理技能都是至关重要的。通过不断学习和实践,您将能够更好地利用SQL数据库来支持您的业务需求和数据分析工作。记住,定期维护和优化数据库是保证其长期性能和稳定性的关键。祝您在安装和配置SQL
|
30天前
|
SQL 存储 数据库
SQL语句给予用户权限:技巧、方法与最佳实践
在数据库管理中,为用户分配适当的权限是确保数据安全性和操作效率的关键步骤
|
1月前
|
SQL 数据管理 数据库
文章初学者指南:SQL新建数据库详细步骤与最佳实践
引言:在当今数字化的世界,数据库管理已经成为信息技术领域中不可或缺的一部分。作为广泛使用的数据库管理系统,SQL已经成为数据管理和信息检索的标准语言。本文将详细介绍如何使用SQL新建数据库,包括准备工作、具体步骤和最佳实践,帮助初学者快速上手。一、准备工作在开始新建数据库之前,你需要做好以下准备工作
109 3
|
3月前
|
Java 开发者 前端开发
Struts 2、Spring MVC、Play Framework 上演巅峰之战,Web 开发的未来何去何从?
【8月更文挑战第31天】在Web应用开发中,Struts 2框架因强大功能和灵活配置备受青睐,但开发者常遇配置错误、类型转换失败、标签属性设置不当及异常处理等问题。本文通过实例解析常见难题与解决方案,如配置文件中遗漏`result`元素致页面跳转失败、日期格式不匹配需自定义转换器、`<s:checkbox>`标签缺少`label`属性致显示不全及Action中未捕获异常影响用户体验等,助您有效应对挑战。
84 0
|
3月前
|
前端开发 开发者
Vaadin Grid的秘密武器:打造超凡脱俗的数据展示体验!
【8月更文挑战第31天】赵萌是一位热爱UI设计的前端开发工程师。在公司内部项目中,她面临大量用户数据展示的挑战,并选择了功能强大的Vaadin Grid来解决。她在技术博客上分享了这一过程,介绍了Vaadin Grid的基本概念及其丰富的内置功能。通过自定义列和模板,赵萌展示了如何实现复杂的数据展示。
41 0
|
3月前
|
SQL 开发框架 .NET
深入解析Entity Framework Core中的自定义SQL查询与Raw SQL技巧:从基础到高级应用的全面指南,附带示例代码与最佳实践建议
【8月更文挑战第31天】本文详细介绍了如何在 Entity Framework Core (EF Core) 中使用自定义 SQL 查询与 Raw SQL。首先,通过创建基于 EF Core 的项目并配置数据库上下文,定义领域模型。然后,使用 `FromSqlRaw` 和 `FromSqlInterpolated` 方法执行自定义 SQL 查询。此外,还展示了如何使用 Raw SQL 进行数据更新和删除操作。最后,通过结合 LINQ 和 Raw SQL 构建动态 SQL 语句,处理复杂查询场景。本文提供了具体代码示例,帮助读者理解和应用这些技术,提升数据访问层的效率和灵活性。
179 0
|
3月前
|
SQL 数据库 索引
SQL 编程最佳实践简直太牛啦!带你编写高效又可维护的 SQL 代码,轻松应对数据库挑战!
【8月更文挑战第31天】在SQL编程中,高效与可维护的代码至关重要,不仅能提升数据库性能,还降低维护成本。本文通过案例分析探讨SQL最佳实践:避免全表扫描,利用索引加速查询;合理使用JOIN,避免性能问题;避免使用`SELECT *`,减少不必要的数据传输;使用`COMMIT`和`ROLLBACK`确保事务一致性;添加注释提高代码可读性。遵循这些实践,不仅提升性能,还便于后期维护和扩展。应根据具体情况选择合适方法并持续优化SQL代码。
52 0
|
3月前
|
SQL 监控 关系型数据库
SQL性能监控与调优工具的神奇之处:如何用最佳实践选择最适合你的那一个,让你的数据库飞起来?
【8月更文挑战第31天】在现代软件开发中,数据库性能监控与调优对应用稳定性至关重要。本文对比了数据库内置工具、第三方工具及云服务工具等几种常用SQL性能监控与调优工具,并通过示例代码展示了如何利用MySQL的EXPLAIN功能分析查询性能。选择最适合的工具需综合考虑功能需求、数据库类型及成本预算等因素。遵循了解工具功能、试用工具及定期维护工具等最佳实践,可帮助开发者更高效地管理和优化数据库性能,迎接未来软件开发中的挑战与机遇。
50 0
|
6月前
|
SQL 监控 测试技术
SQL语法优化与最佳实践
【2月更文挑战第28天】本章将深入探讨SQL语法优化的重要性以及具体的优化策略和最佳实践。通过掌握和理解这些优化技巧,读者将能够编写出更高效、更稳定的SQL查询,提升数据库性能,降低系统资源消耗。
下一篇
无影云桌面