soar 启发规则汇总 常见 MySQL 优化案例

2023-10-16 16:58

本文主要是介绍soar 启发规则汇总 常见 MySQL 优化案例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

最近偶然翻翻一些博客,发现依然有一些介绍 mysql 常见优化场景的东西,甚是有趣。想起了之前在公司做的 SQL 规范相关工作。独乐了不如众乐乐,独学习不如众分享,跟大家分享下自己在这个环节的一些心得。

之前无非是根据一些经验和书籍,列出常见的场景。直到有一次看到了小米的开源工具,SOAR,简直是被震惊的感觉。这个工具通过是 SQL 语法树的分析,结合小米 DBA 多年经验的总结,进行了一系列启发规则的校验。最后给出 SQL 的优化建议,甚是好用。

当然,本篇文章不会介绍 SOAR 的具体使用,我们来聊聊那些 DBA 总结出来的启发规则。根据启发规则,大家也能解决平时遇到的相关 SQL 问题。

关于 SOAR 的使用和二次开发,如果大家有兴趣,欢迎留言。如果有需要,可以和博主交流~~


-------- 美丽的分割线 -------


摘自: https://github.com/XiaoMi/soar/blob/master/doc/heuristic.md

这是小米 soar 的默认启发规则汇总,也是 DBA 多年精华总结。熟读各个案例,对于一般的 MySQL 优化有很高的帮助。
如果你不喜欢太理论的东西,或者没时间去深入,举一反三学习也未尝不可。


启发式规则建议

建议使用 AS 关键字显示声明一个别名

  • Item:ALI.001
  • Severity:L0
  • Content:在列或表别名(如"tbl AS alias")中, 明确使用 AS 关键字比隐含别名(如"tbl alias")更易懂。
  • Case:
select name from tbl t1 where id < 1000

不建议给列通配符’*'设置别名

  • Item:ALI.002
  • Severity:L8
  • Content:例: "SELECT tbl.* col1, col2"上面这条 SQL 给列通配符设置了别名,这样的SQL可能存在逻辑错误。您可能意在查询 col1, 但是代替它的是重命名的是 tbl 的最后一列。
  • Case:
select tbl.* as c1,c2,c3 from tbl where id < 1000

别名不要与表或列的名字相同

  • Item:ALI.003
  • Severity:L1
  • Content:表或列的别名与其真实名称相同, 这样的别名会使得查询更难去分辨。
  • Case:
select name from tbl as tbl where id < 1000

修改表的默认字符集不会改表各个字段的字符集

  • Item:ALT.001
  • Severity:L4
  • Content:很多初学者会将 ALTER TABLE tbl_name [DEFAULT] CHARACTER SET ‘UTF8’ 误认为会修改所有字段的字符集,但实际上它只会影响后续新增的字段不会改表已有字段的字符集。如果想修改整张表所有字段的字符集建议使用 ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;
  • Case:
ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;

同一张表的多条 ALTER 请求建议合为一条

  • Item:ALT.002
  • Severity:L2
  • Content:每次表结构变更对线上服务都会产生影响,即使是能够通过在线工具进行调整也请尽量通过合并 ALTER 请求的试减少操作次数。
  • Case:
ALTER TABLE tbl ADD COLUMN col int, ADD INDEX idx_col (`col`);

删除列为高危操作,操作前请注意检查业务逻辑是否还有依赖

  • Item:ALT.003
  • Severity:L0
  • Content:如业务逻辑依赖未完全消除,列被删除后可能导致数据无法写入或无法查询到已删除列数据导致程序异常的情况。这种情况下即使通过备份数据回滚也会丢失用户请求写入的数据。
  • Case:
ALTER TABLE tbl DROP COLUMN col;

删除主键和外键为高危操作,操作前请与 DBA 确认影响

  • Item:ALT.004
  • Severity:L0
  • Content:主键和外键为关系型数据库中两种重要约束,删除已有约束会打破已有业务逻辑,操作前请业务开发与 DBA 确认影响,三思而行。
  • Case:
ALTER TABLE tbl DROP PRIMARY KEY;

不建议使用前项通配符查找

  • Item:ARG.001
  • Severity:L4
  • Content:例如 “%foo”,查询参数有一个前项通配符的情况无法使用已有索引。
  • Case:
select c1,c2,c3 from tbl where name like '%foo'

没有通配符的 LIKE 查询

  • Item:ARG.002
  • Severity:L1
  • Content:不包含通配符的 LIKE 查询可能存在逻辑错误,因为逻辑上它与等值查询相同。
  • Case:
select c1,c2,c3 from tbl where name like 'foo'

参数比较包含隐式转换,无法使用索引

  • Item:ARG.003
  • Severity:L4
  • Content:隐式类型转换有无法命中索引的风险,在高并发、大数据量的情况下,命不中索引带来的后果非常严重。
  • Case:
SELECT * FROM sakila.film WHERE length >= '60';

IN (NULL)/NOT IN (NULL) 永远非真

  • Item:ARG.004
  • Severity:L4
  • Content:正确的作法是 col IN (‘val1’, ‘val2’, ‘val3’) OR col IS NULL
  • Case:
SELECT * FROM tb WHERE col IN (NULL);

IN 要慎用,元素过多会导致全表扫描

  • Item:ARG.005
  • Severity:L1
  • Content: 如:select id from t where num in(1,2,3)对于连续的数值,能用 BETWEEN 就不要用 IN 了:select id from t where num between 1 and 3。而当 IN 值过多时 MySQL 也可能会进入全表扫描导致性能急剧下降。
  • Case:
select id from t where num in(1,2,3)

应尽量避免在 WHERE 子句中对字段进行 NULL 值判断

  • Item:ARG.006
  • Severity:L1
  • Content:使用 IS NULL 或 IS NOT NULL 将可能导致引擎放弃使用索引而进行全表扫描,如:select id from t where num is null;可以在num上设置默认值0,确保表中 num 列没有 NULL 值,然后这样查询: select id from t where num=0;
  • Case:
select id from t where num is null

避免使用模式匹配

  • Item:ARG.007
  • Severity:L3
  • Content:性能问题是使用模式匹配操作符的最大缺点。使用 LIKE 或正则表达式进行模式匹配进行查询的另一个问题,是可能会返回意料之外的结果。最好的方案就是使用特殊的搜索引擎技术来替代 SQL,比如 Apache Lucene。另一个可选方案是将结果保存起来从而减少重复的搜索开销。如果一定要使用SQL,请考虑在 MySQL 中使用像 FULLTEXT 索引这样的第三方扩展。但更广泛地说,您不一定要使用SQL来解决所有问题。
  • Case:
select c_id,c2,c3 from tbl where c2 like 'test%'

OR 查询索引列时请尽量使用 IN 谓词

  • Item:ARG.008
  • Severity:L1
  • Content:IN-list 谓词可以用于索引检索,并且优化器可以对 IN-list 进行排序,以匹配索引的排序序列,从而获得更有效的检索。请注意,IN-list 必须只包含常量,或在查询块执行期间保持常量的值,例如外引用。
  • Case:
SELECT c1,c2,c3 FROM tbl WHERE c1 = 14 OR c1 = 17

引号中的字符串开头或结尾包含空格

  • Item:ARG.009
  • Severity:L1
  • Content:如果 VARCHAR 列的前后存在空格将可能引起逻辑问题,如在 MySQL 5.5中 ‘a’ 和 'a ’ 可能会在查询中被认为是相同的值。
  • Case:
SELECT 'abc '

不要使用 hint,如:sql_no_cache, force index, ignore key, straight join等

  • Item:ARG.010
  • Severity:L1
  • Content:hint 是用来强制 SQL 按照某个执行计划来执行,但随着数据量变化我们无法保证自己当初的预判是正确的。
  • Case:
SELECT * FROM t1 USE INDEX (i1) ORDER BY a;

不要使用负向查询,如:NOT IN/NOT LIKE

  • Item:ARG.011
  • Severity:L3
  • Content:请尽量不要使用负向查询,这将导致全表扫描,对查询性能影响较大。
  • Case:
select id from t where num not in(1,2,3);

一次性 INSERT/REPLACE 的数据过多

  • Item:ARG.012
  • Severity:L2
  • Content:单条 INSERT/REPLACE 语句批量插入大量数据性能较差,甚至可能导致从库同步延迟。为了提升性能,减少批量写入数据对从库同步延时的影响,建议采用分批次插入的方法。
  • Case:
INSERT INTO tb (a) VALUES (1), (2)

最外层 SELECT 未指定 WHERE 条件

  • Item:CLA.001
  • Severity:L4
  • Content:SELECT 语句没有 WHERE 子句,可能检查比预期更多的行(全表扫描)。对于 SELECT COUNT(*) 类型的请求如果不要求精度,建议使用 SHOW TABLE STATUS 或 EXPLAIN 替代。
  • Case:
select id from tbl

不建议使用 ORDER BY RAND()

  • Item:CLA.002
  • Severity:L3
  • Content:ORDER BY RAND() 是从结果集中检索随机行的一种非常低效的方法,因为它会对整个结果进行排序并丢弃其大部分数据。
  • Case:
select name from tbl where id < 1000 order by rand(number)

不建议使用带 OFFSET 的LIMIT 查询

  • Item:CLA.003
  • Severity:L2
  • Content:使用 LIMIT 和 OFFSET 对结果集分页的复杂度是 O(n^2),并且会随着数据增大而导致性能问题。采用“书签”扫描的方法实现分页效率更高。
  • Case:
select c1,c2 from tbl where name=xx order by number limit 1 offset 20

不建议对常量进行 GROUP BY

  • Item:CLA.004
  • Severity:L2
  • Content:GROUP BY 1 表示按第一列进行 GROUP BY。如果在 GROUP BY 子句中使用数字,而不是表达式或列名称,当查询列顺序改变时,可能会导致问题。
  • Case:
select col1,col2 from tbl group by 1

ORDER BY 常数列没有任何意义

  • Item:CLA.005
  • Severity:L2
  • Content:SQL 逻辑上可能存在错误; 最多只是一个无用的操作,不会更改查询结果。
  • Case:
select id from test where id=1 order by id

在不同的表中 GROUP BY 或 ORDER BY

  • Item:CLA.006
  • Severity:L4
  • Content:这将强制使用临时表和 filesort,可能产生巨大性能隐患,并且可能消耗大量内存和磁盘上的临时空间。
  • Case:
select tb1.col, tb2.col from tb1, tb2 where id=1 group by tb1.col, tb2.col

ORDER BY 语句对多个不同条件使用不同方向的排序无法使用索引

  • Item:CLA.007
  • Severity:L2
  • Content:ORDER BY 子句中的所有表达式必须按统一的 ASC 或 DESC 方向排序,以便利用索引。
  • Case:
select c1,c2,c3 from t1 where c1='foo' order by c2 desc, c3 asc

请为 GROUP BY 显示添加 ORDER BY 条件

  • Item:CLA.008
  • Severity:L2
  • Content:默认 MySQL 会对 ‘GROUP BY col1, col2, …’ 请求按如下顺序排序 ‘ORDER BY col1, col2, …’。如果 GROUP BY 语句不指定 ORDER BY 条件会导致无谓的排序产生,如果不需要排序建议添加 ‘ORDER BY NULL’。
  • Case:
select c1,c2,c3 from t1 where c1='foo' group by c2

ORDER BY 的条件为表达式

  • Item:CLA.009
  • Severity:L2
  • Content:当 ORDER BY 条件为表达式或函数时会使用到临时表,如果在未指定 WHERE 或 WHERE 条件返回的结果集较大时性能会很差。
  • Case:
select description from film where title ='ACADEMY DINOSAUR' order by length-language_id;

GROUP BY 的条件为表达式

  • Item:CLA.010
  • Severity:L2
  • Content:当 GROUP BY 条件为表达式或函数时会使用到临时表,如果在未指定 WHERE 或 WHERE 条件返回的结果集较大时性能会很差。
  • Case:
select description from film where title ='ACADEMY DINOSAUR' GROUP BY length-language_id;

建议为表添加注释

  • Item:CLA.011
  • Severity:L1
  • Content:为表添加注释能够使得表的意义更明确,从而为日后的维护带来极大的便利。
  • Case:
CREATE TABLE `test1` (`ID`</

这篇关于soar 启发规则汇总 常见 MySQL 优化案例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/220276

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

SQL中的外键约束

外键约束用于表示两张表中的指标连接关系。外键约束的作用主要有以下三点: 1.确保子表中的某个字段(外键)只能引用父表中的有效记录2.主表中的列被删除时,子表中的关联列也会被删除3.主表中的列更新时,子表中的关联元素也会被更新 子表中的元素指向主表 以下是一个外键约束的实例展示

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

如何去写一手好SQL

MySQL性能 最大数据量 抛开数据量和并发数,谈性能都是耍流氓。MySQL没有限制单表最大记录数,它取决于操作系统对文件大小的限制。 《阿里巴巴Java开发手册》提出单表行数超过500万行或者单表容量超过2GB,才推荐分库分表。性能由综合因素决定,抛开业务复杂度,影响程度依次是硬件配置、MySQL配置、数据表设计、索引优化。500万这个值仅供参考,并非铁律。 博主曾经操作过超过4亿行数据

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

HDFS—存储优化(纠删码)

纠删码原理 HDFS 默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。 Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。 此种方式节约了空间,但是会增加 cpu 的计算。 纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。 默认只开启对 RS-6-3-1024k

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

MySQL数据库宕机,启动不起来,教你一招搞定!

作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG、Mongodb数据库运维(如安装迁移,性能优化、故障应急处理等)公众号:老苏畅谈运维欢迎关注本人公众号,更多精彩与您分享。 MySQL数据库宕机,数据页损坏问题,启动不起来,该如何排查和解决,本文将为你说明具体的排查过程。 查看MySQL error日志 查看 MySQL error日志,排查哪个表(表空间