MySQL是我们非常常用的关系型数据库,非常重要,所以在这里给大家整理下MySQL的高级内容。
索引(Index)是帮助MySQL高效获取数据的数据结构,当谈到MySQL性能优化时,一定是绕不开的话题,因为它决定SQL性能的好坏,好的SQL离不开一个好的索引,二者是相辅相成的。 索引能极大的减少存储引擎需要扫描的数据量,提高数据查询的效率,减少IO操作次数,提高性能。 MySQL主要使用B+Tree作为索引算法,InnoDB引擎就是使用这种算法,它的特点有如下几点:
下面通过案例理解上面的技巧:
假设表Y建立索引index(a,b,c),Y表还有很多其他字段未列出; a是字符类型,b、c 是整型; 若测试表Y只有a、b、c三个字段,不能达到测试效。
1/2的含义是:若是多列索引,要遵守最左前缀法则;指的是查询从索引的最左前列开始并且不跳过索引中的列,同时如果能够所有索引列都能匹配是最完美的。
-- 使用到索引列a,其他b、c并未使用到
select *from Y where a='1';
-- 使用到索引a、b,未使用到c
select *from Y where a='1' and b=2;
-- 所有的索引列都使用到,最好的最完美的方式
select *from Y where a='1' and b=2 and c=3;
-- 跳过了索引a,所有的索引都未使用到(所以带头大哥不能死哟)
select *from Y where b=2 and c=3;
select *from Y where b=2;
select *from Y where c=3;
-- 使用到索引a,并未使用到索引c,因为跳过了中间索引b
select *from Y where a='1' and c=3;
3 的含义是:不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),否则会导致索引失效而转向全表扫描;若使用索引列中,使用到范围查找,则范围查找右边使用到的索引列会失效。
-- 通过索引列计算,则索引列a未使用到
select *from Y where right(a,2)='1';
-- b列通过范围查找,则范围右边的列c未使用到
select *from Y where a='1' and b>2 and c=3;
4 的含义是:like模糊查找以通配符开头(’%abc’、’%abc%’)mysql索引失效会变成全表扫描操作;查询中尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少使用select*。
-- abc索引列都使用到了
select *from Y where a like 'xx%' and b=2 and c=3;
-- 同上
select *from Y where a like 'k%xx%' and b=2 and c=3;
-- 左匹配模糊查询,导致索引失效,所有索引都未使用到
select *from Y where a like '%xx' and b=2 and c=3;
-- 同上
select *from Y where a like '%xx%' and b=2 and c=3;
-- 使用覆盖索引,不使用select*,覆盖索引前提是保证查询条件和查询内容列一样
select a,b,c from Y where a='1' and b=2 and c=3;
5 的含义是:MySQL在使用(!=或<>或is null或is not null 或or)的时候无法使用索引会导致全表扫描。
-- a、b、c索引失效
select *from Y where a='1' or b='2' and c='3';
-- 索引a未使用
select *from Y where a is null;
-- 索引a未使用
select *from Y where a != '1';
6 的含义是:字符类型的字段作为条件查询时,不加单引号会导致索引失效,因为它存在隐式类型转换。
-- 存在隐式类型转换
select *from Y where a = 1;
-- 不带引号,索引列a是用不到
select *from Y where a = '1';
原则:小表驱动大表,即小的数据集驱动大的数据集。
假设存在小表B,大表A,则查询语句写法:
-- in(subquery)子查询中适合查询小表,这种方式效率更高
select * from A where id in (select id from B)
-- exists(subquery) 子查询适合大表,主查询数据需要放到子查询中匹配
-- 通过返回true或false判断是否保留主查询结果
select * from B where exists (select * from A)
对于order by,尽量使用Index方式排序,避免使用FileSort方式排序。 group by 实质是先排序后进行分组,优化技巧同order by一样。 MySQL支持Index和FileSort排序,Index比FileSort排序效率高,Index是基于索引实现排序,而FileSort是基于外部文件排序的。若想要实现Index排序,需要遵照索引建的最佳左前缀原则,下面通过案例(伪代码)说明: 假设一个表建立索引:index_abc(a,b,c)
-- order by 使用到索引排序,遵守最佳左前缀排序
order by a
order by a,b
order by a,b,c
order by a DESC,b DESC,c DESC
-- 如果WHERE使用索引的左前缀为常量,则order by 能使用索引
where a = const order by b,c
where a = const and b = const order by c
where a = const and b>const order by b,c
-- 不能使用索引排序
-- 排序不一致
order by a ASC,b DESC,c DESC
-- 丢掉a索引
where g=const order by b,c
-- 丢掉b索引
where a=const order by c
-- d不是索引的一部分
where a=const order by a,d
-- 对于排序来说,多个相等的条件也是范围查询
where a in(…………) order by b,c
CSV: 以逗号隔开的数据存储格式文件,它不支持索引,一般常用于数据交互格式,数据导出、导入。
ARCHIVE: 采用压缩协议进行数据的存储,数据存储以ARZ格式存储。
MERMORY: 所有数据存储在内存中,访问数据极快,数据容易丢失。
MyISAM: MySQL 5.5版本之前的默认存储引擎,有很多系统表也使用MyISAM引擎。
存在主键,则以主键作为聚集索引,否则以一个非空的unique作为聚集索引,否则创建一个隐藏的row-id作为聚集索引; 当通过辅助索引查找数据时,通过索引查找树,查找到叶子节点中存储聚集索引,最后才通过聚集索引查找到对应的数据。
数据查询时日常开发中,操作频次最高的,所以练好这部分内功是必不可少的;所有的查询SQL要想性能最好,必须结合MySQL索引的特点实现。
通信方式
mysql连接信息
可以通过show full processlist/show processlist
命令查询,如:
参数说明:
Sleep:线程正在等待客户端发送数据; Query:连接线程正在执行查询; Locked:线程正在等待表锁的释放; Sorting result:线程正在对结果进行排序; Sending data:向请求端返回数据。
查询缓存主要是缓存SQL语句查询的结果和SQL语句,可以理解为key-value存储,sql作为key,查询结果作为value。 默认情况下MySQL的缓存是没有开启的,为了减少资源浪费,可以通过set global query_cache_type=1命令开启或者配置文件配置(需要重启服务);
查询流程 执行查询SQL,先查找缓存中是否存在结果,若存在则直接返回结果,不存在则执行查询,并缓存查询结果(缓存命中SQL需要完全一样,SQL是区分大小写的)。
查询缓存信息
通过命令show variables like 'query%'命令查看
参数说明:
0:不启用查询缓存 ,默认值 ; 1:启用查询缓存,只要符合查询缓存的要求,客户端的查询语句和记录集都可以缓存起来,供其他客户端使用 ,加上 SQL_NO_CACHE 将不缓存; 2:启用查询缓存,只要查询语句中添加了参数: SQL_CACHE ,且符合查询缓存的要求,客户端的查询语句和记录集,则可以缓存起来,供其他客户端使用;
查询缓存状态
通过命令show status like 'qcache%'
命令查看
参数说明:
缓存失效情况
MySQL查询缓存可用于以读为主的业务,数据生成 之后就 不常改变 的业务比如门户 类 、新闻类、报表 类 、论坛类.
查询优化处理主要由解析器、预处理器、查询优化器。
解析器: 通过lex词法分析,yacc语法分析将sql语句解析成解析树; 预处理器: 根据mysql的语法的规则进一步检查解析树的合法性,如:检查数据的表和列是否存在,解析名字和别名的设置。还会进行权限的验证; 查询优化器: 找出最优的查询计划,然后通过查询引擎查询数据。
使用 explain 可以模拟优化器执行SQL语句,从而知道MySQL是何处理你的SQL语句的,分析你的查询语句或是结构的性能瓶颈。 通过explain,能够很清晰的知道SQL查询读取表的顺序、哪些索引被使用到、表直接的引用关系、每张表有多少条数据被扫描等等。
参数说明:
关于explain详细说明可参考官方:https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain_filtered
根据生成的查询计划,调用存储引擎接口执行查询,直到完成所有的数据查询。
将SQL查询的数据返回给客户端,若需要做缓存,则将结果插入缓存; MySQL返回结果给客户端是一个增量、逐步返回的过程,目的是为了减轻服务端的压力,服务端直接将结果返回,不需要储存,浪费过多的内存资源。
MySQL提供的SQL监控的一种日志,记录在MySQL中SQL执行响应的时间的语句,SQL响应时间超过long_query_time的时间就回被记录到慢查询日志中;当SQL语句执行响应时间超过给定的long_query_time时,可以针对性的优化相关SQL语句。
MySQL默认未开启慢查询日志功能,需要手动开启,因为开启或多或少会带来性能上的一点开销。
常用命令
# 查看是否开启
SHOW VARIABLES LIKE '%slow_query_log%'
# 开启慢查询
set global slow_query_log = 1
# 关闭慢查询
set global slow_query_log = 0
# 查看当前多少秒算慢
SHOW VARIABLES LIKE 'long_query_time%';
# 慢的阙值时间(设置后需要另外开启一个回话生效)或者使用第二个命令查看
set global long_query_time=3;
show global variables like 'long_query_time';
# 查询当前系统中有多少条慢查询记录
show global status like '%slow_queries%'
配置文件配置 慢日志查询开启,除了使用上面的命令方式开启,还可以在配置文件my.ini中配置
mysql 开启慢查询在配置文件my.ini中配置
[mysqld]
# 开启慢查询
slow_query_log=1
# 指定慢查询输出的日志文件名(包含路径)
slow_query_log_file=xxx.log
# 指定慢查询阀值时间,单位s(秒)
long_query_time=3
# 指定慢查询输入的方式
log_output=file
日志分析工具
针对大量日志,须要手动分析相当浪费时间,可以使用mysql 的工具 mysqldumpshow
perl mysqldumpslow.pl --help
Usage: mysqldumpslow [ OPTS... ] [ LOGS... ]
Parse and summarize the MySQL slow query log. Options are
--verbose verbose
--debug debug
--help write this text to standard output
-v verbose
-d debug
-s ORDER what to sort by (al, at, ar, c, l, r, t), 'at' is default
al: average lock time
ar: average rows sent
at: average query time
c: count
l: lock time
r: rows sent
t: query time
-r reverse the sort order (largest last instead of first)
-t NUM just show the top n queries
-a don't abstract all numbers to N and strings to 'S'
-n NUM abstract numbers with at least n digits within names
-g PATTERN grep: only consider stmts that include this string
-h HOSTNAME hostname of db server for *-slow.log filename (can be wildcard),
default is '*', i.e. match all
-i NAME name of server instance (if using mysql.server startup script)
-l don't subtract lock time from total time
常用参数说明:
s:是表示按何种方式排序
c:访问次数
l:锁定时间
r:返回记录
t:查询时间
al:平均锁定时间
ar:平均返回记录数
at:平均查询时间
t:即为返回前面多少条的数据
g:后边搭配一个正则匹配模式,大小写不敏感的
案例:
返回记录集最多的10个SQL。
mysqldumpslow -s r -t 10 slow_log1.log
访问次数最多的10个SQL
mysqldumpslow -s c -t 10 slow_log1.log
按照时间排序的前10条里面含有左连接的查询语句。
mysqldumpslow -s t -t 10 -g “left join” slow_log1.log
另外建议在使用这些命令时结合|和more 使用,否则有可能出现刷屏的情况。
mysqldumpslow -s r -t 20 slow_log1.log | more
详见官网:https://dev.mysql.com/doc/refman/5.7/en/mysqldumpslow.html
show profiles是MySQL提供可以用来分析当前会话中语句执行的资源消耗情况,可以用于SQL的调优测量 默认情况下,参数处于关闭状态,可以通过命令set profiling=on开启,并保存最近15次的运行结果 分析步骤
show profile
命令查看sql执行状态 。-- type为需要查看的类型,n对应Query_ID
SHOW PROFILE [type [, type] ... ]
[FOR QUERY n]
[LIMIT row_count [OFFSET offset]]
type: {
ALL
| BLOCK IO
| CONTEXT SWITCHES
| CPU
| IPC
| MEMORY
| PAGE FAULTS
| SOURCE
| SWAPS
}
参数说明
ALL:显示所有的开销信息
BLOCK IO:显示块IO开销
CONTEXT SWITCHES:上下文切换开销
CPU:显示CPU开销信息
IPC:显示发送和接收开销信息
MEMORY:显示内存开销信息
PAGE FAULTS:显示页面错误开销信息
SOURCE:显示和Source_function,Source_file,Source_line相关的开销信息
SWAPS:显示交换次数开销信息
# =======注意(sql生命周期中出现以下周期,说明sql很糟糕)=====
# 查询结果太大,内存都不够用了往磁盘上搬了
converting HEAP to MyISAM
# 创建临时表(拷贝数据到临时表、用完再删除)
Creating tmp table
# 把内存中临时表复制到磁盘,危险!!!
Copying to tmp table on disk
# 被锁住
locked
详见官网:https://dev.mysql.com/doc/refman/5.7/en/show-profile.html
好了MySQL的基础篇和高级篇就给大伙介绍到这儿了哦!