MySQL千万级别优化·中

Wesley13
• 阅读 619

MySQL 千万级别的查询优化手段·中

单列索引(假设在 v_record 表中存在 id 列的索引)

1、WHERE 条件使用

​ EXPLAIN SELECT * FROM v_record WHERE id = 2

​ 结论:利用索引进行回表查询

2、SELECT 字段使用

​ SELECT 字段使用索引列的话,结果就是索引覆盖查询,EXPLAIN结果中Extra列的结果就是Using index

​ 如:

​ EXPLAIN SELECT id FROM v_record WHERE id = 2

​ 结论:直接通过索引信息返回所需信息,不需要回表

3、GROUP BY 条件

​ EXPLAIN SELECT id FROM v_record GROUP BY id

​ 结论:记住其实这样的情况下,总体的查询性能怎么样,需要结合 EXPLAIN 的结果分析,如果 EXPLAIN 中的 rows 列结果很大,总体性能耗时也是一个不可以接受的问题,可以利用 LIMIT 关键字进行处理

4、ORDER BY 条件

​ EXPLAIN SELECT id FROM v_record ORDER BY id DESC

​ 结论:必须谨记,MySQL中 GROUP BY 结果中已经隐藏的进行了一次 ORDER BY 操作,如果当前的 SELECT 语句中,没有ORDER 需求的话,那么可以显示指定 ORDER BY NULL进行禁用自动的GROUP BY 的ORDER BY 操作

5、SELECT 、WHERE、GROUP BY、ORDER BY混合情况

​ EXPLAIN SELECT id FROM v_record WHERE id = 2 GROUP BY id LIMIT 10

​ 结论: 通过索引查询索引的信息然后通过索引进行分组,这个具体的耗时需要根据等待的分组的信息的大小进行确定,在CMS中使用的很多,一般一个分页的数据在30~50左右,这样的话,整体的性能实在可以接受的范围

多列索引 【假设在 v_record 表中有一个主键 id, 复合索引(vote_id, group_id)】

1、索引的列的选择性

​ 索引的列的选择性的高低决定了复合索引的顺序,经验法则就是:选择性高的放在前面,具体的选择性的高低判断是通过去重后的数据集与总数据量的倍数决定的,因为重复的值越多,选择性就更低这样的列一般不建议建立索引,一定要建立的话,可以建立在复合索引的后面,如果是单利索引的话,当前列的重复值已经超过总数据量的70%左右我们不建议建立索引,因为就算是大表的话,索引的性能也会很低,特大的表就算是索引性能也低,建议分区或者分布式部署数据库。

2、最左前缀原则以及适应的条件

​ 最左前缀原则意思就是MySQL的索引的顺序是按照建立索引的顺序进行数据的索引的,如果在底层需要利用好建立的索引的话,那么就一定让MySQL能够分析出可以利用最左前缀原则的索引,如果MySQL优化引擎觉得不能利用索引的话,那么建立的复合多列索引就不会生效!如下两个示例:

EXPLAIN SELECT * FROM v_record WHERE group_id = 2 AND vote_id = 10

EXPLAIN SELECT * FROM v_record WHERE vote_id = 10 AND group_id = 10

上面的这条语句就可以利用复合索引 (vote_id, group_id),但是下面的这条语句就不会利用复合索引而不论调整两列的顺序;这个是因为根据语句就是要去查询 group_id 等于 2 或者 vote_id 等于 10的结果集合,但是我们知道在 vote_id 上我们可以使用复合索引 (vote_id, group_id) 生效,但是对于 group_id 而言,没有任何一个索引可以生效,索引整个语句索引就不会生效,解决方案就是在 group_id 上建立一个索引就可以解决问题:

EXPLAIN SELECT * FROM v_record WHERE group_id = 2 OR vote_id = 10

3、WHERE 条件

EXPLAIN SELECT * FROM v_record = 2 AND group_id = 2(复合索引生效)

EXPLAIN SELECT * FROM group_id = 2 AND v_record = 2(复合索引生效)

EXPLAIN SELECT * FROM v_record = 2 OR group_id = 2(索引不生效)

​ 结论:建议整体的语句使用 AND 进行连接,OR条件可以转换为 IN 的情况,可以优化为IN或者AND进行处理。善于使用让引擎容易理解的方式使用索引处理查询

4、GROUP BY 条件

EXPLAIN SELECT * FROM v_record WHERE vote_id = 2 GROUP BY group_id(紧凑索引扫描)

EXPLAIN SELECT * FROM v_record GROUP BY vote_id (松散索引扫描)

结论:利用好复合索引,紧凑索引、松散索引

5、ORDER BY 条件

EXPLAIN SELECT * FROM v_record WHERE vote_id = 2 ORDER BY group_id

结论:利用好复合索引

6、索引覆盖

索引覆盖含义就是查询的列就是索引列的一部分或者全部列 或者 聚簇索引列,COUNT(*) 等的时候,这样的就可以避免让引擎进行回表查询数据行的数据并拼接后返回。

多列搜索

​ 在CMS系统或者报表系统中,我们一般会利用多列进行条件过滤找到自己需要的列,这样的话,建议使用好复合索引,将常用的列放入复合索引的各个索引中,可以利用好IN关键字,一般如果搜索条件存在区间或者前缀模糊搜索的话,建议放在复合索引列的最后,避免后续的列无法利用索引。

LIMIT 建议

​ 如果当前的数据偏移量过大的话,使用 LIMIT 这个是一个特大的性能问题,无论怎么优化都是一个问题,这样的话,我们建议数据进行灰暗删除,不进行真正的删除,使用标识位处理即可,这样利用表的主键进行偏移或者索引列进行偏移,这样对于千万级别的表而言,性能不是问题。

MySQL的优化策略

1、在条件中如果是AND连接的话,至于具体的条件的顺序不重要,MySQL会自动的利用上索引,如果是复合索引的话,索引的列在SQL的书写上不需要满足最左前缀原则,MySQL自动从最左原则的索引开始自动匹配

2、如果是OR条件的话,MySQL会自动的判断各列是否有索引,如果存在的话,那么MySQL会自动的在各列上使用索引查询,然后使用 UNION操作合并结果集

分析SQL善于利用 EXPLAIN 关键字

id

select_type

table

partitions

type

possible_keys

key

key_len

ref

rows

filtered

Extra

1

SIMPLE

v_record

const

PRIMARY

PRIMARY

4

const

1

100

一个 EXPLIAN 结果中重要查看 第一: select_type、type、key、ref、rows、Extra列的结果

select_type列可以查出当前的查询的类型,当前的是简单的查询

type: 看出结果类型,是NULL、const等

key:当前使用的索引列

rows:结果集的数据量

Extra:额外的信息,这个取决于MySQL服务器层面,上面都是InnoDB存储引擎级别的分析结果

MySQL中的InnoDB的索引特性分析

​ MySQL中InnoDB引擎分为聚簇索引、二级索引,InnoDB的数据是根据聚簇索引进行B+·Tree存储的,每个二级索引中都包含当前的聚簇索引列的值,因为在InnoDB中聚簇索引的值每列都是唯一的。因此可以通过o(1)查询出结果,查询性能极高的就是利用聚簇索引进行查询,而且二级索引的数据查找也是通过聚簇索引的,因此我们经常听到,二级索引需要二次查找:具体的原因就是二级索引就是利用的聚簇索引值进行查找的。

紧凑索引与松散索引

​ 如果只利用了一部分复合索引,那么此时就是松散索引查询,如果利用了全部的复合索引的话,此时就是紧凑索引

特大表的处理手段

​ 大表中进行全表查询中无论怎么优化都可能是个问题,这样的话:初期可以采用分区进行过度,最后我们建议分布式部署(取决于索引用上了后,性能也无法提升的时候)

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
mysql5.6 分页查询优化
mysql5.6分页查询优化场景:表结构:主键(非自增)contentCode(varchar),过滤条件列为updateTime(timeStamp),已经为timestamp建立索引。搜索sql为:SELECTFROMmy_hello_tableWHEREupdat
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这