【笔记】开发指南—SQL调优指南—SQL调优进阶—子查询优化和执行

简介: 子查询是指在父查询的WHERE子句或HAVING子句中嵌套另一个SELECT语句的查询,本文主要介绍如何子查询。

基本概念

根据是否存在关联项,子查询可以分为非关联子查询和关联子查询。非关联子查询是指该子查询的执行不依赖外部查询的变量,这种子查询一般只需要计算一次;而关联子查询中存在引用自外层查询的变量,逻辑上,这种子查询需要每次带入相应的变量、计算多次。


/* 例子:非关联子查询 */
SELECT * FROM lineitem WHERE l_partkey IN (SELECT p_partkey FROM part);
/* 例子:关联子查询(l_suppkey 是关联项) */
SELECT * FROM lineitem WHERE l_partkey IN (SELECT ps_partkey FROM partsupp WHERE ps_suppkey = l_suppkey);

PolarDB-X子查询支持绝大多数的子查询写法,具体参见SQL使用限制

子查询执行

对于多数常见的子查询形式,PolarDB-X可以将其改写为高效的SemiJoin或类似的基于JOIN的计算方式。这样做的好处是显而易见的。当数据量较大时,无需真正带入不同参数循环迭代,大大降低了执行代价。这种查询改写技术称为子查询的去关联化(Unnesting)。

如下示例中2个子查询去关联化可以看到执行计划中使用JOIN代替了子查询。


> EXPLAIN SELECT p_partkey, (
      SELECT COUNT(ps_partkey) FROM partsupp WHERE ps_suppkey = p_partkey
      ) supplier_count FROM part;
Project(p_partkey="p_partkey", supplier_count="CASE(IS NULL($10), 0, $9)", cor=[$cor0])
  HashJoin(condition="p_partkey = ps_suppkey", type="left")
    Gather(concurrent=true)
      LogicalView(tables="part_[0-7]", shardCount=8, sql="SELECT * FROM `part` AS `part`")
    Project(count(ps_partkey)="count(ps_partkey)", ps_suppkey="ps_suppkey", count(ps_partkey)2="count(ps_partkey)")
      HashAgg(group="ps_suppkey", count(ps_partkey)="SUM(count(ps_partkey))")
        Gather(concurrent=true)
          LogicalView(tables="partsupp_[0-7]", shardCount=8, sql="SELECT `ps_suppkey`, COUNT(`ps_partkey`) AS `count(ps_partkey)` FROM `partsupp` AS `partsupp` GROUP BY `ps_suppkey`")


> EXPLAIN SELECT p_partkey, (

SELECT COUNT(ps_partkey) FROM partsupp WHERE ps_suppkey = p_partkey
) supplier_count FROM part;
Project(p_partkey="p_partkey", supplier_count="CASE(IS NULL($10), 0, $9)", cor=[$cor0])
HashJoin(condition="p_partkey = ps_suppkey", type="left")
Gather(concurrent=true)
LogicalView(tables="part_[0-7]", shardCount=8, sql="SELECT * FROM `part` AS `part`")
Project(count(ps_partkey)="count(ps_partkey)", ps_suppkey="ps_suppkey", count(ps_partkey)2="count(ps_partkey)")
HashAgg(group="ps_suppkey", count(ps_partkey)="SUM(count(ps_partkey))")
Gather(concurrent=true)
LogicalView(tables="partsupp_[0-7]", shardCount=8, sql="SELECT `ps_suppkey`, COUNT(`ps_partkey`) AS `count(ps_partkey)` FROM `partsupp` AS `partsupp` GROUP BY `ps_suppkey`")

某些场景下,PolarDB-X无法将子查询进行去关联化,这时会采用迭代执行的方式。如果外层查询数据量很大,迭代执行可能会非常慢。

如下示例由于OR l_partkey < 50的存在,导致子查询无法被去关联化,因而采用了迭代执行:


> EXPLAIN SELECT * FROM lineitem WHERE l_partkey IN (SELECT ps_partkey FROM partsupp WHERE ps_suppkey = l_suppkey) OR l_partkey IS NOT
Filter(condition="IS(in,[$1])[29612489] OR l_partkey < ?0")
Gather(concurrent=true)
LogicalView(tables="QIMU_0000_GROUP,QIMU_0001_GROUP.lineitem_[0-7]", shardCount=8, sql="SELECT * FROM `lineitem` AS `lineitem`")
>> individual correlate subquery : 29612489
Gather(concurrent=true)
LogicalView(tables="QIMU_0000_GROUP,QIMU_0001_GROUP.partsupp_[0-7]", shardCount=8, sql="SELECT * FROM (SELECT `ps_partkey` FROM `partsupp` AS `partsupp` WHERE (`ps_suppkey` = `l_suppkey`)) AS `t0` WHERE (((`l_partkey` = `ps_partkey`) OR (`l_partkey` IS NULL)) OR (`ps_partkey` IS NULL))")

这种情形下,建议改写SQL去掉子查询的OR条件。

相关文章
|
SQL 数据库
SQL Server 连接查询和子查询
SQL Server 连接查询和子查询
368 0
sql语言之子查询语句
sql语言之子查询语句
|
6月前
|
SQL 关系型数据库 PostgreSQL
CTE vs 子查询:深入拆解PostgreSQL复杂SQL的隐藏性能差异
本文深入探讨了PostgreSQL中CTE(公共表表达式)与子查询的选择对SQL性能的影响。通过分析两者底层机制,揭示CTE的物化特性及子查询的优化融合优势,并结合多场景案例对比执行效率。最终给出决策指南,帮助开发者根据数据量、引用次数和复杂度选择最优方案,同时提供高级优化技巧和版本演进建议,助力SQL性能调优。
633 1
|
SQL 关系型数据库 PostgreSQL
遇到SQL 子查询性能很差?其实可以这样优化
遇到SQL 子查询性能很差?其实可以这样优化
612 2
SQL进阶之疯狂的子查询
今天我们不谈子查询的执行效率,只谈子查询功能。对于SQL语句来说,编程开发人员应该都不会陌生,其实各种复杂的逻辑最终落地也就是那么几个基本的招式,增删改查,然而我们经常听到武功招式中又各种连招,那就是了,子查询就是这么个意思。很多SQL简单查询完成不了的查询,子查询都可以很疯狂地完成。当然有的需要一个子查询就够了,有的甚至可能需要嵌套多个子查询来完成。
399 0
SQL进阶之疯狂的子查询
|
SQL 数据挖掘 数据库
SQL 子查询深度剖析来袭!嵌套查询竟有如此无限可能,带你轻松玩转复杂数据检索与操作!
【8月更文挑战第31天】在 SQL 中,子查询是一种强大的工具,允许在一个查询内嵌套另一个查询,从而实现复杂的数据检索和操作。子查询分为标量子查询、列子查询和行子查询,可用于 SELECT、FROM、WHERE 和 HAVING 子句中。例如,查找年龄大于平均年龄的学生或每个课程中成绩最高的学生。子查询具有灵活性、可重用性和潜在的性能优化优势,但需注意性能问题、可读性和数据库支持。合理使用子查询能够显著提升查询效率和代码维护性。
390 1
|
SQL
什么是SQL中的子查询?
【8月更文挑战第2天】什么是SQL中的子查询?
219 1
|
SQL 数据库 开发者
SQL中的子查询:嵌套查询的深度解析
【8月更文挑战第31天】
1977 0
|
SQL 数据处理 数据库
SQL进阶之路:深入解析数据更新与删除技巧——掌握批量操作、条件筛选、子查询和事务处理,提升数据库维护效率与准确性
【8月更文挑战第31天】在数据库管理和应用开发中,数据的更新和删除至关重要,直接影响数据准确性、一致性和性能。本文通过具体案例,深入解析SQL中的高级更新(UPDATE)和删除(DELETE)技巧,包括批量更新、基于条件的删除以及使用子查询和事务处理复杂场景等,帮助读者提升数据处理能力。掌握这些技巧能够有效提高数据库性能并确保数据一致性。
589 0
|
SQL 数据库
SQL中字段跟子查询结果判等,子查询结果为null的处理办法
前言:今天写功能的时候遇到一个问题,SQL中字段跟子查询结果判等,子查询结果为null,查询不到数据