MySQL 性能优化
1. 灵魂拷问
- MySQL的索引在执行过程中是如何被使用的?
- MySQL的表数据和索引在底层是如何被使用的?
- 索引覆盖是什么?索引覆盖如何优化检索性能
- 组合索引和单列所有哪个更好?
- 聚集索引和非聚集索引存储方式有什么不同
- B+ Tree和B Tree的区别
2.1 MySQL架构
2.1.1 结构图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CsccXQcU-1595768400184)(http://zhaox.github.io/assets/images/MySQL.png)]
第一层负责连接管理、授权认证、安全等
第二层负责解析查询(编译SQL),并对其进行优化(如调整表的读取顺序,选择合适的索引等)。对于SELECT语句,在解析查询前,服务器会先检查查询缓存,如果能在其中找到对应的查询结果,则无需再进行查询解析、优化等过程,直接返回查询结果。存储过程、触发器、视图等都在这一层实现。
第三层是存储引擎,存储引擎负责在MySQL中存储数据、提取数据、开启一个事务等等
2.1.2Optimizer优化器
语法解析和查询重写之后,MySQL会根据语法树和数据的统计信息对SQL进行优化,包括决定表的读取顺序、选择合适的索引等,最终生成SQL的具体执行步骤
2.1.3 Pluggable Storage Engines存储引擎
存储引擎 | 优点 | 缺点 |
---|---|---|
InnoDB | 5.5版本后MySQL默认数据库,支持事务,比MyISAM处理速度稍慢 | 非常复杂,性能较一些简单的引擎要差一点儿。空间占用比较多。 |
MyISAM | 高速引擎,拥有极高的插入,查询速度 | 不支持事务,不支持行锁、崩溃后数据不容易修复 |
Archive | 将数据压缩后存储,非常适合存储大量的独立的,作为历史记录的数据 | 只能进行插入和查询操作,非事务型 |
CSV | 是基于CSV格式文件存储数据(应用于跨平台数据交换) | |
Memory | 内存存储引擎,拥有极高的插入,更新和查询效率 | 占用和数据量成正比的内存空间,只在内存上保存数据,意味着数据可能会丢失,并发能力低下。不支持BLOB或TEXT类型的列 |
Falcon | 一种新的存储引擎,支持事务处理,传言可能是InnoDB的替代者 |
最常用的是InnoDB和MyISAM,InnoDB和MyISAM存储引擎区别
类别 | InnoDB | MyISAM |
---|---|---|
存储文件 | .frm 表定义文件 .idb 数据文件和索引文件 |
.frm 表定义文件 .myd 数据文件 .myi 索引文件 |
锁 | 表锁、行锁 | 表锁 |
事务 | 支持 | 不支持 |
CRUD | 读、写 | 读多 |
count | 扫表 | 专门存储的地方 |
索引结构 | B+ Tree | B+ Tree |
2.1.4 MySQL物理文件
1. 日志文件(顺序IO)
MySQL通过日志记录了数据库操作信息和错误信息。常用的日志文件包括错误日志、二进制日志、查询日志、慢查询 日志和事务Redo 日志、中继日志等
错误日志(errorlog)
默认是开启的,而且从5.5.7以后无法关闭错误日志,错误日志记录了运行过程中遇到的所有严重的错误信息,以及MySQL每次启动和关闭的详细信息。二进制日志(bin log)
默认是关闭的。binlog记录了数据库所有的ddl语句和dml语句,但不包括select语句内容,语句以事件的形式保存,描述了数据 的变更顺序,binlog还包括了每个更新语句的执行时间信息。如果是DDL语句,则直接记录到binlog日志,而DML语 句,必须通过事务提交才能记录到binlog日志中。
binlog主要用于实现mysql主从复制、数据备份、数据恢复。通用查询日志(general query log)
默认情况下通用查询日志是关闭的慢查询日志(slow query log)
默认是关闭的。重做日志(redo log)
作用:确保事务的持久性。防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。-
回滚日志(undo log)
保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读
-
中继日志(relay log)
是在主从复制环境中产生的日志。主要作用是为了从机可以从中继日志中获取到主机同步过来的SQL语句,然后执行到从机中。
2. 数据文件(随机IO)
- InnoDB数据文件
.frm文件:主要存放与表相关的数据信息,主要包括表结构的定义信息
.ibd:使用独享表空间存储表数据和索引信息,一张表对应一个ibd文件。
ibdata文件:使用共享表空间存储表数据和索引信息,所有表共同使用一个或者多个ibdata文件 - MyIsam数据文件
.frm文件:主要存放与表相关的数据信息,主要包括表结构的定义信息
.myd文件:主要用来存储表数据信息。
.myi文件:主要用来存储表数据文件中任何索引的数据树。
3. 顺序IO和随机IO
- 顺序I/O一般只需扫描一次数据、所以、缓存对它用处不大
- 顺序I/O比随机I/O快
- 随机I/O通常只要查找特定的行、但I/O的粒度是页级的、其中大部分是浪费的,而顺序I/O所读取的数据、通常发生在想要的数据块上的所有行更加符合成本效益
2.1.5 MySQL执行流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-juGC81EP-1595768400190)(https://ask.qcloudimg.com/http-save/yehe-1446357/l7kw2rr47e.jpeg?imageView2/2/w/1620)]
客户端发送一条查询给服务器;
服务器通过权限检查之后,先会检查查询缓存,如果命中了缓存,则立即返回存储在缓存中的结果。否则进入下一阶段;
服务器端进行SQL解析、预处理,再由优化器根据该SQL所涉及到的数据表的统计信息进行计算,生成对应的执行计划;
MySQL根据优化器生成的执行计划,调用存储引擎的API来执行查询;
将结果返回给客户端。
SQL执行的最大瓶颈在于磁盘的IO,即数据的读取 ;不同SQL的写法,会造成不同的执行计划的执行,而不同的执行计划在IO的上面临完全不一样的数量级,从而造成性能的差距;
所以,我们说,优化SQL,其实就是让查询优化器根据程序猿的计划选择匹配的执行计划,来减少查询中产生的IO;
2.1.6 SQL解析顺序
SELECT DISTINCT
< select_list >
FROM
< left_table > < join_type >
JOIN < right_table > ON < join_condition >
WHERE
< where_condition >
GROUP BY
< group_by_list >
HAVING
< having_condition >
ORDER BY
< order_by_condition >
LIMIT < limit_number >
执行顺序:
FROM <left_table>
ON <join_condition>
<join_type> JOIN <right_table>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
SELECT
DISTINCT <select_list>
ORDER BY <order_by_condition>
LIMIT <limit_number>
2.2 MySQL索引
2.2.1 索引是什么
- 高效获取数据的数据结构,相当于书的目录
- 使用B+树结构(多路搜索树,并不一定是二叉的)
- 索引是存储在磁盘文件中的(可能单独的索引文件中,也可能和数据一起存储在数据文件中)
2.2.2 索引的优势和劣势
优势:
- 可以提高数据检索的效率,降低数据库的IO成本
- 通过索引对数据进行排序,降低数据排序的成本,降低CPU消耗
劣势:
- 空间换时间,索引会占据磁盘空间
- 能提高效率,但是降低更新表的效率
2.2.3 常用索引分类
- 单列索引
- 普通索引:MySQL中基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值,纯粹为了查询数
据更快一点。 - 唯一索引:索引列中的值必须是唯一的,但是允许为空值。
- 主键索引:是一种特殊的唯一索引,不允许有空值
- 组合索引
- 在表中的多个字段组合上创建的一个索引
- 组合索引的使用,需要遵循最左前缀原则(最左匹配原则)。
- 一般情况下,建议使用组合索引代替单列索引(主键索引除外)。
2.2.4 索引的存储结构
-
索引是在存储引擎中实现的。
MyISAM和InnoDB存储引擎:只支持BTREE索引, 也就是说默认使用BTREE,不能够更换
2.2.5 B树和B+树
-
数据结构在线演示
https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
-
B树结构
B树是为了磁盘或其它存储设备而设计的一种多叉平衡查找树(下面你会看到,相对于二叉,B树每个内结点有多个分支,即多叉)
B树的高度一般都是在2-4这个高度,树的高度直接决定IO读写的次数以及查询时间复杂度(log(n))。
-
B树三层可以存储bigint类型的主键10亿条
InnoDB存储引擎中页的大小为16KB,一般表的主键类型为INT(占用4个字节)或BIGINT(占用8个字节),指针 类型也一般为4或8个字节,也就是说一个页(B+Tree中的一个节点)中大概存储16KB/(8B+8B)=1K个键值(因为 是估值,为方便计算,这里的K取值为〖10〗3)。也就是说一个深度为3的B+Tree索引可以维护103 * 10^3 * 10^3 = 10亿 条记录。
如果是三层树结构---支撑的数据可以达到20G,如果是四层树结构---支撑的数据可以达到几十T
- B树和B+树的区别
- B树是非叶子节点和叶子节点都会存储数据。
- B+树只有叶子节点才会存储数据,而且存储的数据都是在一行上,而且这些数据都是有指针指向的,是有顺链表
2.2.6 聚集索引(InnoDB)
InnoDB存储引擎的数据组织方式,是聚簇索引表:完整的记录,存储在主键索引中,通过主键索引,就可以获取记录所有的列,也就是说表数据和索引是在一起,这就是聚集索引
InnoDB要求表必须有主键(MyISAM 可以没有),如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL 自动为 InnoDB 表生成一个隐含字段作为主键,类型为长整形。
- 主键索引
- 辅助索引
聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主
键,然后用主键到主索引中检索获得记录
2.2.7 非聚集索引(MyISAM)
B+树叶子节点只会存储数据行(数据文件)的指针,简单来说数据和索引不在一起,就是非聚集索引。非聚集索引中的主键索引和辅助索引都会存储指针的值
- 主键索引
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mEgG5yIm-1595768400196)(http://ww1.sinaimg.cn/large/007OGB2sgy1g5fk8x2a3kj31b812aar4.jpg)]
- 非主键索引
在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复。
2.2.8 组合索引使用
为了节省mysql索引存储空间以及提升搜索性能,可建立组合索引(能使用组合索引就不使用单列索引)
例如:创建如下的一个组合索引,相当于建立了col1,col1 col2,col1 col2 col3三个索引:
以下语句会创建一颗B+tree,但是它相对于三颗索引树的功效
ALTER TABLE 'table_name' ADD INDEX index_name('col1','col2','col3')
如何选择哪些列用来创建组合索引?
- 常出现在where条件中的列,建议用来创建组合索引,至于组合索引中的顺序,是很重要的,因为组合索引会使用到最左前缀原则。但是因为MySQL中存在查询优化器,所以你的书写SQL条件的顺序,不一定是执行时候的where条件顺序。
- 常出现在order by和group by语句中的列。最后按照顺序去创建组合索引。
- 常出现在select语句中的列,也建议按照顺序,创建组合索引
最左前缀原则
顾名思义,就是最左优先,这个最左是针对于组合索引和前缀索引,理解如下:
- 最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
- =和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式
2.2.9 如何使用索引
哪些情况需要创建索引
- 主键自动建立唯一索引
- 频繁作为查询条件的字段应该创建索引(业务)
- 多表关联查询中,关联字段应该创建索引
- 查询中统计或者分组字段,应该创建索引
- 查询中排序的字段,应该创建索引
哪些情况不需要创建索引
- 表记录太少
- 经常进行增删改操作的表
- 频繁更新的字段
- where条件里使用频率不高的字段
2.3 MySQL性能优化
类型 | 解释 |
---|---|
id | SELECT 查询的标识符. 每个 SELECT 都会自动分配一个唯一的标识符. |
select_type | SELECT 查询的类型. table: 查询的是哪个表partitions: 匹配的分区 |
type | join 类型 |
possible_keys | 此次查询中可能选用的索引key: 此次查询中确切使用到的索引. |
ref | 哪个字段或常数与 key 一起被使用 |
rows | 显示此查询一共扫描了多少行. 这个是一个估计值. filtered: 表示此查询条件所过滤的数据的百分比 |
extra | 额外的信息 |
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8ta0nOc8-1595768400198)(https://i6448038.github.io/img/explain/explain.png)]
2.3.1 type讲解
显示的是单位查询的连接类型或者理解为访问类型,访问性能依次从好到差
1. system
2. const
3. eq_ref
4. ref
5. fulltext
6. ref_or_null
7. unique_subquery
8. index_subquery
9. range
10. index_merge
11. index
12. ALL
除了all之外,其他的type都可以使用到索引
除了index_merge之外,其他的type只可以用到一个索引
最少要使用到range级别
默认数据导入:https://github.com/datacharmer/test_db/blob/master/employees.sql
-
System
表中只有一行数据或者是空表
-
const
使用唯一索引或者主键,返回记录一定是1行记录的等值where条件时,通常type是const。其他数据库也叫做唯一索引扫描
-
eq_ref
此类型通常出现在多表的 join 查询, 表示对于前表的每一个结果, 都只能匹配到后表的一行结果. 并且查询的比较操作通常是 =, 查询效率较高
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lxSw8K3Q-1595768400201)(http://ww1.sinaimg.cn/large/007OGB2sgy1g5fx1vtac9j310s0cg0u9.jpg)]
-
ref
针对非唯一性索引,使用等值(=)查询。或者是使用了最左前缀规则索引的查询。
- 组合索引
- 非唯一索引
-
fulltext
全文索引检索,全文索引的优先级很高,若全文索引和普通索引同时存在时,mysql不管代价,优先选择使用全文索引
-
req_or_null
与ref方法类似,只是增加了null值的比较。实际用的不多。
-
unique_subquery
用于where中的in形式子查询,子查询返回不重复值唯一值
-
index_subquery
用于in形式子查询使用到了辅助索引或者in常数列表,子查询可能返回重复值,可以使用索引将子查询去重
-
range
索引范围扫描,常见于使用>,<,is null,between ,in ,like等运算符的查询中
-
index_merge
表示查询使用了两个以上的索引,最后取交集或者并集,常见and,or的条件使用了不同的索引,官方排序这个在ref_or_null之后,但是实际上由于要读取所个索引,性能可能大部分时间都不如range
-
index
select结果列中使用到了索引,type会显示为index。
索引扫描,把索引从头到尾扫一遍,常见于使用索引列就可以处理
All
2.3.2 extra讲解
-
using index
查询时不需要回表查询,直接通过索引就可以获取查询的结果数据
- 表示相应的SELECT查询中使用到了覆盖索引(covering index),避免访问表的数据行
- 如果同时出现using where,说明索引被用来执行查找索引键值
- 如果没有出现using where,表明索引用来读取数据而非执行查找动作
-
using where
表示Mysql将对storage engine提取的结果进行过滤,过滤条件字段无索引
-
using index condition
Using index condition 会先条件过滤索引,过滤完索引后找到所有符合索引条件的数据行,随后用 WHERE 子句中的其他条件去过滤这些数据行
-
using filesort
排序时无法使用到索引时,就会出现这个。常见于order by和group by语句中说明MySQL会使用一个外部的索引排序,而不是按照索引顺序进行
2.3.3 优化SQL语句
创建索引注意:
为搜索字段(where中的条件)、排序字段、select查询列,创建合适的索引,
不过要考虑数据的业务场景:查询多还是增删多?
尽量建立组合索引并注意组合索引的创建顺序,按照顺序组织查询条件、尽量将筛选粒度大的查询条件放到最左边。
尽量使用覆盖索引
SELECT语句中尽量不要使用*。
order by、group by语句要尽量使用到索引
索引优化
- 全值匹配
- 最佳左前缀法则( 带头索引不能死,中间索引不能断)
- 不要在索引上做计算
- 范围条件右边的列失效
- 尽量使用覆盖索引( 尽量使用覆盖索引(只查询索引的列),也就是索引列和查询列一致,减少select)
- 索引字段上不要使用不等
- 索引字段上不要判断null(索引字段上使用 is null / is not null 判断时,会导致索引失效而转向全表扫描)
- 索引字段使用like不以通配符开头(索引字段使用like以通配符开头(‘%字符串’)时,会导致索引失效而转向全表扫描)
- 索引字段字符串要加单引号
- 索引字段不要使用or
- JOIN两张表的关联字段最好都建立索引,而且最好字段类型是一样的
其他优化
- WHERE条件中尽量不要使用1=1、not in语句(建议使用not exists)
- 不用 MYSQL 内置的函数,因为内置函数不会建立查询缓存。
- 尽量不使用count(*)、尽量使用count(主键)
总结
假设index(a,b,c)
where语句 | 索引是否被引用 |
---|---|
where a = 3 | |
where a = 3 and b = 5 | |
where a = 3 and b = 5 and c = 4 | |
where b = 3 或者 where b = 3 and c = 4 或者 where c = 4 | |
where a = 3 and c = 5 | |
where a = 3 and b > 4 and c = 5 | |
where a = 3 and b like 'kk%' and c = 4 | |
where a = 3 and b like '%kk' and c = 4 | |
where a = 3 and b like '%kk%' and c = 4 | |
where a = 3 and b like 'k%kk%' and c = 4 |
where语句 | 索引是否被引用 |
---|---|
where a = 3 | Yes,使用到a |
where a = 3 and b = 5 | Yes,使用到a,b |
where a = 3 and b = 5 and c = 4 | Yes,使用到a,b,c |
where b = 3 或者 where b = 3 and c = 4 或者 where c = 4 | No |
where a = 3 and c = 5 | Yes,使用到了a,但是c不可以,因为b断了 |
where a = 3 and b > 4 and c = 5 | Yes,使用到了a和b,c不能在范围之后,b断了 |
where a = 3 and b like 'kk%' and c = 4 | Yes,使用到a,b,c |
where a = 3 and b like '%kk' and c = 4 | Yes,使用到了a |
where a = 3 and b like '%kk%' and c = 4 | Yes,使用到了a |
where a = 3 and b like 'k%kk%' and c = 4 | Yes,使用到a,b,c |
2.3.4 服务器参数调优
- 设置足够大的innodb_buffer_pool_size,将数据读取到内存中(建议innodb_buffer_pool_size设置为总内存大小的3/4或者4/5.)
怎样确定 innodb_buffer_pool_size 足够大。数据是从内存读取而不是硬盘?
SHOW GLOBAL STATUS LIKE 'innodb_buffer_pool_pages_%';
- 内存预热
将磁盘数据在MySQL Server启动的时候,读取到内存中。
-
降低磁盘写入次数
对于生产环境来说,很多日志是不需要开启的,比如:通用查询日志
-
慢查询日志、错误日志使用足够大的写入缓存 innodb_log_file_size
推荐 innodb_log_file_size 设置为 0.25 * innodb_buffer_pool_size
设置合适的innodb_flush_log_at_trx_commit,和日志落盘有关系
提高磁盘读写
可以考虑使用SSD硬盘,不过得考虑成本是否合适
2.3.5 硬件选购和参数优化
- 内存相关
内存的 IO 比硬盘的速度快很多,可以增加系统的缓冲区容量,使数据在内存停留的时间更长,以减少磁盘的 IO
- 磁盘 I/O 相关
- 使用 SSD 或 PCle SSD 设备,至少获得数百倍甚至万倍的 IOPS 提升
- 购置阵列卡同时配备 CACHE 及 BBU 模块,可以明显提升 IOPS
- 尽可能选用 RAID-10,而非 RAID-5
- 配置 CUP 相关
- 在服务器的 BIOS 设置中,调整如下配置:
- 选择 Performance Per Watt Optimized(DAPC)模式,发挥 CPU 最大性能
- 关闭 C1E 和 C States 等选项,提升 CPU 效率
- Memory Frequency(内存频率)选择 Maximum Performance
2.3.6 SQL设计层面优化
- 表设计
设计中间表,一般针对于统计分析功能,或者实时性不高的需求(OLTP、OLAP)
为减少关联查询,创建合理的冗余字段(考虑数据库的三范式和查询性能的取舍,创建冗余字段还需要注意数据一致性问题
每张表建议都要有一个主键(主键索引),而且主键类型最好是int类型,建议自增主键(不考虑分布式系统的情况下)
- 选择合适的数据类型
使用可以存下数据最小的数据类型
使用简单的数据类型。int 要比 varchar 类型在mysql处理简单
尽量使用 tinyint、smallint、mediumint 作为整数类型而非 int
尽可能使用 not null 定义字段,因为 null 占用4字节空间
尽量少用 text 类型,非用不可时最好考虑分表
尽量使用 timestamp 而非 datetime
单表不要有太多字段,建议在 20 以内
-
拆分表
对于表中经常不被使用的字段或者存储数据比较多的字段,考虑拆表
对于字段太多的大表,考虑垂直拆表(比如一个表有100多个字段
比如商品表中会存储商品介绍,此时可以将商品介绍字段单独拆解到另一个表中,使用商品ID关联)
- 垂直拆分:将表中多个列分开放到不同的表中。例如用户表中一些字段经常被访问,将这些字段放在一张表中,另外一些不常用的字段放在另一张表中。插入数据时,使用事务确保两张表的数据一致性。
- 水平拆分:按照行进行拆分。例如用户表中,使用用户ID,对用户ID取10的余数,将用户数据均匀的分配到0~9的10个用户表中。查找时也按照这个规则查询数据。
-
读写分离
一般情况下对数据库而言都是“读多写少”。换言之,数据库的压力多数是因为大量的读取数据的操作造成的。我们可以采用数据库集群的方案,使用一个库作为主库,负责写入数据;其他库为从库,负责读取数据。这样可以缓解对数据库的访问压力。
2.3.7 数据库架构调优
- 分区分表
- 业务分库
- 主从同步与读写分离
- 数据缓存
- 主从热备与HA双活
2.4 实战优化
-
慢SQL优化挑战赛
表结构
CREATE TABLE `a` ( `id` int(11) NOT NULL AUTO_INCREMENT, `seller_id` bigint(20) DEFAULT NULL, `seller_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, `gmt_create` varchar(30) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=32744 DEFAULT CHARSET=utf8; CREATE TABLE `b` ( `id` int(11) NOT NULL AUTO_INCREMENT, `seller_name` varchar(100) DEFAULT NULL, `user_id` varchar(50) DEFAULT NULL, `user_name` varchar(100) DEFAULT NULL, `sales` bigint(20) DEFAULT NULL, `gmt_create` varchar(30) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=32744 DEFAULT CHARSET=utf8; CREATE TABLE `c` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` varchar(50) DEFAULT NULL, `order_id` varchar(100) DEFAULT NULL, `state` bigint(20) DEFAULT NULL, `gmt_create` varchar(30) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=458731 DEFAULT CHARSET=utf8;
待优化SQL
select a.seller_id, a.seller_name, b.user_name, c.state from a,b,c where a.seller_name = b.seller_name and b.user_id = c.user_id and c.user_id = 17 and a.gmt_create BETWEEN DATE_ADD(NOW(), INTERVAL 600 MINUTE) and DATE_ADD(NOW(), INTERVAL 600 MINUTE) order by a.gmt_create;
创建索引
-- A表上创建索引: Alter table a add index ind_a_gmt_create(gmt_create); -- B表上创建索引: Alter table b add index ind_b_seller_name(seller_name); -- C表创建索引: Alter table c add index ind_c_user_id(user_id);
隐式转换
-- a表:gmt_create使用了varchar来存储,在5.6支持更高时间精度后,将会发生隐式转换。
-- b表:a表和b表的seller_name字段在COLLATE定义上不一致,也会导致隐式转换。
-- c表:b表和c表的user_id字段都定义为了varchar,但是SQL传入为数字,也会导致隐式转换。
alter table a modify column gmt_create datetime;
alter table a modify column seller_name varchar(100) ;
alter table c modify column user_id bigint;
-
优化LIMIT分页
尽可能的使用覆盖索引扫描
SELECT ID, ADDRESS FROM PROJECT ORDER BY STATUS LIMIT 64000, 100
SELECT SQL_NO_CACHE `b_regbroker`.*,`db`.`name`,db.sub_branch,db.account,db.card_img,mu.UserName,pb.broker_name,pb.mobile_tel from b_regbroker LEFT JOIN myuser mu on mu.UserGUID=b_regbroker.ModifiedBy LEFT JOIN b_regbroker pb on pb.b_regbrokerId=b_regbroker.parent_brokerId LEFT JOIN b_regbroker_bank db on db.regbroker_id = b_regbroker.b_regbrokerId and isdel=0 and isdefault=1 where b_regbroker.`status` in (1,2) and b_regbroker.token='rkqqnn1427611021' and b_regbroker.is_delete=0 and IFNULL(b_regbroker.capacity_des,'') <> '9108' ORDER BY CreatedOn desc LIMIT 126000, 3000;
SELECT p.ID,p.ADDRESS
FROM PROJECT p
INNER JOIN (
SELECT ID FROM PROJECT ORDER BY STATUS LIMIT 64000, 100
) AS tmp
ON p.ID = tmp.ID
SELECT SQL_NO_CACHE `b_regbroker`.*,`db`.`name`,db.sub_branch,db.account,db.card_img,mu.UserName,pb.broker_name,pb.mobile_tel
from b_regbroker
LEFT JOIN myuser mu on mu.UserGUID=b_regbroker.ModifiedBy
LEFT JOIN b_regbroker pb on pb.b_regbrokerId=b_regbroker.parent_brokerId
LEFT JOIN b_regbroker_bank db on db.regbroker_id = b_regbroker.b_regbrokerId
and isdel=0 and isdefault=1
where b_regbroker.`status` in (1,2)
and b_regbroker.token='rkqqnn1427611021'
and b_regbroker.is_delete=0
and IFNULL(b_regbroker.capacity_des,'') <> '9108'
AND b_regbroker.CreatedOn <= '2016-07-23 14:19:04'
ORDER BY CreatedOn desc
LIMIT 3000;
3. 参考
- https://zhaox.github.io/2016/06/24/mysql-architecture【MySQL的多存储引擎架构】
- https://segmentfault.com/a/1190000010681611【MySQL三层逻辑架构】
- https://www.jianshu.com/p/1f17a496f14e【MySQL架构及历史】
- https://www.cnblogs.com/wy123/p/7102128.html【MySQL 物理文件体系结构的简单整理说明】
- http://database.51cto.com/art/201901/590564.htm【一份超详细的MySQL高性能优化实战总结!】
- https://blog.csdn.net/asdfsadfasdfsa/article/details/83015488【从数据库层面理解:随机 I/O & 顺序 I/O】
- https://juejin.im/post/59d83f1651882545eb54fc7e#heading-26【MySQL 性能优化技巧】
- https://www.cnblogs.com/nullzx/p/8729425.html【B树和B+树的插入、删除图文详解】
- https://blog.51cto.com/13912525/2313851【随机读写与顺序读写怎么去理解】
- https://www.kancloud.cn/kancloud/theory-of-mysql-index/41851【MySQL索引背后的数据结构及算法原理】
- https://www.jianshu.com/p/5600781f67ba 【聊一聊B+树】
- https://www.jianshu.com/c/cd1570246385【高性能MySQL】
- https://blog.csdn.net/qq_26222859/article/details/80631121【b+树图文详解】
- https://juejin.im/post/5d351303f265da1bd30596f9【[灵魂拷问]MySQL面试高频一百问(工程师方向)】
- https://juejin.im/post/5d3423c35188252bd255de32【MySql优化之索引原理与 SQL 优化】
- https://juejin.im/post/5d1c32bf51882551253e483d【MySQL 中NULL和空值的区别?】
- https://my.oschina.net/benhaile/blog/849499【记一次mysql性能优化过程】
- https://yq.aliyun.com/articles/645477【MySQL高性能优化实战总结!】
- https://blog.csdn.net/weixin_39152648/article/details/80250741【MySQL优化原理,这一篇就够了!】
- https://www.bilibili.com/video/av56419635/【MySQL性能优化视频】
- https://cloud.tencent.com/developer/article/1056041【MySQL性能优化的最佳20+条经验】
- https://www.centos.bz/2017/09/mysql-big-table-performance-optimize/【MySQL大表性能优化方案】
- http://www.365jz.com/article/24732【MySQL性能优化提升访问速度的方法】
- https://juejin.im/post/5d23ef4ce51d45572c0600bc【我以为我对Mysql索引很了解,直到我遇到了阿里的面试官】
- https://juejin.im/post/5d1758d06fb9a07eed351405【推荐收藏!MySQL重要知识点/面试题总结。】
- https://juejin.im/post/5d2335846fb9a07f021a2509#heading-127【客官,这里有一份《MySQL 必知必会》读书笔记,请您笑纳!】
- https://www.jianshu.com/p/9fab9266be84【一次非常有意思的SQL优化经历:从30248.271s到0.001s】
- https://www.jianshu.com/p/569569b8b40c【mysql数据库设计中的14个技巧】
- https://www.jianshu.com/p/a14ea51a4458【心里没点B树,怎能吃透数据库索引底层原理?】
- https://yq.aliyun.com/articles/136363?spm=5176.100240.searchblog.32.oYlhtr【速围观!慢SQL数据库挑战赛】
- https://cloud.tencent.com/developer/article/1200822【MySQL探秘(二):SQL语句执行过程详解】、
- https://www.cnblogs.com/annsshadow/p/5037667.html【MySQL架构总览->查询执行流程->SQL解析顺序】
- https://github.com/datacharmer/test_db【mysql test_db】