Mysql 高级优化之 逻辑处理

Preview:

Citation preview

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

谢谢