本篇文章主要是对MySQL学习时的一些总结,作为学习笔记记录
对于某些sql语句来说,会导致执行时间长,等待时间长的后果,从而造成整个sql语句的性能下降。导致sql性能下降的原因主要有:
SQL中对大量数据进行比较、关联、排序、分组。其中最大的压力在于比较
由于服务器硬件导致的性能瓶颈,此时可以通过top、free、iostat和vmstat来查看系统的性能状态
使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理SQL语句的,分析查询语句或是表结构的性能瓶颈,详情见官网。
通过Explain查看sql语句执行计划,可以查看到:
EXPLAIN SQL语句;
Explain执行后包含的信息都有:
CREATE TABLE t1 (
id INT (10) AUTO_INCREMENT,
content VARCHAR (100) NULL,
PRIMARY KEY (id)
) ;
CREATE TABLE t2 (
id INT (10) AUTO_INCREMENT,
content VARCHAR (100) NULL,
PRIMARY KEY (id)
) ;
CREATE TABLE t3 (
id INT (10) AUTO_INCREMENT,
content VARCHAR (100) NULL,
PRIMARY KEY (id)
) ;
CREATE TABLE t4 (
id INT (10) AUTO_INCREMENT,
content VARCHAR (100) NULL,
PRIMARY KEY (id)
) ;
INSERT INTO t1 (content)
VALUES
(CONCAT('t1_', FLOOR(1+ RAND() * 1000))) ;
INSERT INTO t2 (content)
VALUES
(CONCAT('t2_', FLOOR(1+ RAND() * 1000))) ;
INSERT INTO t3 (content)
VALUES
(CONCAT('t3_', FLOOR(1+ RAND() * 1000))) ;
INSERT INTO t4 (content)
VALUES
(CONCAT('t4_', FLOOR(1+ RAND() * 1000))) ;
select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序。总共存在三种情况:
此例中 先执行where后的第一条语句t1.id = t2.id通过t1.id关联t2.id,而 t2.id的结果建立在t2.id=t3.id的基础之上。
id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行。
查询的类型,主要是用于区别普通查询、联合查询、子查询等的复杂查询。主要有:
对于各类型的解释为:
SIMPLE:
简单的 select 查询,查询中不包含子查询或者UNION
PRIMARY
查询中若包含任何复杂的子部分,最外层查询则被标记为Primary
DERIVED
在FROM列表中包含的子查询被标记为DERIVED(衍生),MySQL会递归执行这些子查询, 把结果放在临时表里
SUBQUERY
在SELECT或WHERE列表中包含了子查询
DEPENDENT SUBQUERY
在SELECT或WHERE列表中包含了子查询,子查询基于外层
dependent subquery 与 subquery 的区别
UNCACHEABLE SUBQUREY
无法被缓存的子查询
上图种的 @@ 表示查的环境参数 ,没办法缓存。
UNION
UNION RESULT表示两个语句执行完后的结果
UNION RESULT
从UNION表获取结果的SELECT
显示这一行的数据是关于哪张表的
type显示的是访问类型,是较为重要的一个指标,主要结果为:
访问类型排序
结果值从最好到最坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range(尽量保证) > index > ALL
一般可以简化为:
system > const > eq_ref > ref > range > index > ALL
一般说来,要保证查询至少达到range级别,最好能够达到ref。
system
表只有一行记录(等于系统表),这是const类型的特列,平时不会出现,这个也可以忽略不计
const
eq_ref
ref
range
index
all
Full Table Scan,将遍历全表以找到匹配的行
index_merge
在查询过程中需要多个索引组合使用,通常出现在有 or 的关键字的sql中
ref_or_null
index_subquery
利用索引来关联子查询,不再全表扫描
unique_subquery
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度
怎么计算?
上图中字符集为utf8格式,因此需要*3,动态类型包括varchar,detail text()截取字符串
同时key_len字段能够帮你检查是否充分的利用上了索引
同样的使用了索引但是索引的涉及的字段却不同:
由上图可知,充分利用了索引的查询效率会更高。
包含不适合在其他列中显示但十分重要的额外信息
Using filesort
出现filesort的情况:
优化后,不再出现filesort的情况(给 ename 加上了索引):
Using temporary
优化前存在using temporary和using filesort:
create index idx_deptno_ename on emp(deptno,ename);后解决优化前存在的using temporary和using filesort问题,性能发生明显变化:
Using index
覆盖索引(Covering Index)
- 索引是高效找到行的一个方法,而一般数据库也能使用索引找到一个列的数据,因此它不必读取整个行
- 毕竟索引叶子节点存储了它们索引的数据;当能通过读取索引就可以得到想要的数据,那就不需要读取行了
- ①一个索引 ②包含了(或覆盖了)[select子句]与查询条件[Where子句]中 ③所有需要的字段就叫做覆盖索引
如果有以下的sql语句:
select id , name from t_xxx where age=18;
若表中存在组合索引idx_id_name_age,此时该索引包含了(覆盖了)id、name、age三个字段,查询时直接读取建立了索引的列,而不需要查找所在行的其它数据,所以很高效。
注意:
- 在数据量较大,固定字段查询情况多时可以使用这种方法
- 如果要使用覆盖索引,一定要注意select列表中只取出需要的列,不可select *,因为如果将所有字段一起做索引会导致索引文件过大,查询性能下降
Using where
表明使用了where过滤
using join buffer
impossible where
where子句的值总是false,不能用来获取任何元组
select tables optimized away
在没有GROUP BY子句的情况下,基于索引优化MIN/MAX操作或者对于MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化
在innodb中:
在Myisam中: