网络
虚拟私有云 VPC
弹性公网IP EIP
弹性负载均衡 ELB
NAT网关 NAT
云专线 DC
虚拟专用网络 VPN
云连接 CC
VPC终端节点 VPCEP
企业路由器 ER
企业交换机 ESW
全球加速 GA
企业连接 EC
云原生应用网络 ANC
安全与合规
安全技术与应用
Web应用防火墙 WAF
企业主机安全 HSS
云防火墙 CFW
安全云脑 SecMaster
DDoS防护 AAD
数据加密服务 DEW
数据库安全服务 DBSS
云堡垒机 CBH
数据安全中心 DSC
云证书管理服务 CCM
威胁检测服务 MTD
态势感知 SA
认证测试中心 CTC
边缘安全 EdgeSec
应用中间件
微服务引擎 CSE
分布式消息服务Kafka版
分布式消息服务RabbitMQ版
分布式消息服务RocketMQ版
API网关 APIG
分布式缓存服务 DCS
多活高可用服务 MAS
事件网格 EG
管理与监管
统一身份认证服务 IAM
消息通知服务 SMN
云监控服务 CES
应用运维管理 AOM
应用性能管理 APM
云日志服务 LTS
云审计服务 CTS
标签管理服务 TMS
配置审计 Config
应用身份管理服务 OneAccess
资源访问管理 RAM
组织 Organizations
资源编排服务 RFS
优化顾问 OA
IAM 身份中心
云运维中心 COC
资源治理中心 RGC
解决方案
高性能计算 HPC
SAP
混合云灾备
开天工业工作台 MIW
Haydn解决方案工厂
数字化诊断治理专家服务
云生态
云商店
合作伙伴中心
华为云开发者学堂
华为云慧通差旅
开发与运维
软件开发生产线 CodeArts
需求管理 CodeArts Req
流水线 CodeArts Pipeline
代码检查 CodeArts Check
编译构建 CodeArts Build
部署 CodeArts Deploy
测试计划 CodeArts TestPlan
制品仓库 CodeArts Artifact
移动应用测试 MobileAPPTest
CodeArts IDE Online
开源镜像站 Mirrors
性能测试 CodeArts PerfTest
应用管理与运维平台 ServiceStage
云应用引擎 CAE
开源治理服务 CodeArts Governance
华为云Astro轻应用
CodeArts IDE
Astro工作流 AstroFlow
代码托管 CodeArts Repo
漏洞管理服务 CodeArts Inspector
联接 CodeArtsLink
软件建模 CodeArts Modeling
Astro企业应用 AstroPro
CodeArts盘古助手
华为云Astro大屏应用
计算
弹性云服务器 ECS
Flexus云服务
裸金属服务器 BMS
云手机服务器 CPH
专属主机 DeH
弹性伸缩 AS
镜像服务 IMS
函数工作流 FunctionGraph
云耀云服务器(旧版)
VR云渲游平台 CVR
Huawei Cloud EulerOS
云化数据中心 CloudDC
网络
虚拟私有云 VPC
弹性公网IP EIP
弹性负载均衡 ELB
NAT网关 NAT
云专线 DC
虚拟专用网络 VPN
云连接 CC
VPC终端节点 VPCEP
企业路由器 ER
企业交换机 ESW
全球加速 GA
企业连接 EC
云原生应用网络 ANC
CDN与智能边缘
内容分发网络 CDN
智能边缘云 IEC
智能边缘平台 IEF
CloudPond云服务
安全与合规
安全技术与应用
Web应用防火墙 WAF
企业主机安全 HSS
云防火墙 CFW
安全云脑 SecMaster
DDoS防护 AAD
数据加密服务 DEW
数据库安全服务 DBSS
云堡垒机 CBH
数据安全中心 DSC
云证书管理服务 CCM
威胁检测服务 MTD
态势感知 SA
认证测试中心 CTC
边缘安全 EdgeSec
大数据
MapReduce服务 MRS
数据湖探索 DLI
表格存储服务 CloudTable
可信智能计算服务 TICS
推荐系统 RES
云搜索服务 CSS
数据可视化 DLV
数据接入服务 DIS
数据仓库服务 GaussDB(DWS)
数据治理中心 DataArts Studio
湖仓构建 LakeFormation
智能数据洞察 DataArts Insight
应用中间件
微服务引擎 CSE
分布式消息服务Kafka版
分布式消息服务RabbitMQ版
分布式消息服务RocketMQ版
API网关 APIG
分布式缓存服务 DCS
多活高可用服务 MAS
事件网格 EG
开天aPaaS
应用平台 AppStage
开天企业工作台 MSSE
开天集成工作台 MSSI
API中心 API Hub
云消息服务 KooMessage
交换数据空间 EDS
云地图服务 KooMap
云手机服务 KooPhone
组织成员账号 OrgID
云空间服务 KooDrive
管理与监管
统一身份认证服务 IAM
消息通知服务 SMN
云监控服务 CES
应用运维管理 AOM
应用性能管理 APM
云日志服务 LTS
云审计服务 CTS
标签管理服务 TMS
配置审计 Config
应用身份管理服务 OneAccess
资源访问管理 RAM
组织 Organizations
资源编排服务 RFS
优化顾问 OA
IAM 身份中心
云运维中心 COC
资源治理中心 RGC
区块链
区块链服务 BCS
数字资产链 DAC
华为云区块链引擎服务 HBS
解决方案
高性能计算 HPC
SAP
混合云灾备
开天工业工作台 MIW
Haydn解决方案工厂
数字化诊断治理专家服务
价格
成本优化最佳实践
专属云商业逻辑
云生态
云商店
合作伙伴中心
华为云开发者学堂
华为云慧通差旅
其他
管理控制台
消息中心
产品价格详情
系统权限
客户关联华为云合作伙伴须知
公共问题
宽限期保留期
奖励推广计划
活动
云服务信任体系能力说明
开发与运维
软件开发生产线 CodeArts
需求管理 CodeArts Req
流水线 CodeArts Pipeline
代码检查 CodeArts Check
编译构建 CodeArts Build
部署 CodeArts Deploy
测试计划 CodeArts TestPlan
制品仓库 CodeArts Artifact
移动应用测试 MobileAPPTest
CodeArts IDE Online
开源镜像站 Mirrors
性能测试 CodeArts PerfTest
应用管理与运维平台 ServiceStage
云应用引擎 CAE
开源治理服务 CodeArts Governance
华为云Astro轻应用
CodeArts IDE
Astro工作流 AstroFlow
代码托管 CodeArts Repo
漏洞管理服务 CodeArts Inspector
联接 CodeArtsLink
软件建模 CodeArts Modeling
Astro企业应用 AstroPro
CodeArts盘古助手
华为云Astro大屏应用
存储
对象存储服务 OBS
云硬盘 EVS
云备份 CBR
高性能弹性文件服务 SFS Turbo
弹性文件服务 SFS
存储容灾服务 SDRS
云硬盘备份 VBS
云服务器备份 CSBS
数据快递服务 DES
云存储网关 CSG
专属分布式存储服务 DSS
数据工坊 DWR
地图数据 MapDS
键值存储服务 KVS
容器
云容器引擎 CCE
云容器实例 CCI
容器镜像服务 SWR
云原生服务中心 OSC
应用服务网格 ASM
华为云UCS
数据库
云数据库 RDS
数据复制服务 DRS
文档数据库服务 DDS
分布式数据库中间件 DDM
云数据库 GaussDB
云数据库 GeminiDB
数据管理服务 DAS
数据库和应用迁移 UGO
云数据库 TaurusDB
人工智能
AI开发平台ModelArts
华为HiLens
图引擎服务 GES
图像识别 Image
文字识别 OCR
自然语言处理 NLP
内容审核 Moderation
图像搜索 ImageSearch
医疗智能体 EIHealth
企业级AI应用开发专业套件 ModelArts Pro
人脸识别服务 FRS
对话机器人服务 CBS
语音交互服务 SIS
人证核身服务 IVS
视频智能分析服务 VIAS
城市智能体
自动驾驶云服务 Octopus
盘古大模型 PanguLargeModels
IoT物联网
设备接入 IoTDA
全球SIM联接 GSL
IoT数据分析 IoTA
路网数字化服务 DRIS
IoT边缘 IoTEdge
设备发放 IoTDP
企业应用
域名注册服务 Domains
云解析服务 DNS
企业门户 EWP
ICP备案
商标注册
华为云WeLink
华为云会议 Meeting
隐私保护通话 PrivateNumber
语音通话 VoiceCall
消息&短信 MSGSMS
云管理网络
SD-WAN 云服务
边缘数据中心管理 EDCM
云桌面 Workspace
应用与数据集成平台 ROMA Connect
ROMA资产中心 ROMA Exchange
API全生命周期管理 ROMA API
政企自服务管理 ESM
视频
实时音视频 SparkRTC
视频直播 Live
视频点播 VOD
媒体处理 MPC
视频接入服务 VIS
数字内容生产线 MetaStudio
迁移
主机迁移服务 SMS
对象存储迁移服务 OMS
云数据迁移 CDM
迁移中心 MGC
专属云
专属计算集群 DCC
开发者工具
SDK开发指南
API签名指南
DevStar
华为云命令行工具服务 KooCLI
Huawei Cloud Toolkit
CodeArts API
云化转型
云架构中心
云采用框架
用户服务
账号中心
费用中心
成本中心
资源中心
企业管理
工单管理
客户运营能力
国际站常见问题
支持计划
专业服务
合作伙伴支持计划
我的凭证
华为云公共事业服务云平台
工业软件
工业数字模型驱动引擎
硬件开发工具链平台云服务
工业数据转换引擎云服务

语句下推调优

更新时间:2025-01-06 GMT+08:00
分享

语句下推介绍

目前,GaussDB优化器在分布式框架下制定语句的执行策略时,有三种执行计划方式:生成下推语句计划、生成分布式执行计划、生成发送语句的分布式执行计划。

  • 下推语句计划:指直接将完整的查询语句从CN发送到DN进行执行,然后将执行结果返回给CN。
  • 分布式执行计划:指CN对查询语句进行编译和优化,生成计划树,再将计划树发送给DN进行执行,并在执行完毕后返回结果到CN。
  • 发送语句的分布式执行计划:上述两种方式都不可行时,将可下推的查询部分组成查询语句(多为基表扫描语句)下推到DN进行执行,获取中间结果到CN,然后在CN执行剩下的部分。

在第3种策略中,要将大量中间结果从DN发送到CN,并且要在CN运行不能下推的部分语句,会导致CN成为性能瓶颈(带宽、存储、计算等)。在进行性能调优的时候,应尽量避免只能选择第3种策略的查询语句。

执行语句不能下推是因为语句中含有不支持下推的函数或者不支持下推的语法。一般都可以通过等价改写规避执行计划不能下推的问题。

下推语句计划典型场景

GaussDB优化器中如果想要支持语句下推需要将GUC参数enable_fast_query_shipping设置为on即可。通常而言explain语句后没有显示具体的执行计划算子,执行计划中关键字“Data Node Scan on”出现在第一行(不包含计划格式)则说明语句已下推给DN去执行。下面从多个维度场景介绍语句下推及其支持的范围。

  1. 单表查询语句下推

    在分布式数据库中对于单表查询而言,当前语句是否可以下推需要判断CN是否要进一步参与计算而不是简单收集数据。如果CN要进一步对DN结果进行计算则语句不可下推。通常带有agg、windows function、limit/offset、sort、distinct等关键字都不可下推。

    • 可下推:简单查询,无需在CN进一步计算则可以下推。
      gaussdb=# explain select * from t where c1 > 1;
                                       QUERY PLAN                                 
      ----------------------------------------------------------------------------
       Data Node Scan on "__REMOTE_FQS_QUERY__"  (cost=0.00..0.00 rows=0 width=0)
         Node/s: All datanodes
      (2 rows)
    • 不可下推:带有limit子句,对于CN而言不能简单发语句给DN并收集数据,明显与limit语义不符。
      gaussdb=# explain select * from t limit 1;
                                           QUERY PLAN                                      
      -------------------------------------------------------------------------------------
       Limit  (cost=0.00..0.00 rows=1 width=12)
         ->  Data Node Scan on "__REMOTE_LIMIT_QUERY__"  (cost=0.00..0.00 rows=1 width=12)
               Node/s: All datanodes
      (3 rows)
    • 不可下推:带有聚集函数CN不能简单下推语句,而应该对从DN收集结果进一步聚集运算处理。
      gaussdb=# explain select sum(c1), count(*) from t;
                                           QUERY PLAN                                      
      -------------------------------------------------------------------------------------
       Aggregate  (cost=0.10..0.11 rows=1 width=20)
         ->  Data Node Scan on "__REMOTE_GROUP_QUERY__"  (cost=0.00..0.00 rows=20 width=4)
               Node/s: All datanodes
      (3 rows)
  1. 多表查询语句下推
    多表查询场景下语句能否下推通常与join条件以及分布列有关,即如果join条件与表分布列匹配得上则可下推,否则无法下推。对于复制表来说通常可以下推。
    • 创建两个hash分布表。
      gaussdb=# create table t(c1 int, c2 int, c3 int)distribute by hash(c1);
      CREATE TABLE
      gaussdb=# create table t1(c1 int, c2 int, c3 int)distribute by hash(c1);
      CREATE TABLE
    • 可下推:join条件满足两个表hash分布列属性。
      gaussdb=# explain select * from t1 join t on t.c1 = t1.c1;
                                       QUERY PLAN                                 
      ----------------------------------------------------------------------------
       Data Node Scan on "__REMOTE_FQS_QUERY__"  (cost=0.00..0.00 rows=0 width=0)
         Node/s: All datanodes
      (2 rows)
    • 不可下推:join条件不满足hash分布列属性,即t1.c2不是t1表的分布列。
      gaussdb=# explain select * from t1 join t on t.c1 = t1.c2;
                                               QUERY PLAN                                         
      --------------------------------------------------------------------------------------------
       Hash Join  (cost=0.25..0.53 rows=20 width=24)
         Hash Cond: (t1.c2 = t.c1)
         ->  Data Node Scan on t1 "_REMOTE_TABLE_QUERY_"  (cost=0.00..0.00 rows=20 width=12)
               Node/s: All datanodes
         ->  Hash  (cost=0.00..0.00 rows=20 width=12)
               ->  Data Node Scan on t "_REMOTE_TABLE_QUERY_"  (cost=0.00..0.00 rows=20 width=12)
                     Node/s: All datanodes
      (7 rows)
    • 删除两个hash分布表。
      gaussdb=# DROP TABLE t;
      DROP TABLE
      gaussdb=# DROP TABLE t1;
      DROP TABLE
  1. 集合操作、CTE下推

    集合操作场景语句能否下推,与左右子查询是否下推有关,规则如下:

    • UNION ALL左右分支都能下推且左右分支分布的DN相同,整个UNION ALL才能下推。
    • UNION/INTERSECT/INTERSECT ALL/EXCEPT/EXCEPT ALL左右分支都能下推到相同的单个节点,整个集合操作才能下推。
      --测试环境包含1个CN和6个DN
      --创建NODEGROUP,NODEGROUP中的DN名字可以通过语句SELECT node_name FROM PGXC_NODE WHERE node_type = 'D'查询,查询的结果按需替换CREATE NODE GROUP语句中WITH后的DN名。
      gaussdb=# CREATE NODE GROUP ng WITH(datanode1, datanode2, datanode3, datanode4, datanode5, datanode6);
      CREATE NODE GROUP
      --建表
      gaussdb=# CREATE TABLE t1(a int, b int, c int) DISTRIBUTE BY HASH(a) TO GROUP ng;
      CREATE TABLE
      gaussdb=# CREATE TABLE t2(a int, b int, c int) DISTRIBUTE BY HASH(a) TO GROUP ng;
      CREATE TABLE
      --UNION ALL两边都可以下推,UNION ALL可以下推
      gaussdb=# EXPLAIN (COSTS OFF) SELECT * FROM t1 UNION ALL SELECT * FROM t2;
             QUERY PLAN
      -------------------------
       Data Node Scan
         Node/s: All datanodes
      (2 rows)
      
      --union两边都可以下推,但不是单DN,所以不能下推
      gaussdb=# EXPLAIN (COSTS OFF) SELECT * FROM t1 UNION SELECT * FROM t2;
                     QUERY PLAN
      ----------------------------------------
       Streaming (type: GATHER)
         Node/s: All datanodes
         ->  HashAggregate
               Group By Key: t1.a, t1.b, t1.c
               ->  Append
                     ->  Seq Scan on t1
                     ->  Seq Scan on t2
      (7 rows)
      
      --UNION两边都可以下推,且是同一个DN,所以能下推
      gaussdb=# EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE a = 1 UNION SELECT * FROM t2 WHERE a = 1;
              QUERY PLAN
      --------------------------
       Data Node Scan
         Node/s: (ng) datanode5
      (2 rows)
      
      gaussdb=# EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE a = 1;
              QUERY PLAN
      --------------------------
       Data Node Scan
         Node/s: (ng) datanode5
      (2 rows)
      
      gaussdb=# EXPLAIN (COSTS OFF) SELECT * FROM t2 WHERE a = 3;
              QUERY PLAN
      --------------------------
       Data Node Scan
         Node/s: (ng) datanode4
      (2 rows)
      
      --union两边都可以下推,但不是同一个DN,所以不能下推
      gaussdb=# EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE a = 1 UNION SELECT * FROM t2 WHERE a = 3;
                      QUERY PLAN
      -------------------------------------------
       Streaming (type: GATHER)
         Node/s: (GenGroup) datanode4, datanode5
         ->  Unique
               ->  Sort
                     Sort Key: t1.a, t1.b, t1.c
                     ->  Append
                           ->  Seq Scan on t1
                                 Filter: (a = 1)
                           ->  Seq Scan on t2
                                 Filter: (a = 3)
      (10 rows)

    CTE场景语句能否下推,与CTE中的语句是否能够下推有关,规则如下:

    • 对于CTE,只有CTE中的语句能够下推,整个CTE才能下推。
    • 对于Recursive CTE,由于递归部分会自引用CTE,在判断递归部分能否下推时,自引用的CTE的下推信息取决于非递归部分下推信息,即非递归部分的语句可以当做自引用CTE的子查询。
    • 对于Recursive CTE,在满足CTE中的语句能下推的条件下,语句中递归部分和非递归部分都可以下推到相同的DN,整个Recursive CTE才能下推。
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      --CTE中语句能下推,CTE可以下推
      gaussdb=# EXPLAIN (COSTS OFF) WITH cte AS (SELECT * FROM t1) SELECT * FROM cte;
             QUERY PLAN
      -------------------------
       Data Node Scan
         Node/s: All datanodes
      (2 rows)
      
      --CTE中语句能下推单个DN,CTE可以下推单个DN
      gaussdb=# EXPLAIN (COSTS OFF) WITH cte AS (SELECT * FROM t1 WHERE a = 1) SELECT * FROM cte;
              QUERY PLAN
      --------------------------
       Data Node Scan
         Node/s: (ng) datanode5
      (2 rows)
      
      --CTE中语句不能下推,CTE不能下推
      gaussdb=# EXPLAIN (COSTS OFF) WITH cte AS (SELECT * FROM t1 ORDER BY a ) SELECT * FROM cte;
               QUERY PLAN
      ----------------------------
       Streaming (type: GATHER)
         Node/s: All datanodes
         ->  Sort
               Sort Key: t1.a
               ->  Seq Scan on t1
      (5 rows)
      
      --Recursive CTE中语句能下推,且递归部分和非递归部分都可以下推到相同的多个DN,Recursive CTE可以下推多个DN
      gaussdb=# EXPLAIN (COSTS OFF)
      WITH RECURSIVE cte AS (
      SELECT * FROM t1
      UNION ALL
      SELECT t2.* FROM t2, cte WHERE cte.a = t2.a) SELECT * FROM cte;
             QUERY PLAN
      -------------------------
       Data Node Scan
         Node/s: All datanodes
      (2 rows)
      
      --Recursive CTE中语句能下推,且递归部分和非递归部分都可以到相同的单个DN,Recursive CTE可以下推到单个DN
      gaussdb=# EXPLAIN (COSTS OFF)
      WITH RECURSIVE cte AS (
      SELECT * FROM t1 WHERE a = 1
      UNION ALL
      SELECT t2.* FROM t2, cte WHERE cte.a = t2.a AND t2.a = 1) SELECT * FROM cte;
              QUERY PLAN
      --------------------------
       Data Node Scan
         Node/s: (ng) datanode5
      (2 rows)
      
      --Recursive CTE中语句不能下推,Recursive CTE不能下推
      gaussdb=# EXPLAIN (COSTS OFF)
      WITH RECURSIVE cte AS (
      SELECT * FROM t1
      UNION
      SELECT t2.* FROM t2, cte WHERE cte.a = t2.a
      ) SELECT * FROM cte;
                                    QUERY PLAN
      -----------------------------------------------------------------------
       CTE Scan on cte
         CTE cte
           ->  Recursive Union
                 ->  Data Node Scan on t1 "_REMOTE_TABLE_QUERY_"
                       Node/s: All datanodes
                 ->  Hash Join
                       Hash Cond: (cte.a = t2.a)
                       ->  WorkTable Scan on cte
                       ->  Hash
                             ->  Data Node Scan on t2 "_REMOTE_TABLE_QUERY_"
                                   Node/s: All datanodes
      (11 rows)
      gaussdb=# DROP TABLE t1;
      DROP TABLE
      gaussdb=# DROP TABLE t2;
      DROP TABLE
      gaussdb=# DROP NODE GROUP ng;
      DROP NODE GROUP
      
  1. 特殊场景

    对于一些特殊场景下推规则和约束如下:

    • 对于带有WITH Recursive CTE、普通CTE、集合操作的非SELECT语句,不支持下推。
    • 语句中带有不支持下推的元素,则不支持下推(如volatile函数、not shippable函数、record类型、agg函数、returning子句、不下推的trigger等)。
    • CTE、Recursive CTE、集合操作、子查询、子链接通过常量条件无法进一步裁剪DN(可以通过改写语句,把条件写到CTE、Recursive CTE、集合操作、子查询、子链接中)。
    • CTE、Recursive CTE、集合操作与主查询进行联合查询时,只有CTE、Recursive CTE、集合操作与主查询的其它对象分布信息相同且满足下推条件时,整条语句才能下推。
    • 对于多表查询场景,如果分布表含有多列分布列,且查询条件中分布列带有参数,不支持gplan计划下推。

查看分布式执行计划是否下推

执行计划是否下推可以依靠如下方法快速判断:

  1. 将GUC参数enable_fast_query_shipping设置为off,使查询优化器使用分布式框架策略确保语句生成分布式执行计划,而非下推语句计划

    1
    SET enable_fast_query_shipping = off;
    

  2. 查看执行计划。

    如果执行计划中有Data Node Scan节点,那么此执行计划是发送语句的分布式执行计划,为不可下推的执行计划;如果执行计划中有Streaming节点,那么计划是可以下推的。

    例如如下业务SQL:

    1
    2
    3
    4
    5
    gaussdb=# explain select
    count(ss.ss_sold_date_sk order by ss.ss_sold_date_sk)c1 
    from store_sales ss, store_returns sr 
    where 
    sr.sr_customer_sk = ss.ss_customer_sk;
    

    执行计划如下,可以看出此SQL语句不能下推。

                                  QUERY PLAN
    --------------------------------------------------------------------------
    Aggregate
    ->  Hash Join
    Hash Cond: (ss.ss_customer_sk = sr.sr_customer_sk)
    ->  Data Node Scan on store_sales "_REMOTE_TABLE_QUERY_"
    Node/s: All datanodes
    ->  Hash
    ->  Data Node Scan on store_returns "_REMOTE_TABLE_QUERY_"
    Node/s: All datanodes
    (8 rows)

    例如如下业务SQL:

    1
    2
    3
    gaussdb=# create table t1(a int, b int);
    gaussdb=# create table t2(a int, b int);
    gaussdb=# explain verbose select * from t1,t2 where t1.b=t2.b;
    

    执行计划如下,可以看出此SQL语句生成下推的分布式执行计划

                       QUERY PLAN
    -------------------------------------------------
     Streaming (type: GATHER)
       Node/s: All datanodes
       ->  Nested Loop
             Join Filter: (t1.b = t2.b)
             ->  Streaming(type: REDISTRIBUTE)
                   Spawn on: All datanodes
                   ->  Seq Scan on t1
             ->  Materialize
                   ->  Streaming(type: REDISTRIBUTE)
                         Spawn on: All datanodes
                         ->  Seq Scan on t2
    (11 rows)

    清除表:

    1
    2
    gaussdb=# drop table t1;
    gaussdb=# drop table t2;
    

不支持下推的语法

以如下三个表定义说明不支持下推的SQL语法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
gaussdb=# CREATE TABLE CUSTOMER1
(
    C_CUSTKEY     BIGINT NOT NULL
  , C_NAME        VARCHAR(25) NOT NULL
  , C_ADDRESS     VARCHAR(40) NOT NULL
  , C_NATIONKEY   INT NOT NULL
  , C_PHONE       CHAR(15) NOT NULL
  , C_ACCTBAL     DECIMAL(15,2)   NOT NULL
  , C_MKTSEGMENT  CHAR(10) NOT NULL
  , C_COMMENT     VARCHAR(117) NOT NULL
)
DISTRIBUTE BY hash(C_CUSTKEY);
gaussdb=# CREATE TABLE test_stream(a int,b float); --float不支持重分布
gaussdb=# CREATE TABLE sal_emp ( c1 integer[] ) DISTRIBUTE BY replication;
  • 不支持returning语句下推
    1
    2
    3
    4
    5
    6
    7
    8
    9
    gaussdb=# explain update customer1 set C_NAME = 'a' returning c_name;
                                   QUERY PLAN                                           
    ------------------------------------------------------------------
     Update on customer1  (cost=0.00..0.00 rows=30 width=187)
       Node/s: All datanodes
       Node expr: c_custkey
       ->  Data Node Scan on customer1 "_REMOTE_TABLE_QUERY_"  (cost=0.00..0.00 rows=30 width=187)
             Node/s: All datanodes
    (5 rows)
    
  • 不支持聚集函数中使用order by语句的下推
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    gaussdb=# explain verbose select count ( c_custkey order by c_custkey) from customer1;
                                   
                             QUERY PLAN                                        
    ------------------------------------------------------------------ Aggregate  (cost=2.50..2.51 rows=1 width=8)
       Output: count(customer1.c_custkey ORDER BY customer1.c_custkey)
       ->  Data Node Scan on customer1 "_REMOTE_TABLE_QUERY_"  (cost=0.00..0.00 rows=30 width=8)
             Output: customer1.c_custkey
             Node/s: All datanodes
             Remote query: SELECT c_custkey FROM ONLY public.customer1 WHERE true
    (6 rows)
    
  • count(distinct expr)中的字段不支持重分布,则不支持下推
    1
    2
    3
    4
    5
    6
    7
    8
    9
    gaussdb=# explain verbose select count(distinct b) from test_stream;
                                              QUERY PLAN                                           
    ------------------------------------------------------------------ Aggregate  (cost=2.50..2.51 rows=1 width=8)
       Output: count(DISTINCT test_stream.b)
       ->  Data Node Scan on test_stream "_REMOTE_TABLE_QUERY_"  (cost=0.00..0.00 rows=30 width=8)
             Output: test_stream.b
             Node/s: All datanodes
             Remote query: SELECT b FROM ONLY public.test_stream WHERE true
    (6 rows)
    
  • 不支持distinct on用法下推
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    gaussdb=# explain verbose select distinct on (c_custkey) c_custkey from customer1 order by c_custkey;
                                                QUERY PLAN                                             
    ------------------------------------------------------------------ Unique  (cost=49.83..54.83 rows=30 width=8)
       Output: customer1.c_custkey
       ->  Sort  (cost=49.83..52.33 rows=30 width=8)
             Output: customer1.c_custkey
             Sort Key: customer1.c_custkey
             ->  Data Node Scan on customer1 "_REMOTE_TABLE_QUERY_"  (cost=0.00..0.00 rows=30 width=8)
                   Output: customer1.c_custkey
                   Node/s: All datanodes
                   Remote query: SELECT c_custkey FROM ONLY public.customer1 WHERE true
    (9 rows)
    
  • 不支持数组表达式下推
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    gaussdb=# explain verbose select array[c_custkey,1] from customer1 order by c_custkey;
    
                              QUERY PLAN                                                    
    ------------------------------------------------------------------ Sort  (cost=49.83..52.33 rows=30 width=8)
       Output: (ARRAY[customer1.c_custkey, 1::bigint]), customer1.c_custkey
       Sort Key: customer1.c_custkey
       ->  Data Node Scan on "__REMOTE_SORT_QUERY__"  (cost=0.00..0.00 rows=30 width=8)
             Output: (ARRAY[customer1.c_custkey, 1::bigint]), customer1.c_custkey
             Node/s: All datanodes
             Remote query: SELECT ARRAY[c_custkey, 1::bigint], c_custkey FROM ONLY public.customer1 WHERE true ORDER BY 2
    (7 rows)
    
  • With Recursive当前版本不支持下推的场景和原因如表1 With Recursive不支持下推的场景和原因所示。
    表1 With Recursive不支持下推的场景和原因

    序号

    场景

    不下推原因

    1

    包含外表的查询场景。

    LOG: SQL can't be shipped, reason: RecursiveUnion contains ForeignScan is not shippable(LOG为CN日志中打印的不下推原因,下同)

    外表,当前版本暂不支持下推。

    2

    多nodegroup场景。

    LOG: SQL can't be shipped, reason: With-Recursive under multi-nodegroup scenario is not shippable

    基表存储nodegroup不相同,或者计算nodegroup与基表不相同,当前版本暂不支持下推。

    3

    UNION不带ALL,需要去重。

    LOG: SQL can't be shipped, reason: With-Recursive does not contain "ALL" to bind recursive & none-recursive branches

    例如:

    WITH recursive t_result AS (
    SELECT dm,sj_dm,name,1 as level
    FROM test_rec_part
    WHERE sj_dm > 10
    UNION
    SELECT t2.dm,t2.sj_dm,t2.name||' > '||t1.name,t1.level+1
    FROM t_result t1
    JOIN test_rec_part t2 ON t2.sj_dm = t1.dm
    )
    SELECT * FROM t_result t;

    4

    基表中有系统表。

    LOG: SQL can't be shipped, reason: With-Recursive contains system table is not shippable

    例如:

    WITH RECURSIVE x(id) AS
    (
    select count(1) from pg_class where oid=1247
    UNION ALL
    SELECT id+1 FROM x WHERE id < 5
    ), y(id) AS
    (
    select count(1) from pg_class where oid=1247
    UNION ALL
    SELECT id+1 FROM x WHERE id < 10
    )
    SELECT y.*, x.* FROM y LEFT JOIN x USING (id) ORDER BY 1;

    5

    基表扫描只有VALUES子句,仅在CN上即可完成执行。

    LOG: SQL can't be shipped, reason: With-Recursive contains only values rte is not shippable

    例如:

    WITH RECURSIVE t(n) AS (
    VALUES (1)
    UNION ALL
    SELECT n+1 FROM t WHERE n < 100
    )
    SELECT sum(n) FROM t;

    6

    相关子查询的关联条件仅在递归部分,非递归部分无关联条件。

    LOG: SQL can't be shipped, reason: With-Recursive recursive term correlated only is not shippable

    例如:

    select  a.ID,a.Name,
    (
    with recursive cte as (
    select ID, PID, NAME from b where b.ID = 1
    union all
    select parent.ID,parent.PID,parent.NAME
    from cte as child join b as parent on child.pid=parent.id
    where child.ID = a.ID
    )
    select NAME from cte limit 1
    ) cName
    from
    (
    select id, name, count(*) as cnt
    from a group by id,name
    ) a order by 1,2;

    7

    非递归部分带limit为Replicate计划,递归部分为Hash计划,计划存在冲突。

    LOG: SQL can't be shipped, reason: With-Recursive contains conflict distribution in none-recursive(Replicate) recursive(Hash)

    例如:

    WITH recursive t_result AS (
    select * from(
    SELECT dm,sj_dm,name,1 as level
    FROM test_rec_part
    WHERE sj_dm < 10 order by dm limit 6 offset 2)
    UNION all
    SELECT t2.dm,t2.sj_dm,t2.name||' > '||t1.name,t1.level+1
    FROM t_result t1
    JOIN test_rec_part t2 ON t2.sj_dm = t1.dm
    )
    SELECT * FROM t_result t;

    8

    多层Recursive嵌套,即recursive的递归部分又嵌套另一个recursive查询。

    LOG: SQL can't be shipped, reason: Recursive CTE references recursive CTE "cte"

    例如:

    with recursive cte as
    (
    select * from rec_tb4 where id<4
    union all
    select h.id,h.parentID,h.name from
    (
    with recursive cte as
    (
    select * from rec_tb4 where id<4
    union all
    select h.id,h.parentID,h.name from rec_tb4 h inner join cte c on h.id=c.parentID
    )
    SELECT id ,parentID,name from cte order by parentID
    ) h
    inner join cte  c on h.id=c.parentID
    )
    SELECT id ,parentID,name from cte order by parentID,1,2,3;
删除表:
1
2
3
4
5
6
gaussdb=# DROP TABLE CUSTOMER1;
DROP TABLE
gaussdb=# DROP TABLE test_stream;
DROP TABLE
gaussdb=# DROP TABLE sal_emp;
DROP TABLE

不支持下推的函数

首先介绍函数的易变性。在GaussDB中共分三种形态:

  • IMMUTABLE

    表示该函数在给出同样的参数值时总是返回同样的结果。

  • STABLE

    表示该函数不能修改数据库,对相同参数值,在同一次表扫描里,该函数的返回值不变,但是返回值可能在不同SQL语句之间变化。

  • VOLATILE

    表示该函数值可以在一次表扫描内改变,因此不会做任何优化。

函数易变性可以查询pg_proc的provolatile字段获得,i代表IMMUTABLE,s代表STABLE,v代表VOLATILE。另外,在pg_proc中的proshippable字段,取值范围为t/f/NULL,这个字段与provolatile字段一起用于描述函数是否下推。

  • 如果函数的provolatile属性为i,则无论proshippable的值是否为t,则函数始终可以下推。
  • 如果函数的provolatile属性为s或v,则仅当proshippable的值为t时,函数可以下推。
  • random、exec_hadoop_sql、exec_on_extension如果出现CTE中,也不下推。因为这种场景下下推可能出现结果错误。

对于用户自定义函数,可以在创建函数的时候指定provolatile和proshippable属性的值,详细请参见CREATE FUNCTION

对于函数不能下推的场景:

  • 如果是系统函数,建议根据业务等价替换这个函数。
  • 如果是自定义函数,建议分析客户业务场景,看函数的provolatile和proshippable属性定义是否正确。

实例分析:自定义函数

对于自定义函数,如果对于确定的输入,有确定的输出,则应将函数定义为immutable类型。

利用TPCDS的销售信息举例,比如要写一个函数,获取商品的打折情况,需要一个计算折扣的函数,可以将这个函数定义为:

1
2
3
4
CREATE FUNCTION func_percent_2 (NUMERIC, NUMERIC) RETURNS NUMERIC
AS 'SELECT $1 / $2 WHERE $2 > 0.01'
LANGUAGE SQL
VOLATILE;

执行下列语句:

1
2
SELECT func_percent_2(ss_sales_price, ss_list_price)
FROM store_sales;

其执行计划为:

可见,func_percent_2并没有被下推,而是将ss_sales_price和ss_list_price收到CN上,再进行计算,消耗大量CN的资源,而且计算缓慢。

由于该自定义函数对确定的输入有确定的输出,如果将该自定义函数改为:

1
2
3
4
CREATE FUNCTION func_percent_1 (NUMERIC, NUMERIC) RETURNS NUMERIC
AS 'SELECT $1 / $2 WHERE $2 > 0.01'
LANGUAGE SQL
IMMUTABLE;

执行语句:

1
2
SELECT func_percent_1(ss_sales_price, ss_list_price)
FROM store_sales;

其执行计划为:

可见函数func_percent_1被下推到DN执行。

提示

您即将访问非华为云网站,请注意账号财产安全

文档反馈

文档反馈

意见反馈

0/500

标记内容

同时提交标记内容