mysql 高级优化之 逻辑处理
TRANSCRIPT
www.2345.com
MySQL 高级优化之——
查询逻辑及where条件提取
上海二三四五网络科技股份有限公司
互联网研发中心
王德玖
2013-09-27
www.2345.com
议程
• Mysql 查询逻辑处理步骤
• 查询语句中where 条件如果提取
• 总结
• 问答
www.2345.com
SELECT查询预览
SELECT DISTINCT <select_list>
FROM <left_table>
<join_type> JOIN <right_table>
ON <join_condition>
WHERE <where_condition>
GROUP BY <group_by_list>
WITH{CUBE|ROLLUP}
HAVING <having_condition>
ORDER BY <order_by_list>
LIMIT <limit_number>
www.2345.com
SELECT 逻辑处理概览:
(8) SELECT (9) DISTINCT <select_list>
(1) FROM <left_table>
(3 ) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) WITH{CUBE|ROLLUP}
(7) HAVING <having_condition>
(10) ORDER BY <order_by_list>
(11) LIMIT <limit_number>
11个步骤,最先执行
的是FROM操作,最后执行的是LIMIT操作。每个操作都会产
生一张虚拟表,以下记为“VTn”该虚拟表
作为一个处理的输入
www.2345.com
第一组FROM、ON:
(8) SELECT (9) DISTINCT <select_list>
(1) FROM <left_table>
(3 ) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) WITH{CUBE|ROLLUP}
(7) HAVING <having_condition>
(10) ORDER BY < order_by_list >
(11) LIMIT <limit_number>
对FROM子句中的左表<left_table>和右表
<right_table>执行笛卡儿
积(Cartesian product),产生虚拟表VT1
对虚拟表VT1应用ON筛选,
只有符合<join_condition>的行才被插入虚拟表VT2中
www.2345.com
承前启后的join:
(8) SELECT (9) DISTINCT <select_list>
(1) FROM <left_table>
(3 ) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) WITH{CUBE|ROLLUP}
(7) HAVING <having_condition>
(10) ORDER BY < order_by_list >
(11) LIMIT <limit_number>
如果指定了OUTER JOIN(如LEFT OUTER JOIN、
RIGHT OUTER JOIN),那么保留表中未匹配的行作为
外部行添加到虚拟表VT2中,产生虚拟表VT3。如果
FROM子句包含两个以上表,则对上一个连接生成的结果
表VT3和下一个表重复执行
步骤1)~步骤3),直到处理完所有的表为止。
www.2345.com
Where你需要什么:
(8) SELECT (9) DISTINCT <select_list>
(1) FROM <left_table>
(3 ) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) WITH{CUBE|ROLLUP}
(7) HAVING <having_condition>
(10) ORDER BY <having_condition>
(11) LIMIT <limit_number>
对虚拟表VT3应用
WHERE过滤条件,只有
符合<where_condition>的记录才被插入虚拟表
VT4中
www.2345.com
GROUP BY:
(8) SELECT (9) DISTINCT <select_list>
(1) FROM <left_table>
(3 ) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) WITH{CUBE|ROLLUP}
(7) HAVING <having_condition>
(10) ORDER BY < order_by_list >
(11) LIMIT <limit_number>
根据GROUP BY子句中的列,对VT4中的记录
进行分组操作,产生
VT5
如果有对表VT5进行CUBE或
ROLLUP操作,产生表VT6
www.2345.com
组内过滤HAVING:
(8) SELECT (9) DISTINCT <select_list>
(1) FROM <left_table>
(3 ) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) WITH{CUBE|ROLLUP}
(7) HAVING <having_condition>
(10) ORDER BY < order_by_list >
(11) LIMIT <limit_number>
对虚拟表VT6应
用HAVING过滤器,只
有符合<having_condition>的记录才被插入虚拟
表VT7中
www.2345.com
选择去重:
(8) SELECT (9) DISTINCT <select_list>
(1) FROM <left_table>
(3 ) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) WITH{CUBE|ROLLUP}
(7) HAVING <having_condition>
(10) ORDER BY <having_condition>
(11) LIMIT <limit_number>
把重复的行从VT8中删除,插
入VT9
执行SELECT操作,选择指定的列,插
入到虚拟表VT8中
www.2345.com
排序,返回结果:
(8) SELECT (9) DISTINCT <select_list>
(1) FROM <left_table>
(3 ) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group _by_list>
(6) WITH{CUBE|ROLLUP}
(7) HAVING <having_condition>
(10) ORDER BY <having_condition>
(11) LIMIT <limit_number>
将虚拟表VT9中的记录
按照<order_by_list>进
行排序操作,产生虚拟
表VT10
取出指定行的记录,
产生虚拟表VT11,并返回给查询用户
www.2345.com
查询总结…
(8) SELECT (9) DISTINCT <select_list>
(1) FROM <left_table>
(3 ) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) WITH{CUBE|ROLLUP}
(7) HAVING <having_condition>
(10) ORDER BY < order_by_list >
(11) LIMIT <limit_number>
Join表生成笛卡尔积vt1
On条件过滤vt1插入到vt2
join未匹配的外部行插入得vt3
Where过滤vt3得vt4
分组vt4得出vt5
www.2345.com
…查询总结
(8) SELECT (9) DISTINCT <select_list>
(1) FROM <left_table>
(3 ) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) WITH{CUBE|ROLLUP}
(7) HAVING <having_condition>
(10) ORDER BY < order_by_list >
(11) LIMIT <limit_number>
Vt7排序后插入vt8
从vt8选择所需列得vt9有distinct删除重复行插入vt10
取出vt10指定行插入vt11并返回给用户
Having条件对vt6过滤得vt7
rollup对vt5汇总得vt6(CUBE mysql 还未实现)
www.2345.com
Where中的查询条件提取…
表索引
数据
聚簇索引表 堆表
数据库数据的组成
表结构
www.2345.com
Where中的查询条件提取…
堆表:所有的记录无序存储;
聚簇索引表:所有的记录按照记录主键进
行排序存储
表结构 表索引
Myisam .MYI innodb
in tablespace
.frm
数据元素
www.2345.com
Where中的查询条件提取…
root@ test >show create table test\GTable: testCreate Table: CREATE TABLE `test` (`a` int(11) NOT NULL,`b` int(11) DEFAULT NULL,`c` int(11) DEFAULT NULL,`d` int(11) DEFAULT NULL,`e` varchar(10) DEFAULT NULL,PRIMARY KEY (`a`),KEY `idx_b_c_d` (`b`,`c`,`d`)
) ENGINE=MyISAM DEFAULT CHARSET=gbk
实例一创建表
这里是myisam表,即堆表
www.2345.com
Where中的查询条件提取…
实例一插入数据
root@localhost: test >insert into test select 4,3,1,1,'d';root@localhost: test >insert into test select 1,1,1,1,'a'; root@localhost: test >insert into test select 9,9,9,9,'t'; root@localhost: test >insert into test select 2,2,2,2,'b'; root@localhost: test >insert into test select 5,2,3,5,'e'; root@localhost: test >insert into test select 3,3,2,2,'v'; root@localhost: test >insert into test select 7,4,5,5,'g'; root@localhost: test >insert into test select 6,6,4,4,'f';
www.2345.com
Where中的查询条件提取…
索引组织,存储结构 311
999
4311d
1111a
9999t
2222b
5235e
3322v
7455g
6644f
堆表
索引:idx_b_c_d
图一
www.2345.com
Where中的查询条件提取…
SQL的where条件提取
select * from test where b >= 2 and b < 9 and c > 1 and d != 4 and e != 'a';
结合图一索引思考此查询语句:where条件使用到了[b,c,d,e]四个字段,而test表的idx_b_c_d索引,恰好使用
了[b,c,d]这三个字段,
那么走idx_b_c_d索引进行条件过滤成为可能
www.2345.com
Where中的查询条件提取…
索引范围检查
select * from test where b >= 2 and b < 9 and c > 1 and d != 4 and e != 'a';
起始范围:记录[2,2,2]是第一个需要检查的索引项。索引起始查
找范围由b >= 2,c > 1决定。
终止范围:记录[9,9,9]是第一个不需要检查的记录,而之前的记
录均需要判断。索引的终止查找
范围由b < 9决定;
www.2345.com
Where中的查询条件提取…
索引范围检查
select * from test where b >= 2 and b < 9 and c > 1 and d != 4 and e != 'a';
固定了索引的查询范围
[(2,2,2),(9,9,9))之后,此索引范围中
并不是每条记录都是满足where查询
条件,例如:(3,1,1)不满足c > 1,(6,4,4)不满足d != 4的约束。而c,d列,均可在索引idx_b_c_d中过滤掉不
满足条件的索引记录。
因此,SQL中还可以使用c > 1 and d != 4条件进行索引记录的过滤
www.2345.com
Where中的查询条件提取…
索引范围外检查
select * from test where b >= 2 and b < 9 and c > 1 and d != 4 and e != 'a';
可见,e != ‘a’这个查询条件,无法
在索引idx_a_b_c上进行过滤,因
为索引不包含e列,e列只在堆表上存在,
为了过滤此查询条件,必须将已
经满足索引查询条件的记录回表,
取出表中的e列,然后使用e列的查询条件e != ‘a’进行最终的过滤
4311d
1111a
9999t
2222b
5235e
3322v
7455g
6644f
堆表
www.2345.com
Where中的查询条件提取…
where
Table FilterIndex FilterIndex Key
First Key Last Key
SQL的where条件,可归纳为3大类
www.2345.com
Where中的查询条件提取…
释义过滤表 index key
Index Key
First Key
Last Key
查询确定
SQL查询
在索引中的连续范
围(起始范围+结束
范围)的条件
确定索引查
询的终止范围
确定索引查
询的起始范
围
www.2345.com
Where中的查询条件提取…
Table Filter
Index Filter
索引过滤器及表过滤器
过滤索引查询范围中不
满足查询条件的记录
最后一道where条件的防线,
用于过滤通过前面索引考验的记录,此时的记录已
经满足了Index First Key与Index Last Key构成的范围,
并且满足Index Filter的条件
where
Index Key
www.2345.com
Where中的查询条件提取…
Where提取的逻辑处理过程
First Key
Last Key
确定起终点
Index Filter
去除不符合规则记
录
Table Filter
过滤
返回
www.2345.com
Where中的查询条件提取…
Mysql 5.6 特性:index condition pushdown
MySQL 5.6之前,不区分Index Filter与Table Filter,统统将Index First Key与Index Last Key范围内的索引记录回表读取完整记录,
然后返回给MySQL Server层进行过滤。而在MySQL 5.6之后,Index Filter与Table Filter分离,Index Filter下降到InnoDB的索引层面进行过滤,
减少了回表与返回MySQL Server层的记录交互开销,提高了SQL的执行
效率
www.2345.com
结束
Q&A
www.2345.com
谢谢