Mysql查询优化汇总 order by优化例子,group by优化例子,limit优化例子,优化建议

索引

索引是一种存储引擎快速查询记录的一种数据结构。

注意

  • MYSQL一次查询只能使用一个索引,这个说法是不正确的,MYSQL会在两个索引列中,使用OR查询的时候,进行索引合并(index_merge;Using union(col1,col2);),但这种建立索引会使得索引数据的膨胀,不建议使用。如果对多个字段使用索引,建立使用复合索引。
 

冗余和重复索引

  • Mysql需要单独维护重复的索引,并且优化查询的时候也需要逐个进行考虑,这会影响性能。
  • 重复索引是指在相同的列上按照相同的顺序创建的相同类型的索引。应该避免这样创建重复索引,发现以后也应该立即移除。

例如:

  1. 在唯一限制和主键ID上建立索引,则是重复索引。Mysql的唯一限制和主键限制都是通过索引实现的。
  2. 如果创建了索引(A,B),再创建(A)索引,就是冗余索引,这只是一个索引的前缀索引。
  3. 如果创建了索引(A,B),再创建(B,A)则不是冗余索引。
  • 大多数情况下都不需要冗余索引,应该尽量扩展已有的索引而不是创建新的索引。
  • 解决冗余和重复索引的方法很简单,删除这些索引就可以了。可以使用Percona-Toolikt的pt-duplicate-key-checker检查重复索引。
 

索引的优点:

  1. 索引大大减少了服务器需要扫描的数据量。
  2. 索引可以帮助服务器避免排序和临时表。
  3. 索引可以将随机I/O变为顺序I/O。
 
CREATE TABLE `tab` (
`col1` int(11) DEFAULT NULL,
`col2` int(11) DEFAULT NULL,
`col3` int(11) DEFAULT NULL,
`col4` int(11) DEFAULT NULL,
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
KEY `col1_2` (`col1`,`col2`,`col3`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
 
insert into tab (col1, col2, col3) values (1,2,3,1),(4,5,6,1),(4,5,6,2),(4,5,6,3),(4,5,6,4),(4,5,6,3),(4,5,6,3);
 
CREATE TABLE `tab_1` (
`col1` int(11) DEFAULT NULL,
`col2` int(11) DEFAULT NULL,
`col3` int(11) DEFAULT NULL,
`col4` int(11) DEFAULT NULL,
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 

ORDER BY优化

  • 在ORDER BY操作中,MYSQL只有在排序条件不是一个查询表达式的情况下才使用索引。
  • 说明:表:tab,字段:col1,col2,col3,索引:INDEX(col1,col2,col3)。
  • 在关联表查询(JOIN)中,order by第一张表会使用索引排序,如果是使用JOIN的话,由于优化器在优化时可能将第二个表当成第一张表即(RIGHT JOIN),那么实际上无法使用索引,如:desc select t.col1 from tab t left join tab_1 t1 on t.id = t1.id order by t.col1;。

能够使用到索引的情况

  1. desc select col1, col2, col3 from tab order by col1, col2, col3。
  2. desc select col1, col2 from tab where col1 = 1 order by col2。[有where的时候,前导列为常数的情况下可以用索引]
  3. desc select * from tab where col1 < 4 order by col1 desc。
  4. desc select * from tab where col1 = 10 and col2 > 10 order by col2 desc。
  5. desc select * from tab where col1 < 10 and col2 > 20 order by col1 desc。

不能够使用索引的情况

  1. desc select col1 from tab where col1 > 18 order by col2, col3。[col1是一个范围查询条件,而不是一个常数,无法使用索引]
  2. desc select * from tab where col1 > 1 order by col2, col1。[排序键顺序与索引中列顺序不一致,无法使用索引排序]
  3. desc select col1, col2 from tab order by col1 desc, col2 asc。[升序降序不一致,无法使用索引排序]
  4. desc select col1, col2 from tab where col1 > 1 order by col2。[条件1是范围查询,无法使用索引排序,具体和组合索引数据分布有关系]
  5. desc select * from tab where col1 = 1234 or col2 = 4321 order by col2。[当你逻辑表达式为OR时,使用索引排序会丢失,无法使用索引排序]
  6. desc select * from tab where col1 = 123 and col2 in (1,2) order by col3。[IN查询也是一种范围查询,无法使用索引排序]
  7. desc select * from tab where col1 = 123 order by col2, col4。[ORDER BY子句中引用了一个不在索引中的列,col4,无法使用索引排序]
 

LIMIT优化

  • 对limit分页问题的性能优化方法-延迟关联
推荐使用“延迟关联”的方法来优化排序操作,何为“延迟关联”:通过使用覆盖索引查询返回需要的主键,然后再根据主键关联原表获得需要的数据来加速分页查询。
我们都知道,利用了索引查询的语句中如果只包含了那个索引列(覆盖索引),那么这种情况会查询很快。因为利用索引查找有优化算法,且数据就在查询索引上面,不用再去找相关的数据地址了,这样节省了很多时间。
 

例如

select * from ummor_user_detail ud order by user_id limit 300000,20 ;
优化写法1
select * from ummor_user_detail ud where user_id >= (select user_id from ummor_user_detail order by user_id limit 300000,1) limit 20 ;
优化写法2
select * from ummor_user_detail as a join (select user_id from ummor_user_detail order by user_id limit 300000,20 ) as b on a.user_id = b.user_id;
 

GROUP BY

MYSQL有三种索引扫描方式完成GROUP BY操作,分别是松散索引扫描和紧凑索引扫描以及临时表实现GROUP BY。
在松散索引扫描下,分组操作和范围预测(如果有的话)一起执行完成的。
在紧凑索引扫描下,先对索引执行范围扫描(range scan),再对结果元祖进行分组。
 

GROUP BY优化

  • desc select * from tab where col1 > 1 group by col1, col2, col3, col4。[松散索引扫描]
  • desc select * from tab where col2 > 1 group by col1, col3。[紧凑索引扫描,必须加where,在查询中存在常量相等的where条件字段(索引中的字段,且该字段在GROUP BY指定的字段的前面或者中间)]
  • desc select * from tab where col1 > 1 group by col2, col3。
  • desc select * from tab where col1 > 1 group by col3, col4。[临时表实现GROUP BY]
 

1. 松散索引扫描[Loose Index San]

使用松散索引扫描需要满足以下条件
  1. 查询在单一表上。
  2. GROUP BY指定的所有列是索引的一个最左前缀,并且没有其他的列。比如:表tab1(col1,col2,col3,col4)上建立了索引(col1,col2,col3)。如果查询包含“group by col1,col2”,那么可以使用松散索引扫描。但是“group by col2,col3”(不是最左前缀)和“group by col1,col2,col4”(col4字段不在索引中)无法使用。
  3. 如果在选择列表select list中存在聚集函数,只能使用MIN()和MAX()两个聚合函数,并且指定的事同一个列(如果min()和max()同时存在),这一列必须在索引中,且紧跟着GROUP BY指定的列。比如:select col1,col2,min(col3),max(col3) from tab group by col1, col2。
  4. 如果查询中存在除了group by指定的列之外的索引其他部分,那么必须以常量的形式出现(除了min()和max()两个聚集函数)。比如:select col1, col3 from tab group by col1, col2不能使用松散索引扫描。而select col1, col3 from tab where col3 = 3 group by col1, col2可以使用松散索引扫描。
 

2. 紧凑索引扫描(Tight Index Scan)

紧凑索引扫描可能是全索引扫描或者范围索引扫描,取决于查询条件。
紧凑索引扫描实现GROUP BY和松散索引扫描的区别主要在于他需要在扫描索引的时候,读取所有满足条件的索引键,然后再根据读取的数据来完成GROUP BY 操作得到相应结果。
 

3. 使用临时表实现GROUP BY

 
 

优化建议

  1. JOIN。
    1. 在ON字段上加索引,并且字段类型必须是相同的,否则MYSQL无法使用到它们的索引。
  2. 使用 ENUM 而不是 VARCHAR。
  3. 避免使用!=或<>、IS NULL或IS NOT NULL、IN ,NOT IN ORDER BY RAND 等这样的操作符。
  4. 把IP地址存成 UNSIGNED INT。
  5. 固定长度的表会更快。
  6. 垂直分割。
    1. “垂直分割”是一种把数据库中的表按列变成几张表的方法,这样可以降低表的复杂度和字段的数目,从而达到优化的目的。
    2. 例一:在Users表中有一个字段是家庭地址,这个字段是可选字段,相比起,而且你在数据库操作的时候除了个人信息外,你并不需要经常读取或是改写这个字段。那么,为什么不把他放到另外一张表中呢? 这样会让你的表有更好的性能,大家想想是不是,大量的时候,我对于用户表来说,只有用户ID,用户名,口令,用户角色等会被经常使用。小一点的表总是会有好的性能。
    3. 示例二: 你有一个叫 “last_login” 的字段,它会在每次用户登录时被更新。但是,每次更新时会导致该表的查询缓存被清空。所以,你可以把这个字段放到另一个表中,这样就不会影响你对用户ID,用户名,用户角色的不停地读取了,因为查询缓存会帮你增加很多性能。
    4. 另外,你需要注意的是,这些被分出去的字段所形成的表,你不会经常性地去Join他们,不然的话,这样的性能会比不分割时还要差,而且,会是极数级的下降。
  7. 拆分大的 DELETE 或 INSERT 语句。
    1. 如果你需要在一个在线的网站上去执行一个大的 DELETE 或 INSERT 查询,你需要非常小心,要避免你的操作让你的整个网站停止相应。因为这两个操作是会锁表的,表一锁住了,别的操作都进不来了。
  8. 越小的列会越快。建议:布尔/枚举:tinyint,日期与时间戳:timestamp或int,char/text/blob: 尽量用符合实际长度的varchar(n),小数及货币:移位转为int 或 decimal,IP地址:int。
  9. 在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。
  10. 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会 逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
  11. NOT IN、NOT EXISTS的相关子查询可以改用LEFT JOIN代替写法。
  12. 能用UNION ALL就不要用UNION,需知道两者区别。
  13. 尽量避免使用or,会导致数据库引擎放弃索引进行全表扫描。
    1. SELECT * FROM t WHERE id = 1 OR id = 3
    2. 优化方式:可以用union代替or。如下:
    3. SELECT * FROM t WHERE id = 1 UNION SELECT * FROM t WHERE id = 3
  14. 能够用BETWEEN的就不要用IN。
  15. 能够用DISTINCT的就不用GROUP BY。
  16. 尽量不要用SELECT INTO语句。SELECT INTO 语句会导致表锁定,阻止其他用户访问该表。
  17. UPDATE操作不要拆成DELETE操作+INSERT操作的形式,虽然功能相同,但是性能差别是很大的。
  18. 索引字段上进行运算会使索引失效。
 

数据表结构优化建议

根据数据分析建议来修改表结构,使之更符合数据存储规范:PROCEDURE ANALYSE(1)。
  • 如:select * from tab PROCEDURE ANALYSE(1);分析出每个字段。
 
 

编写MYSQL习惯

1. SELECT * from TABLE1 和 SELECT * FROM TABLE1
  • 上面的两条SQL语句对于查询缓冲是完全不同的SELECT。而且查询缓冲并不自动处理空格,因此,在写SQL语句时,应尽量减少空格的使用,尤其是在SQL首和尾的空格(因为,查询缓冲并不自动截取首尾空格)。
2. 关键字大写。如:SELECT,LIKE,OR。
 

例子:

desc select col1, col2 from tab where col1 = 1 or col2 = 1; # index col1, index col2 索引合并,不建议
desc select * from tab where col1 = 1 or col2 = 2; # index col1, index col2,使用col1索引,索引合并,不建议使用
 
desc select col1, col2 from tab where col1 = 1 or col2 = 1; # index col1 col3, index col2 没有使用到索引,不是独立索引列
desc select * from tab where col1 = 1 or col2 = 2; # index col1 col3, index col2 没有使用到索引,不是独立索引列
 
desc select col1,col2 from tab where col1 = 1 or col2 = 1; # index col1, col2 使用到了索引
desc select * from tab where col1 = 1 or col2 = 1; # index col1, col2 没有使用到索引
对比下面
desc
select * from tab where col1 = 1
union all
select * from tab where col2 = 2; # 使用这个策略是第一条语句能够使用到索引,而第二条不行,这样就有一半的数据还是能够使用到索引,而不是整条语句使用不到索引。如果col2也有做索引列的话,那么两条均能使用到索引查询。

Mysql查询优化汇总 order by优化例子,group by优化例子,limit优化例子,优化建议的更多相关文章

  1. MySQL之单表查询 一 单表查询的语法 二 关键字的执行优先级(重点) 三 简单查询 四 WHERE约束 五 分组查询:GROUP BY 六 HAVING过滤 七 查询排序:ORDER BY 八 限制查询的记录数:LIMIT 九 使用正则表达式查询

    MySQL之单表查询 阅读目录 一 单表查询的语法 二 关键字的执行优先级(重点) 三 简单查询 四 WHERE约束 五 分组查询:GROUP BY 六 HAVING过滤 七 查询排序:ORDER B ...

  2. mysql查询优化之四:优化特定类型的查询

    本文将介绍如何优化特定类型的查询. 1.优化count()查询count()聚合函数,以及如何优化使用了该函数的查询,很可能是mysql中最容易被误解的前10个话题之一 count() 是一个特殊的函 ...

  3. MySQL笔记汇总

    [目录] MySQL笔记汇总 一.mysql简介 数据简介 结构化查询语言 二.mysql命令行操作 三.数据库(表)更改 表相关 字段相关 索引相关 表引擎操作 四.数据库类型 数字型 字符串型 日 ...

  4. MySQL查询优化(转)

    在分析性能欠佳的查询时,应考虑: 1) 应用程序是否正获取超过需要的数据,即访问了过多的行或列. 2) Mysql服务器是否分析了超过需要的行. 如果发现访问的数据行数很大,而生成的结果中数据行很少, ...

  5. MySQL查询优化之explain的深入解析

    在分析查询性能时,考虑EXPLAIN关键字同样很管用.EXPLAIN关键字一般放在SELECT查询语句的前面,用于描述MySQL如何执行查询操作.以及MySQL成功返回结果集需要执行的行数.expla ...

  6. Mysql查询优化器

    Mysql查询优化器 本文的目的主要是通过告诉大家,查询优化器为我们做了那些工作,我们怎么做,才能使查询优化器对我们的sql进行优化,以及启示我们sql语句怎么写,才能更有效率.那么到底mysql到底 ...

  7. Mysql查询优化器浅析

    --Mysql查询优化器浅析 -----------------------------2014/06/11 1 定义    Mysql查询优化器的工作是为查询语句选择合适的执行路径.查询优化器的代码 ...

  8. mysql高性能6章总结(下) mysql查询优化

    6.5查询优化器的局限性 mysql优化器是有局限性的,有时需要我们改写查询以提高效率. 6.5.1关联子查询 子查询是mysql一个很不效率的地方. 这一节首先我们需要了解一下相关子查询:内外部查询 ...

  9. mysql查询优化之二:查询优化器的局限性

    在<mysql查询优化之一:mysql查询优化常用方式>一文中列出了一些优化器常用的优化手段.查询优化器在提供这些特性的同时,也存在一定的局限性,这些局限性往往会随着MySQL版本的升级而 ...

随机推荐

  1. [敏捷软工团队博客]Beta阶段发布声明

    项目 内容 2020春季计算机学院软件工程(罗杰 任健) 博客园班级博客 作业要求 Beta阶段发布声明 我们在这个课程的目标是 在团队合作中锻炼自己 这个作业在哪个具体方面帮助我们实现目标 对Bet ...

  2. 【二食堂】Alpha - Scrum Meeting 8

    Scrum Meeting 8 例会时间:4.18 11:40 - 12:10 进度情况 组员 昨日进度 今日任务 李健 1. 实体的添加和关系的添加实现的有bug,柴博和刘阳进行了帮助issue 1 ...

  3. Vue3+Typescript+Node.js实现微信端公众号H5支付(JSAPI v3)教程--各种填坑

    ----微信支付文档,不得不说,挺乱!(吐槽截止) 功能背景 微信公众号中,点击菜单或者扫码,打开公众号中的H5页面,进行支付. 一.技术栈 前端:Vue:3.0.0,typescript:3.9.3 ...

  4. GPS与AGPS定位服务

    最近客户反馈车子启动从车库开到地面后,机器定位相对OBD内部定位会慢很多. 机器定位主要依赖定位模块 + AGPS辅助定位. 其中定位模块目前主流支持的有以下三种定位系统. 一.GPS(全球定位系统) ...

  5. 021中国大学生程序设计竞赛(CCPC)- 压力测试赛题解

    A.Matrix 挺狗的一道题,从开始冲到最后都没冲出来,都没啥思路. 其实分开考虑每个数的贡献,这个想法也存在过,就是不知道该怎么计算,我们考虑我们单独考虑一个数字\(i(1\leq i\leq n ...

  6. DP秒思维

    DP算法对于大部分题有着良好的能力,但有些题目我们要转换思维,不能直接的设具体的转态.... 最近做了两道秒题,在这里分享一下: https://ac.nowcoder.com/acm/contest ...

  7. 如何抓取直播源及视频URL地址-疯狂URL(教程)

    直播源介绍 首先,我们来快速了解一下什么是直播源,所谓的直播源,其实就说推流地址,推流地址可能你也不知道是什么,那么我再简单说一下,推流地址就是,当某个直播开播的时候,需要将自己的直播状态实时的展示给 ...

  8. zabbix 自定义监控项,监控tomcat访问量

    uv:访客量.每个独立上网电脑视为一位访客.pv:访问量.页面浏览量或者点击量,访客每访问一次记录一次. 1.创建文件 /home/zabbix/pvuv_number.sh [ #/bin/bash ...

  9. dart系列之:dart语言中的特殊操作符

    dart系列之:dart语言中的特殊操作符 目录 简介 普通操作符 类型测试操作符 条件运算符 级联符号 类中的自定义操作符 总结 简介 有运算就有操作符,dart中除了普通的算术运算的操作符之外,还 ...

  10. Java学习(十二)

    今天安装讲师推荐下载了一个叫Hbuiler X的IDE,并且学习了选择器的知识. 作为练习,写了一下的代码 <!DOCTYPE html> <html> <head> ...