工做须要写一个查询:sql
最开始写了最原始的嵌套查询:编程
select * from realservice where realservname in (select realservname from groupmember where groupname in (select groupname from v_group where vname in (select vname from vservice where vip = '10.181.65.185')));
发现很慢,查了一下用时4min 22.74sec。编程语言
而后考虑如何优化,天然想到了链接,而后优化后代码以下:优化
select * from realservice as a join groupmember as b where a.realservname=b.realservname and b.groupname in (select a.groupname from v_group as a join vservice as b where a.vname=b.vname and b.vip = '10.181.65.185');
用时0.03sec,已经很快了,可是出于好奇,想知道把in和=的区别,继续改进:.net
select * from realservice as a join groupmember as b where a.realservname=b.realservname and b.groupname=(select a.groupname from v_group as a join vservice as b where a.vname=b.vname and b.vip = '10.181.65.185');
用时0.00sec!!!!指针
因此先来了解下in和=的区别:code
等号:确切知道所要查找的内容,且为单一值时,可使用等号运算符来进行数据比较。等号运算符中可使用字符串、日期或数字。blog
in:当确切知道所要查找的内容,且为多个值时,可使用 IN 子句来进行数据比较。IN 子句中也可使用数字、字符串或日期。ip
这里子查询出来的groupname只有一个,是单一值,因此可使用等号,但若是groupname查询出来的结果是多个,再使用等号就会出错,此时只能使用in来查询了。内存
因为groupname有可能会出现有多个值的状况,因此为了保证查询的正确,这里应该使用in而不是等号。
而后看一下为何直接使用多层嵌套查询会很慢?咱们先看一下select查询的本质:
分析器会先看语句的第一个词,当它发现第一个词是SELECT关键字的时候,它会跳到FROM关键字,而后经过FROM关键字找到表名并把表装入内存。接着是找WHERE关键字,若是找不到则返回到SELECT找字段解析,若是找到WHERE,则分析其中的条件,完成后再回到SELECT分析字段。最后造成一张咱们要的虚表。
WHERE关键字后面的是条件表达式。若是学过C语言等编程语言就会知道,条件表达式计算完成后,会有一个返回值,即非0或0,非0即为真(true),0即为假(false)。同理WHERE后面的条件也有一个返回值,真或假,来肯定接下来执不执行SELECT。
分析器先找到关键字SELECT,而后跳到FROM关键字将STUDENT表导入内存,并经过指针p1找到第一条记录,接着找到WHERE关键字计算它的条件表达式,若是为真那么把这条记录装到一个虚表当中,p1再指向下一条记录。若是为假那么p1直接指向下一条记录,而不进行其它操做。一直检索完整个表,并把虚表返回给用户。
这是一个SQL语句的嵌套使用,但和上面说的SQL语句的执行过程也是相同的。嵌套的意思也就是说当分析主SQL语句(外面的那个SELECT)到WHERE关键字的时候,又进入了另外一个SQL语句中。那么也就是说,分析器先找到表Student并装入内存,一个指针(例如p1)指向Student表中的第一条记录。而后进入WHERE里分析里面的SQL语句,再把SC表装入内存,另外一个指针(例如p2)指向SC表中的第一条记录,分析WHERE后面的条件表达式,依次进行分析,最后分析出一个虚表2。
若是虚表为空表,EXISTS 虚表2 也就为false,不返回到SELECT,而p1指向下一条记录。若是虚表2不为空也就是有记录,那么EXISTS 虚表2 为true同,返回到SELECT并把p1指向的记录添加到主SQL语句的虚表1当中。(这也是为何嵌套的SQL语句SELECT 后面为通常为*的缘由,由于它EXISTS返回的只是真或假,字段的名没有意义,用*就行,固然用别的也不会错。 )
注意,这里虽然嵌套的SQL语句分析完了,但主SQL语句只执行了一遍,也就是说p1指向Student的第一条记录,p1还要再指向Student表的下一条记录并分析,这样又进入了嵌套中的SQL语句,同上面说的同样分析。当p1也到了Student表的结尾,整个SQL语句结束。返回虚表1Sname这一列。
因此,才说嵌套查询的复杂度是M*N次查询,由于每一条数据都要和一次子查询的查询结果进行比对,同时,每次查询分析到from的时候都会把表装进一次内存,建立一次临时表,M*N次的存入内存也是很大的消耗。
参考连接: