sql嵌套查询很慢——优化方案

原创
2019/03/05 18:00
阅读数 203

工作需要写一个查询:

最开始写了最原始的嵌套查询:

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和=的区别,继续改进:

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和=的区别:

等号:确切知道所要查找的内容,且为单一值时,可以使用等号运算符来进行数据比较。等号运算符中可以使用字符串、日期或数字。

in:当确切知道所要查找的内容,且为多个值时,可以使用 IN 子句来进行数据比较。IN 子句中也可以使用数字、字符串或日期。

这里子查询出来的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次的存入内存也是很大的消耗。

参考链接:

https://blog.csdn.net/jiankunking/article/details/23590239

https://blog.csdn.net/MTbaby/article/details/79860796

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部