国产集中库SQL能力评测 – 子查询
子查询(Subquery),是SQL查询中的一种,它允许一个查询嵌套在另一个查询中。子查询通常用在SELECT、INSERT、UPDATE或DELETE语句中,作为一个单独的查询单元来返回数据,这些数据可以被外部查询使用。子查询通常是数据库开发中自然逻辑的体现,但对于数据库而言会带来很大挑战。一方面,子查询可能使得数据库的查询优化器难以生成高效的执行计划,优化器需要考虑如何最有效地执行嵌套查询,这可能涉及到多个表的连接、复杂的条件逻辑等,这对于优化器挑战是很大的。另一方面,子查询可能会降低SQL代码的可读性和维护性,使得优化和调试变得更加困难,特别是层次嵌套很深的子查询。此外,子查询还可能会改变数据访问模式、若逻辑复杂还可能影响索引使用等等弊端。本文将对比不同数据库对子查询的处理方式差异。
1. 子查询分类
1)子查询分类
图片
2)Oracle 示例
3)国产库支持情况
国产数据库(含MySQL)都支持了上述子查询写法,除了MySQL需要稍微调整下写法外,其他都可以无需修改直接使用。
图片
2. 子查询优化
子查询有多种优化方式,下面以 Oracle 支持的子查询优化手段为目标,看看国产数据库(含MySQL)支持情况如何。特说明,国产数据库可能含有其他子查询优化手段,下文不代表国产数据库针对子查询的全部优化能力。
图片
1)子查询展开/解嵌套
子查询展开是优化器处理带子查询的目标SQL的一种优化手段,它是指优化器不再将目标SQL中的子查询当作一个独立的处理单元来单独执行,而是将该子查询转换为它自身和外部查询之间等价的表连接。从而获得更优的执行计划。子查询展开有两种形式,一种是将子查询拆开(即将该子查询中的表、视图从子查询拿出来,然后和外部查询中的表、视图做表连接);一种是不拆开但是会把该子查询转换为一个内嵌视图(Inline View),然后再和外部查询中的表、视图做表连接。前者属于启发式查询转换,后者属于基于代价的转换。
子查询展开通常都会提高原SQL的执行效率,因为如果原SQL不做子查询展开,那么通常情况下该子查询就会在其执行计划的最后一步才执行,并且会走FILTER类型的执行计划,这也意味着对于外部查询所在结果集中的每一条记录,该子查询都会被当作一个独立的执行单元来执行一次,外部查询所在的结果集有多少条记录,该子查询就会被执行多少次(可以近似这么理解,实际上并不完全是这样)。这种执行方式的执行效率通常都不会太高,尤其是在子查询中包含两个或者两个以上表连接时,此时做子查询展开后的执行效率往往会比走FILTER类型的执行计划高很多,因为此时优化器就会有其他更多、更高效的执行路径(比如哈希连接)可以选择。
Oracle2)标量子查询合并
针对含有标量子查询的情况,优化器会尝试与主查询中的对象进行合并关联操作。
Oracle3)子查询合并
当优化器未对子查询做反嵌套的情况下,可以将两个兼容的子查询合并为一个子查询。
Oracle4)子查询推入
子查询推入是一项对未能合并或者反嵌套的子查询优化的补充优化技术。通常情况下,未能合并或者反嵌套的子查询的子计划会被放置在整个查询计划的最后步骤执行,而子查询推进使得子查询能够提前被评估,使之可以出现在整体执行计划的较早步骤,从而获得更优的执行计划。
Oracle5)简单谓词推入
简单过滤谓词推入,即简单地将主查询中作用于子查询的过滤谓词推入子查询中。它是属于启发式查询转换技术,只要满足条件就会进行转换。
Oracle6)子查询谓词迁移
谓词迁移是指在含有多个子查询的复杂查询中,将其中一个子查询的谓词条件提取出来,并推入另外的子查询中,成为谓词的一部分。
Oracle