深入解析mysql查询优化
1。MySQL查询优化器如何工作
MySQL查询优化器有几个目标,但主要目标是使用索引尽可能使用最严格的指标来消除尽可能多的数据行的可能。最终的目标是提交SELECT语句来查找数据行,而不是排除数据行,优化器尝试排除数据线的原因是,更快的是排除数据线,更快的发现符合条件的数据行匹配。如果最严格的测试,可以先做,可以更快地执行查询。
解释的每个输出行都提供关于一个表的信息,每一行包含以下列:
学期
解释
身份证件
在MySQL查询优化器选择的执行计划的查询的序列号。在SELECT子句或工作表中的查询执行的顺序,该ID值越高,优先级越高,和更多的是first.id执行,执行从上到下的顺序。
select_type查询类型
解释
简单的
简单的选择查询,不使用联盟和子查询
原发性
最外面的SELECT查询
联盟
联合中的第二个或后续SELECT查询不依赖于外部查询的结果集。
依赖的联盟
联合中的第二个或后续SELECT查询依赖于外部查询的结果集。
子查询
首先选择查询的子查询,不依赖于外部查询的结果集
相关子查询
首先选择查询的子查询,根据查询结果集的外部
衍生
为了从clause.mysql递归地执行这些子查询子查询的情况下,将临时表中的结果。
可缓存的查询
结果集不可缓存的查询和必须被重新评估为每行外查询。
可缓存的联盟
再次选择查询的工会,属于非缓存查询
学期
解释
表
输出行引用的表
键入重要的项,显示使用的连接类型,根据最佳到最坏类型排序
解释
系统
表只有一行(=系统表)。这是常量连接类型的特殊情况。
const
const用于比较主键与常量值。当查询表只有一行时,使用系统。
eq_ref
const用于比较主键与常量值。当查询表只有一行时,使用系统。
裁判
连接不能基于关键字选择单个行,并且可能会找到多行符合的名称,因为索引与一个引用值进行比较,所以称为REF,这个引用值是一个常量或从表中多表查询的结果值。
ref_or_null
与REF一样,MySQL必须在第一次搜索的结果中找到null条目,然后进行两次查找。
index_merge
结果表明,采用了索引合并优化方法。
unique_subquery
这是用在一些查询的,不是常规的参考:值(选择从哪里primary_key single_table some_expr)
index_subquery
在查询中,这种类似于unique_subquery,但查询是非唯一索引:值(选择从哪里key_column single_table some_expr)。
范围
只在给定的范围内检索行,然后使用电缆选择行。键列显示使用的索引。当使用=、>、>、或或在运算符之间,使用常数比较键列时,可以使用范围。
指数
所有的表扫描都是在索引表中进行的,而不是在扫描表时行。主要的优点是避免排序,但开销仍然很大。
所有
在最坏的情况下,从开始到结束的所有表扫描。
学期
解释
possible_keys
指出mysql可以在表中使用哪些索引来帮助查询。如果它是空的,则没有可用索引。
学期
解释
关键
MySQL其实选择指数,从possible_key.if无效用,指标是没有用的。在一些情况下,MySQL会选择优化索引索引。在这种情况下,使用索引(indexname)可以用于SELECT语句强制索引或忽略指数(indexname)强迫MySQL忽略该指数。
学期
解释
key_len
所用索引的长度。在没有精度损失的情况下,越短越好。
学期
解释
裁判
索引的哪个列显示出来了
学期
解释
排
MySQL认为必须检查以返回请求数据的行数。
学期
解释
排
MySQL认为必须检查以返回请求数据的行数。
额外的2项意味着MySQL根本不能使用索引,效率会受到很大影响,应该尽可能优化。
额外项目
解释
Using filesort
这意味着MySQL将用外部索引对结果进行排序,而不是从表中读取索引顺序中的相关内容。在内存或磁盘上排序是可能的。
使用临时
这表明MySQL在查询结果排序时使用临时表,按排序顺序按组查询和分组查询是常见的。
下面是一个例子来说明下一个解释的用法。
首先是表格:
复制代码代码如下所示:
如果不存在`第`创建表(` ID ` int(10)符号的非空auto_increment,
` author_id ` int(10)符号的非空,
` category_id ` int(10)符号的非空,
视图int(10)未签名不空,
注释int(10)无符号不空,
`标题` varbinary(255)不为空,
内容文本不为空,
主键(id)
);
更多的数据:
复制代码代码如下所示:
插入到文章中
(` author_id `,` category_id `,`观点`,`评论`,`标题`,`内容`)值
(1, 1, 1,1,1,1'),
(2, 2, 2,2,2,2'),
(1, 1, 3,3,3,3');
需求:
当查询category_id 1和评论是大于1的,意见是最article_id。
先检查一下。
复制代码代码如下所示:
解释
选择author_id
从'文章'
在category_id = 1和评论> 1
ORDER BY views DESC
限制1 g
查看一些输出结果:
复制代码代码如下所示:
*************************** 1。行***************************
编号:1
select_type:简单
表:第
类型:所有
possible_keys:空
关键词:零
key_len:空
参考:空
行数:3
额外的:使用;使用filesort
1行集(0秒)
显然,类型,最坏的情况下,额外的,也有使用filesort,和最坏的打算。优化是必要的。
好的,那么最简单的解决方案是indexed.ok,让我们试一试。查询后,三场category_id,评论,和看法是用来在哪里。所以联合指数是最简单的。
复制代码代码如下所示:
修改表`第`添加指数X(` category_id `,`评论`,`观点`);
结果是更好,但仍然是坏的:
复制代码代码如下所示:
*************************** 1。行***************************
编号:1
select_type:简单
表:第
类型:范围
possible_keys:X
关键词:X
key_len:8
参考:空
行数:1
额外的:使用;使用filesort
1行集(0秒)
型变的范围,这是可以容忍的。但是使用filesort额外使用的仍然是不可接受的。但我们已经建立了索引。为什么不起作用这是因为,根据B树索引的工作原理,category_id排序第一。如果我们遇到同样的category_id,然后评论进行排序。如果遇到相同的注释,我们将对视图进行排序。当注释字段位于联合索引的中间位置时,注释> 1的条件是一个范围值(称为范围)。MySQL不能使用索引并稍后检索视图部分,也就是说,范围类型查询字段后面的索引无效。
然后我们需要删除注释并删除旧索引:
复制代码代码如下所示:
在文章上删除索引x;
然后创建一个新索引:
复制代码代码如下所示:
修改表`第`添加指数Y(` category_id `,`观点`);
然后再次运行查询:
复制代码代码如下所示:
*************************** 1。行***************************
编号:1
select_type:简单
表:第
类型:裁判
possible_keys:Y
关键词:Y
key_len:4
参考:const
行数:1
附加:使用在哪里
1行集(0秒)
你可以看到,类型改为裁判,和额外的使用filesort正在消失,其结果是非常理想的。
查看一个多表查询的示例。
首先,定义了3个表,类和空间。
复制代码代码如下所示:
如果不存在,创建表(类)
` ID ` int(10)符号的非空auto_increment,
卡片int(10)无符号不空,
主键(id)
);
如果不存在,创建表(书)
` bookid ` int(10)符号的非空auto_increment,
卡片int(10)无符号不空,
主键(` bookid `)
);
如果不存在,创建表(电话)
` PhoneID ` int(10)符号的非空auto_increment,
卡片int(10)无符号不空,
主键(` PhoneID `)
InnoDB引擎=);
然后,大量的数据被插入respectively.php脚本插入数据:
复制代码代码如下所示:
< PHP
$link = mysql_connect(localhost
mysql_select_db(测试
($ i = 0;$ i < 10000;$ + +)
{
J =兰特(中);
插入到类(卡)值中({ $ });
mysql_query($ SQL);
}
($ i = 0;$ i < 10000;$ + +)
{
J =兰特(中);
插入图书(卡片)值({ $ });
mysql_query($ SQL);
}
($ i = 0;$ i < 10000;$ + +)
{
J =兰特(中);
$插入到电话(卡)值({ $ });
mysql_query($ SQL);
}
mysql_query(提交);
>
然后看看左边的连接查询:
复制代码代码如下所示:
解释选择*从类左连接class.card =书。卡 G
分析结果如下:
复制代码代码如下所示:
*************************** 1。行***************************
编号:1
select_type:简单
表:类
类型:所有
possible_keys:空
关键词:零
key_len:空
参考:空
行数:20000
额外的:
*************************** 2。行***************************
编号:1
select_type:简单
表:书
类型:所有
possible_keys:空
关键词:零
key_len:空
参考:空
行数:20000
额外的:
2行(0秒)
显然,第二个问题都需要优化。
设置索引尝试:
复制代码代码如下所示:
修改表添加索引y(卡片);
复制代码代码如下所示:
*************************** 1。行***************************
编号:1
select_type:简单
表:类
类型:所有
possible_keys:空
关键词:零
key_len:空
参考:空
行数:20000
额外的:
*************************** 2。行***************************
编号:1
select_type:简单
表:书
类型:裁判
possible_keys:Y
关键词:Y
key_len:4
参考:test.class.card
行数:1000
额外的:
2行(0秒)
你可以看到,类型更改为参考第二行,排成1741×18,和优化更为明显。这是由左连接的特点决定的。左加入条件来确定如何从右表搜索线,必须有所有的左边,所以正确的是我们的重点,必须被索引。
删除旧索引:
复制代码代码如下所示:
删除索引y在书上;
创建一个新索引。
复制代码代码如下所示:
更改表类添加索引X(卡片);
结果
复制代码代码如下所示:
*************************** 1。行***************************
编号:1
select_type:简单
表:类
类型:所有
possible_keys:空
关键词:零
key_len:空
参考:空
行数:20000
额外的:
*************************** 2。行***************************
编号:1
select_type:简单
表:书
类型:所有
possible_keys:空
关键词:零
key_len:空
参考:空
行数:20000
额外的:
2行(0秒)
基本上没有变化。
然后看一个正确的连接查询:
复制代码代码如下所示:
解释选择*从类右连接class.card = book.card书;
分析结果如下:
复制代码代码如下所示:
*************************** 1。行***************************
编号:1
select_type:简单
表:书
类型:所有
possible_keys:空
关键词:零
key_len:空
参考:空
行数:20000
额外的:
*************************** 2。行***************************
编号:1
select_type:简单
表:类
类型:裁判
possible_keys:X
关键词:X
key_len:4
参考:test.book.card
行数:1000
额外的:
2行(0秒)
优化更为明显,这是因为正确的连接条件用于决定如何从左表中搜索行,并且必须在右边有所有,所以左边是我们的关键点,必须索引。
删除旧索引:
复制代码代码如下所示:
类上的索引x;
创建一个新索引。
复制代码代码如下所示:
修改表添加索引y(卡片);
结果
复制代码代码如下所示:
*************************** 1。行***************************
编号:1
select_type:简单
表:类
类型:所有
possible_keys:空
关键词:零
key_len:空
参考:空
行数:20000
额外的:
*************************** 2。行***************************
编号:1
select_type:简单
表:书
类型:所有
possible_keys:空
关键词:零
key_len:空
参考:空
行数:20000
额外的:
2行(0秒)
基本上没有变化。
最后,看看内部连接的情况。
复制代码代码如下所示:
解释选择*从课内连接class.card = book.card书;
结果:
复制代码代码如下所示:
*************************** 1。行***************************
编号:1
select_type:简单
表:书
类型:所有
possible_keys:空
关键词:零
key_len:空
参考:空
行数:20000
额外的:
*************************** 2。行***************************
编号:1
select_type:简单
表:类
类型:裁判
possible_keys:X
关键词:X
key_len:4
参考:test.book.card
行数:1000
额外的:
2行(0秒)
删除旧索引:
复制代码代码如下所示:
删除索引y在书上;
结果
复制代码代码如下所示:
*************************** 1。行***************************
编号:1
select_type:简单
表:类
类型:所有
possible_keys:空
关键词:零
key_len:空
参考:空
行数:20000
额外的:
*************************** 2。行***************************
编号:1
select_type:简单
表:书
类型:所有
possible_keys:空
关键词:零
key_len:空
参考:空
行数:20000
额外的:
2行(0秒)
创建一个新索引。
复制代码代码如下所示:
更改表类添加索引X(卡片);
结果
复制代码代码如下所示:
*************************** 1。行***************************
编号:1
select_type:简单
表:类
类型:所有
possible_keys:空
关键词:零
key_len:空
参考:空
行数:20000
额外的:
*************************** 2。行***************************
编号:1
select_type:简单
表:书
类型:所有
possible_keys:空
关键词:零
key_len:空
参考:空
行数:20000
额外的:
2行(0秒)
总之,内部连接类似于左连接,所有这些都需要对右表进行优化,而右连接需要优化左表。
让我们看看三个查询示例
添加新索引:
复制代码代码如下所示:
更改表'电话'添加索引Z('卡');
修改表添加索引y(卡片);
复制代码代码如下所示:
解释选择*从类左加入书类。卡= book.card左连接手机。
复制代码代码如下所示:
*************************** 1。行***************************
编号:1
select_type:简单
表:类
类型:所有
possible_keys:空
关键词:零
key_len:空
参考:空
行数:20000
额外的:
*************************** 2。行***************************
编号:1
select_type:简单
表:书
类型:裁判
possible_keys:Y
关键词:Y
key_len:4
参考:test.class.card
行数:1000
额外的:
*************************** 3。行***************************
编号:1
select_type:简单
表:手机
类型:裁判
possible_keys:Z
关键词:Z
key_len:4
参考:test.book.card
行数:260
附加:使用索引
3行(0秒)
接下来的2行类型都是REF,总行优化好,效果好。
MySql的解释语法可以帮助我们重写查询,优化表的结构和索引的设置,从而最大限度地提高查询的效率。当然,当数据量很大时,索引建立和维护的成本也很高。它通常需要更长的时间和更大的空间。如果我们在不同的列组合上建立索引,那么空间的成本会更大,因此,索引最好在需要频繁查询的字段中设置。