为何查询速度会慢mysql
1.慢是指一个查询的响应时间长。一个查询的过程:laravel
2.数据访问sql
3.查询的方式数据库
慢查询分析缓存
问题SQL性能优化
把复杂的SQL分红多个简单SQL并执行,查看具体那个字段会慢,区分度不高。服务器
EXPLAIN函数
显示SQL如何使用索引的执行计划。性能
执行计划的参数:优化
table 显示这一行的数据是关于哪张表的
type 显示链接使用了何种类型。从最好到最差的链接类型为const、eq_reg、ref、range、indexhe和ALL
possible_keys 显示可能应用在这张表中的索引。若是为空,没有可能的索引。能够为相关的域从WHERE语句中选择一个合适的语句
key 实际使用的索引。若是为NULL,则没有使用索引。不多的状况下,MYSQL会选择优化不足的索引。这种状况下,能够在SELECT语句中使用USE INDEX(indexname)来强制使用一个索引或者用IGNORE INDEX(indexname)来强制MYSQL忽略索引
key_len 使用的索引的长度。在不损失精确性的状况下,长度越短越好
ref 显示索引的哪一列被使用了,若是可能的话,是一个常数
rows 扫描请求数据的行数
Extra 关于MYSQL如何解析查询的额外信息
PROFILE
显示SQL执行消耗系统资源的信息。
查询执行的过程
MySQL客户端/服务器通讯协议是“半双工”的。客服端/服务器端均可以向对方发送数据,但不能同时发生。因此咱们没法也无须将一个消息切成小块独立来发送。
这种协议没办法进行流量控制。
客户端发送请求的数据包大小由参数max_allowed_packet限制。若是查询太大,服务端会拒绝接受更多的数据并抛出相应的错误。
服务器端返回的多个数据包,客户端必须完整接受。
1.查询状态 SHOW FULL PROCESSLIST
mysql>SHOW FULL PROCESSLIST; Id User Host db Command Time State Info ------ ------ --------------- ------------ ------- ------ ------ ----------------------- 1 root localhost:61316 laravel_blog Query 0 (NULL) show FULL processlist 2 root localhost:61319 (NULL) Sleep 94 (NULL)
对于一个链接,或者说一个线程,任什么时候刻都有一个状态,该状态表示了MySQL当前正在作什么。
2.查询缓存
-- 查看缓存是否开启 (query_cache_type 为 ON 表示已经开启
mysql> show variables like '%query_cache%';
+------------------------------+----------+ | Variable_name | Value | +------------------------------+----------+ | have_query_cache | YES | | query_cache_limit | 1048576 | | query_cache_min_res_unit | 4096 | | query_cache_size | 20971520 | | query_cache_type | ON | | query_cache_wlock_invalidate | OFF | +------------------------------+----------+
检查sql是否命中缓存。命中则检查一次用户权限后返回,这个检查是经过一个对大小写敏感的哈希查找实现的。两次查询只要有一个字节的不一样就会失败。不然将进入下一个阶段。
当sql中有不肯定的数据时,则不会被缓存。例如用户自定义函数、存储函数、用户变量、临时表、mysql库中的系统表,其查询结果都不会被缓存。
3.查询优化
语法解析器和预处理
MySQL经过关键字将sql语句进行解析,并生成一颗对应的解析树。这个过程解析器主要经过语法规则来验证和解析。好比sql中是否使用了错误的关键字或者关键字的顺序是否正确等。预处理则会根据MySQL规则进一步检查解析树是否合法。好比检查要查询的数据表和数据列是否存在等。
查询优化器
通过前面的步骤生成的语法树被认为是合法的了,而且由优化器将其转化成查询计划。多数状况下,一条查询能够有不少种执行方式,最后都返回相应的结果。优化器的做用就是找到这其中最好的执行计划。
MySQL使用基于成本的优化器,经过计算成本选择其中最小的一个。经过SHOW STATUS LIKE 'Last_query_cost';查当作本。成本的最小单位是随机读取一个4K数据页的成本。
MySQL的查询优化器是一个很是复杂的部件,它使用了很是多的优化策略来生成一个最优的执行计划:
上面列举了一些,随着MySQL的不断发展,优化器使用的优化策略也在不断的进化。
查询执行引擎
在完成解析和优化阶段之后,MySQL会生成对应的执行计划,查询执行引擎根据执行计划给出的指令逐步执行得出结果。整个执行过程的大部分操做均是经过调用存储引擎实现的接口来完成,这些接口被称为handler API。查询过程当中的每一张表由一个handler实例表示。实际上,MySQL在查询优化阶段就为每一张表建立了一个handler实例,优化器能够根据这些实例的接口来获取表的相关信息,包括表的全部列名、索引统计信息等。存储引擎接口提供了很是丰富的功能,但其底层仅有几十个接口,这些接口像搭积木同样完成了一次查询的大部分操做。
返回结果
查询执行的最后一个阶段就是将结果返回给客户端。即便查询不到数据,MySQL仍然会返回这个查询的相关信息,好比该查询影响到的行数以及执行时间等。
若是查询缓存被打开且这个查询能够被缓存,MySQL也会将结果存放到缓存中。
结果集返回客户端是一个增量且逐步返回的过程。有可能MySQL在生成第一条结果时,就开始向客户端逐步返回结果集了。这样服务端就无须存储太多结果而消耗过多内存,也可让客户端第一时间得到返回结果。须要注意的是,结果集中的每一行都会以一个知足①中所描述的通讯协议的数据包发送,再经过TCP协议进行传输,在传输过程当中,可能对MySQL的数据包进行缓存而后批量发送。
性能优化
优化count()查询
count()是一个特殊的函数。能够统计行数、某个列值的数量。在统计列值时要求列值是非空的(不统计NULL)。在统计行数时count(*)不会被扩展成全部的列,而是忽略全部的列。这样写意义清晰,性能好。
优化LIMIT分页
LIMIT 10000,20这样的查询,MySQL须要查询10020条记录后返回最后20记录。通常优化为WHERE id>10000 LIMIT 20。其余优化关联一个冗余表,冗余表只包含主键列和须要排序的数据列。
数据类型优化
选择数据类型的原则:更小的一般更好、简单就好、尽可能避免NULL。
更小的数据类型一般会更快,由于占用更少的磁盘、内存和CPU缓存。
简单的数据类型须要更少的CPU周期。例:int比char的操做代价低。
这里总结几个可能容易理解错误的技巧:
一般来讲把可为NULL的列改成NOT NULL不会对性能提高有多少帮助,只是若是计划在列上建立索引,就应该将该列设置为NOT NULL。
对整数类型指定宽度,好比INT(11),没有任何卵用。INT使用32位(4个字节)存储空间,那么它的表示范围已经肯定,因此INT(1)和INT(20)对于存储和计算是相同的。
UNSIGNED表示不容许负值,大体可使正数的上限提升一倍。好比TINYINT存储范围是-128 ~ 127,而UNSIGNED TINYINT存储的范围倒是0 - 255。
一般来说,没有太大的必要使用DECIMAL数据类型。即便是在须要存储财务数据时,仍然可使用BIGINT。好比须要精确到万分之一,那么能够将数据乘以一百万而后使用BIGINT存储。这样能够避免浮点数计算不许确和DECIMAL精确计算代价高的问题。
TIMESTAMP使用4个字节存储空间,DATETIME使用8个字节存储空间。于是,TIMESTAMP只能表示1970 - 2038年,比DATETIME表示的范围小得多,并且TIMESTAMP的值因时区不一样而不一样。
大多数状况下没有使用枚举类型的必要,其中一个缺点是枚举的字符串列表是固定的,添加和删除字符串(枚举选项)必须使用ALTER TABLE(若是只只是在列表末尾追加元素,不须要重建表)。
schema的列不要太多。缘由是存储引擎的API工做时须要在服务器层和存储引擎层之间经过行缓冲格式拷贝数据,而后在服务器层将缓冲内容解码成各个列,这个转换过程的代价是很是高的。若是列太多而实际使用的列又不多的话,有可能会致使CPU占用太高。
大表ALTER TABLE很是耗时,MySQL执行大部分修改表结果操做的方法是用新的结构建立一个张空表,从旧表中查出全部的数据插入新表,而后再删除旧表。尤为当内存不足而表又很大,并且还有很大索引的状况下,耗时更久。固然有一些奇技淫巧能够解决这个问题,有兴趣可自行查阅。
索引的设计
索引的优势:大大减小了服务器须要扫描的数据量、帮主服务器避免排序和临时表、能够将随机I/O变为顺序I/O;
“三星系统”:索引将相关的记录放到一块儿则得到一星;若是索引中的数据顺序和查找中的排序顺序一致则得到二星;若是索引中的列包含了查询中须要的所有列则得到三星。
注:若是在EXPLAIN中看到有索引合并(Extra字段出现Using union),应该好好检查一下查询和表的结构,看是否是已是最优的。
参考资料
Baron Scbwartz 等著;宁海元 周振兴等译;高性能MySQL(第三版); 电子工业出版社, 2013