数据库的嵌套查询的性能问题怎么解决

59次阅读
没有评论

共计 4016 个字符,预计需要花费 11 分钟才能阅读完成。

本文丸趣 TV 小编为大家详细介绍“数据库的嵌套查询的性能问题怎么解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“数据库的嵌套查询的性能问题怎么解决”文章能帮助大家解决疑惑,下面跟着丸趣 TV 小编的思路慢慢深入,一起来学习新知识吧。

解读数据库的嵌套查询的性能

explain 是非常重要的性能查询的工具!!!

1、嵌套查询

首先大家都知道我们一般不提倡嵌套查询或是 join 查询

原因在哪呢?

下面是一个简单地嵌套查询

SELECT id ,name ,age
FROM teacher
WHERE status=0 and name IN ( 
SELECT name FROM student WHERE age  18
)

我们一开始设想的是先执行内部查询,然后再执行外部查询的。

这是我们美好的愿景。

这个时候我们就可以使用 explain 来看一下这条语句的执行过程是怎样的

+------+--------------+-------------+--------+---------------+--------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+--------------+-------------+--------+---------------+--------------+---------+------+------+-------------+
| 1 | PRIMARY | teacher | ALL | NULL | NULL | NULL | NULL |65712| Using where |
| 1 | PRIMARY |  subquery2  | eq_ref | distinct_key | distinct_key | 4 | func | 1 | |
| 2 | DEPENDENT SUBQUERY| student | ALL | NULL | NULL | NULL | NULL | 418 | Using where |

这里可以看到 student 表的 select_type 是 DEPENDENT SUBQUERY

DEPENDENT SUBQUERY 是什么意思呢?

翻译就是依靠外层查询

简而言之就是 student 内层查询要依靠外层查询

如上面显示,teacher 表中关联行数是 65712

那就意味着内层查询要执行 6 万次之多,肯定会很慢的。

但也不是所有的嵌套的 select_type 都是 DEPENDENT SUBQUERY

比如还有 MATERIALIZED 类型,他就是 sql 自己进行的优化,他会在第一次进行子查询的时候建立一个临时表,保证后续查询的速度。

2、join 查询

join 连接也是类似的,联表查询时,会有一个驱动表来作为原始数据的循环表。

如果使用的是 left join 那么左表就是这个驱动表,反之亦然

我们要尽量用小表来当做驱动表。如果实在不能判断哪个比较合适就用 join 让 mysql 来帮你做选择,他会自动选择一个小表来做驱动表。

3、解决方法

1、首先,最直接简单地方法就是不使用嵌套查询。

使用多个单个的查询来代替嵌套查询

2、其次,我们还可以使用临时表进行简单地嵌套查询

SELECT id ,name ,age
FROM teacher t, (SELECT name FROM student WHERE age 18) s
WHERE t.status=0 and t.name=s.name
)

问题:数据库内部嵌套关系实现

我在做报表的时候遇到一个问题,想了很长时间没有解决,后来转换思路一下子就解决了。具体问题是这样的,我们公司有一张行业表,总共有四级行业需要维护,具体包括一级行业、二级行业、三级行业和四级行业,每个行业之间又存在包含关系,比如四级行业包含于三级行业,三级行业包含于二级行业,二级行业包含于一级行业,最诡异的地方就是我们把这么多信息放在一张表里维护,只不过额外加了两个字段以示区分,一个是行业等级,一个是父行业,具体的表结构如下:

行业 ID 行业等级父行业 ID 二级行业二级一级行业三级行业 1 三级二级行业三级行业 2 三级二级行业四级行业 1 四级三级行业 1 四级行业 2 四级三级行业 2

最后的需求是有另外一张表,是用四级行业划分的,其中有一项费用,最后需要按一级行业统计每个行业的费用。

模型

根据实际业务,为了说明这个问题,笔者在这里做了一个模型简化,假设我们只有两张表 tb_cls 和 tb_cost,tb_cls 包含行业 id,行业等级 cls,父行业 p_id,所有行业(包括一级、二级、三级行业都保存在这张表里)都包含在内,具体创建出来的表如下(为了读者阅读方便,这里做了一个简化:id 前面的第一位数代表一级行业编码,例如 121 表示属于一级大行业;整个 id 的位数代表几级行业,例如 211 总共三位表示三级行业):

另外一张表,我也做了简化,只提取其中用到的行业 id 和费用两个字段,具体的表内容如下:

问题

我们现在的任务有两个:

第一、建立三级行业跟一级行业一一对应关系;

第二、按一级行业统计费用。

思路

弯路:

最开始的思路是嵌套,就是根据现实世界的逻辑关系一层一层建立联系,SELECT * FROM tb WHERE id IN(SELECT * FROM tb WHERE),沿着这个思路尝试了很多,首先在 SELECT 外层声明的变量内层的嵌套识别不了,内外层建立的变量不能相互访问,另外一个这种建立起来的关系,没有一一对应关系,因为我们用的是 IN,最终只要存在就可以,所以没有严格的一一对应关系。具体思路如下:

1.1 第 1 层:

SELECT id FROM tb_cost

1.2 第 2 层:

SELECT p_id FROM tb_cls WHERE id IN(SELECT id FROM tb_cost) AND cls=3

1.3 第 3 层:

SELECT p_id FROM tb_cls WHERE id IN(SELECT p_id FROM tb_cls WHERE id IN(SELECT id FROM tb_cost) AND cls=3) AND cls=2

1.4 第 4 层(最终):

SELECT t1.id,t2.id FROM tb_cls AS t1,tb_cost AS t2 WHERE t1.id IN(SELECT p_id FROM tb_cls WHERE id IN(SELECT p_id FROM tb_cls WHERE id IN(SELECT id FROM tb_cost) AND cls=3) AND cls=2)AND cls=1;

最终查询的结果如下:

发现那里不对了没有,每个一级行业下面包含所有的三级行业,所以这种嵌套方式走不通,同时进一步深入下去研究发现嵌套内外层定义的变量是不能相互交互的,什么意思呢?

SELECT t1.id, var_1 FROM t1 WHERE p_id IN(SELECT id AS var_1 FROM t1)var_1 变量在内层那个 SELECT 是不可用的。

新思路:

基于上面的弯路,笔者换了一个,假设我们有 3 张一模一样的表,通过这 3 张不同的表来区分各自的逻辑关系,把这 3 张表看成不同的表,一个个添加条件,具体思路如下:

2.1 第 1 层:tb_cls(AS t3) 三级行业跟 tb_cost(AS t4) 建立关联:t3.id=t4.id AND t3.cls=3

2.2 第 2 层:tb_cls(AS t2) 二级行业跟 tb_cls(AS t3) 建立关联:t3.p_id=t2.id AND t2.cls=2

2.3 第 3 层:tb_cls(AS t1) 一级行业跟 tb_cls(AS t2) 建立关联:t2.p_id=t1.id AND t1.cls=1

最终,建立起来的三级行业对应一级行业的对应关系如下:

SELECT t1.id,t4.id FROM tb_cls AS t1,tb_cls AS t2,tb_cls AS t3,tb_cost AS t4 WHERE t4.id=t3.id AND t3.p_id=t2.id AND t2.p_id=t1.id AND t3.cls=3 AND t2.cls=2 AND t1.cls=1;

查询结果如下,跟我们实际建立的情况一致,第一个任务(第一、建立三级行业跟一级行业一一对应关系)完成。 

解决了第一个任务,第二个任务就简单多了,其实就是按照一级行业 id 加个 GROUP BY,分一下组就可以,

具体语句如下:

SELECT t1.id,SUM(t4.cost) FROM tb_cls AS t1,tb_cls AS t2,tb_cls AS t3,tb_cost AS t4 WHERE t4.id=t3.id AND t3.p_id=t2.id AND t2.p_id=t1.id AND t3.cls=3 AND t2.cls=2 AND t1.cls=1 GROUP BY t1.id;

查询结果如下,简单计算一下一级、二级、三级费用是不是查询出来的值,至此,任务二也圆满完成。

总之,当我们需要解决 SQL 语句的查询任务的时候,不要一味的选择深奥的技术、逻辑复杂的语言去解决(像笔者这里用多层嵌套,最后把自己绕进去了。)首先我们要做的是简化逻辑,能通过简单的思路解决复杂的问题本身也是一种能力,在这个基础上然后基于性能、需求、业务慢慢再继续优化 SQL 才是我们应该做的。

读到这里,这篇“数据库的嵌套查询的性能问题怎么解决”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注丸趣 TV 行业资讯频道。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-13发表,共计4016字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)