MySQL 联表查询和子查询

两个集合X和Y的笛卡儿积(Cartesian product),又称直积,表示为X × Y,是其第一个对象是X的成员而第二个对象是Y的一个成员的所有可能的有序对。

假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1), (b,2)}。


MYSQL执行流程的简单探讨.

周末纠结了一个关于mysql执行流程的问题,现在有点感悟,写下这篇blog,以做记录!
现在网络上有很多文章,都极力推荐在mysql的多表查询中使用联表式,而反对子查询式.但大多文章都是只说其然,而不说其所以然.

说到mysql的执行,就不得不说它的执行流程.而它的执行流程又分为标准执行流程和优化后的执行流程.

标准流程
标准流程是SQL执行的标准流程,几乎所有的SQL数据库都是以这个流程作为基础的.那么在联表的时候,他的流程是怎么样的呢?
这里会带入两个专业的名词,笛卡尔积,虚拟表(Virtual Table 简称VT);
笛卡尔积这个说明的篇幅太长,大家可以先google一下,这里就不说明了,而且一般有学过集合的同学,都知道这么一个东西
VT就是虚拟的表,在mysql处理某个问题的时候,它需要一个容器存放内容,那么这个容器就是VT.

以下是标准流程的举例说明
SELECT * FROM T1 INNER JOIN T2 ON T1.id = T2.t1_id WHERE T1.name = ‘name’ LIMIT 5;

这是一个很常见的SQL语句.那它在标准流程中是怎么执行的呢?
1.T1和T2进行笛卡尔积的计算,形成以个新的集合,放在一个VT内.我们称这个VT为VT1;
2.对VT1进行ON条件的处理,找出VT1中符合T1.id = T2.t1_id条件的记录,形成VT2;
3.对VT2进行WHERE字句处理,找出VT2中符合T1.name = ‘name’条件的记录,形成VT3;
4.对VT3进行LIMIT字句处理,取出前5条数据,形成VT4;
5.返回VT4;

这就是一个SQL的标准执行流程,由上面的流程可以看出,每两表相联的时候,都会先整理出一个笛卡尔集.这是非常消耗资源的.

这里我们再看一个子查询的处理过程.
SELECT * FROM (SELECT * FROM T1 WHERE T1.name = ‘name’) as TMP INNER JOIN T2 ON TMP.id = T2.t1_id LIMIT 5;

如果按照标准的执行流程.这里的处理流程是
1.对T1进行WHERE字句处理,得到一个临时表TMP;
2.TMP和T2进行笛卡尔积的计算,形成以个新的集合,形成VT1;
3.对VT1进行ON条件的处理,找出VT1中符合T1.id = T2.t1_id条件的记录,形成VT2;
4.对VT2进行WHERE字句处理,找出VT2中符合T1.name = ‘name’条件的记录,形成VT3;
5.对VT3进行LIMIT字句处理,取出前5条数据,形成VT4;
6.返回VT4;

对比之下,子查询比INNER JOIN查询多了一步的操作,就是先执行WHERE字句,过滤一遍T1,形成一个临时表.这样,使用TMP表和T2进行笛卡尔积计算的时候,因为TMP的数据比T1减少了很多,所以大大地提高了两表连接的效率.虽然说因为子查询而形成一个临时表,
增加了开销,但是却能很大程度地减少笛卡尔积的体积,这个牺牲是可接受的.

如果是这样的执行流程,子查询肯定会比INNER JOIN快.那为什么那么多人推荐INNER JOIN呢?终究其原因就是,MYSQL优化器.
在MYSQL的语句执行之前,都会经过优化器,优化器对SQL进行一系列的处理,编程它自己认为效率最高的方式(但也有失误的时候),然后再执行;

优化流程
以下是同一语句,经过MYSQL优化器处理之后的简述.MYSQL优化器做的事很多,这里只是简述.
SELECT * FROM T1 INNER JOIN T2 ON T1.id = T2.t1_id WHERE T1.name = ‘name’ LIMIT 5;

1.发现T1是主表,而且WHERE字句中使用的是T1中的name字段作为条件,所以优先排除T1.name != ‘name’的记录.形成VT1
2.TMP和T2进行笛卡尔积的计算,形成以个新的集合,形成VT2;
3.对VT2进行ON条件的处理,找出VT1中符合T1.id = T2.t1_id条件的记录,形成VT3;
4.对VT3进行WHERE字句处理,找出VT2中符合T1.name = ‘name’条件的记录,形成VT4;
5.对VT4进行LIMIT字句处理,取出前5条数据,形成VT5;
6.返回VT5;

优化器自行优先执行了WEHRE字句的内容,不用通过子查询来排除记录,这样既可以减少笛卡尔积的体积,同时也不会因为子查询而产生了一个临时表.
故得出,如果可以尽量使用联表查询的结论

题外拓展
很多时候,你自己认为的主表,并不是真正的主表.例如
SELECT * FROM T1 INNER JOIN T2 ON T1.id = T2.t1_id WHERE T2.name = ‘name’ LIMIT 5;

这条SQL中,用T2表中的name作为条件来查询,当优化器察觉到这个问题的时候,它就会选择T2作为主表,然后处理WHERE子句之后,再对T1进行联接
虽然出来的结果是一样的,但是他们的处理过程却不一定是你所想象的
当然,这个还跟WEHRE子句中所用到到的索引有关系,总之优化器会选择它认为最优的办法来执行.但是,优化器认为是最优的,事实上并不一定是,所以我们要知道它的执行流程和规律,让它在优化的时候,符合我们所想得.L


1、
mysql> SELECT t2.`RoomID`,t3.FloorID,t3.BuildingID FROM `bii_RoomUser` AS t1
    -> LEFT JOIN `bii_Room` AS t2 ON(t2.RoomID = t1.RoomID)
    -> LEFT JOIN `bii_Floor` AS t3 ON(t3.FloorID = t2.FloorID)
    -> WHERE t1.UserID IN(166);
+----------+---------+------------+
| RoomID   | FloorID | BuildingID |
+----------+---------+------------+
| 10000026 | 1000012 |     100005 |
| 10000027 | 1000012 |     100005 |
| 10000028 | 1000012 |     100005 |
+----------+---------+------------+
3 rows in set (0.00 sec)

2、
mysql> select * from bii_RoomUser;
+------------+--------+----------+
| RoomUserID | UserID | RoomID   |
+------------+--------+----------+
|          1 |    111 | 10000015 |
|          2 |    112 | 10000000 |
|          3 |    114 | 10000000 |
|          4 |    115 | 10000000 |
|          5 |    136 | 10000000 |
|          6 |    136 | 10000001 |
|          7 |    136 | 10000002 |
|          8 |    136 | 10000003 |
|          9 |    136 | 10000008 |
|         10 |    136 | 10000009 |
|         11 |    136 | 10000015 |
|         12 |    136 | 10000016 |
|         13 |    137 | 10000000 |
|         14 |    137 | 10000001 |
|         15 |    137 | 10000002 |
|         16 |    137 | 10000003 |
|         17 |    137 | 10000015 |
|         18 |    137 | 10000016 |
|         19 |    137 | 10000008 |
|         20 |    137 | 10000009 |
|         21 |    137 | 10000004 |
|         22 |    137 | 10000005 |
|         23 |    137 | 10000024 |
|         24 |    137 | 10000025 |
|         25 |    138 | 10000004 |
|         26 |    138 | 10000005 |
|         27 |    138 | 10000024 |
|         28 |    138 | 10000000 |
|         29 |    138 | 10000015 |
|         30 |    137 | 10000005 |
|         31 |    155 | 10000000 |
|         32 |    155 | 10000001 |
|         33 |    155 | 10000002 |
|         34 |    155 | 10000003 |
|         35 |    155 | 10000008 |
|         36 |    155 | 10000009 |
|         37 |    155 | 10000015 |
|         38 |    155 | 10000016 |
|         39 |    156 | 10000000 |
|         40 |    156 | 10000001 |
|         41 |    156 | 10000002 |
|         42 |    155 | 10000003 |
|         43 |    156 | 10000008 |
|         44 |    156 | 10000009 |
|         45 |    156 | 10000015 |
|         46 |    156 | 10000016 |
|         47 |    157 | 10000000 |
|         48 |    157 | 10000001 |
|         49 |    157 | 10000002 |
|         50 |    157 | 10000003 |
|         51 |    157 | 10000008 |
|         52 |    157 | 10000009 |
|         53 |    157 | 10000015 |
|         54 |    157 | 10000016 |
|         55 |    158 | 10000000 |
|         56 |    158 | 10000001 |
|         57 |    158 | 10000002 |
|         58 |    158 | 10000003 |
|         59 |    158 | 10000008 |
|         60 |    158 | 10000009 |
|         61 |    158 | 10000015 |
|         62 |    158 | 10000016 |
|         63 |    166 | 10000026 |
|         64 |    166 | 10000027 |
|         65 |    166 | 10000028 |
|         66 |    170 | 10000000 |
|         67 |    170 | 10000001 |
|         68 |    170 | 10000002 |
|         69 |    170 | 10000003 |
|         70 |    170 | 10000008 |
|         71 |    170 | 10000009 |
|         72 |    170 | 10000015 |
|         73 |    170 | 10000016 |
+------------+--------+----------+
73 rows in set (0.00 sec)

3、
mysql> select * from bii_Room;
+----------+---------------+-------------------------------------------------------------------------+---------+----------+--------------------------------------------+---------+
| RoomID   | RoomName      | Location                                                                | FloorID | IsPublic | Pic                                        | Point   |
+----------+---------------+-------------------------------------------------------------------------+---------+----------+--------------------------------------------+---------+
| 10000000 | 大会议室      | 90,19,120,13,144,9,172,5,204,6,219,8,219,104,90,104                     | 1000000 |        0 | userfile/image/room/yicenghuiyishi.png     | 144,52  |
| 10000001 | 男卫生间      | 260,13,285,23,306,33,306,103,260,103                                    | 1000000 |        0 | userfile/image/room/yicengnanwei.png       | 274,53  |
| 10000002 | 女卫生间      | 304,33,330,49,354,75,366,103,304,103                                    | 1000000 |        0 | userfile/image/room/yicengnvwei.png        | 321,63  |
| 10000003 | 公共区域      | 4,103,366,103,366,149,4,149                                             | 1000000 |        1 | userfile/image/room/yicengdating.png       | 193,115 |
| 10000004 | 接待室        | 87,147,186,147,186,239,150,235,120,231,87,220                           | 1000000 |        0 | userfile/image/room/yicengjiedaishi.png    | 129,171 |
| 10000005 | 大会议室      | 216,149,362,149,354,169,336,187,312,207,282,221,252,229,235,235,216,237 | 1000001 |        0 | userfile/image/room/ercenghuiyishi.png     | 251,174 |
| 10000006 | 男卫生间      | 259,15,281,24,202,32,202,104,259,104                                    | 1000001 |        0 | userfile/image/room/ercengnanwei.png       | 273,50  |
| 10000007 | 女卫生间      | 302,32,327,48,344,66,356,84,365,102,302,102                             | 1000001 |        0 | userfile/image/room/ercengnvwei.png        | 317,68  |
| 10000008 | 办公区        | 72,32,95,20,131,9,161,5,185,3,215,6,233,8,233,61,72,61                  | 1000001 |        0 | userfile/image/room/ercengbanggongqu.png   | 149,24  |
| 10000009 | 第二洽谈室    | 72,61,173,61,173,126,72,126                                             | 1000001 |        0 | userfile/image/room/ercengdierqiatang.png  | 113,84  |
| 10000010 | 男卫生间      | 259,15,283,23,304,34,304,103,259,103                                    | 1000002 |        0 | userfile/image/room/sancengnanwei.png      | 271,55  |
| 10000011 | 女卫生间      | 304,34,324,45,340,61,355,79,366,103,304,103                             | 1000002 |        0 | userfile/image/room/sancengnvwei.png       | 317,67  |
| 10000015 | A-101机房     | 365,81,422,81,422,113,365,113                                           | 1000008 |        0 | userfile/image/room/jifang.png             | 380,82  |
| 10000016 | A座大厅       | 163,59,243,59,243,113,163,113                                           | 1000008 |        0 | userfile/image/room/dating.png             | 191,73  |
| 10000024 | 第三洽谈室    | 1,126,11,94,17,76,23,57,56,38,92,30,72,26                               | 1000001 |        0 | userfile/image/room/ercengdisanqiatang.png | 32,84   |
| 10000025 | 休息室        | 87,165,186,165,186,237,161,237,137,234,113,228,87,219                   | 1000001 |        0 | userfile/image/room/ercengxiuxishi.png     | 125,184 |
| 10000026 | NEC办公区西片 | 0,0,142,0,142,400,0,400                                                 | 1000012 |        0 | userfile/image/room/NECxi.png              | 59,110  |
| 10000027 | NEC办公区中片 | 142,0,290,0,290,400,142,400                                             | 1000012 |        0 | userfile/image/room/NECzhong.png           | 196,110 |
| 10000028 | NEC办公区东片 | 290,0,425,0,425,400,290,400                                             | 1000012 |        0 | userfile/image/room/NECdong.png            | 345,110 |
+----------+---------------+-------------------------------------------------------------------------+---------+----------+--------------------------------------------+---------+
19 rows in set (0.00 sec)

4、
mysql> select * from bii_Floor;
+---------+-------+-----------+----------+------------+-------------------------------------+
| FloorID | Floor | FloorName | Location | BuildingID | Pic                                 |
+---------+-------+-----------+----------+------------+-------------------------------------+
| 1000000 |     1 | 1         |          |     100002 | userfile/image/floor/C1.png         |
| 1000001 |     2 | 2         |          |     100002 | userfile/image/floor/C2.png         |
| 1000002 |     3 | 3         |          |     100002 | userfile/image/floor/C3.png         |
| 1000003 |     0 | B1        |          |     100002 |                                     |
| 1000004 |     1 | 1         |          |     100001 |                                     |
| 1000005 |     2 | 2         |          |     100001 |                                     |
| 1000006 |     3 | 3         |          |     100001 |                                     |
| 1000007 |    -1 | B1        |          |     100001 |                                     |
| 1000008 |     1 | 1         |          |     100000 | userfile/image/floor/A1.png         |
| 1000009 |     2 | 2         |          |     100000 |                                     |
| 1000010 |     3 | 3         |          |     100000 |                                     |
| 1000011 |    -1 | B1        |          |     100000 |                                     |
| 1000012 |    11 | 11        |          |     100005 | userfile/image/floor/NEClouceng.png |
+---------+-------+-----------+----------+------------+-------------------------------------+
13 rows in set (0.00 sec)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值