Greenplum 函数内嵌套查询在query中调用的替代方案

简介: 背景 在使用数据库过程中,用户可能会封装一些函数,用来返回一些映射值。 例如,有一张表存储了学号和学生名字,写一个函数,根据学号,返回学生名字。 SQL如下 : create table tab(id int primary key, std_name name); cr

背景

在使用数据库过程中,用户可能会封装一些函数,用来返回一些映射值。

例如,有一张表存储了学号和学生名字,写一个函数,根据学号,返回学生名字。

screenshot

SQL如下 :

create table tab(id int primary key, std_name name);

create or replace function f1(int) returns name as 
$$

  select std_name from tab where id=$1;

$$
 language sql strict volatile;

dwh=> insert into tab values (1,'abc');
INSERT 0 1

dwh=> select f1(1);
 f1  
-----
 abc
(1 row)

使用Greenplum时,可能需要注意,因为如果函数中有QUERY,但是这个函数又在QUERY中调用的话,可能会报错。

目前执行计划还不支持这种查询:

dwh=> select f1(id) from tab;
ERROR:  XX000: function cannot execute on segment because it accesses relation "public.tab" (functions.c:155)  (seg0 slice1 e45f16674.cloud.nu17:3017 pid=20659) (cdbdisp.c:1326)
DETAIL:  SQL function "f1" during startup
LOCATION:  cdbdisp_finishCommand, cdbdisp.c:1326

出错原因,在检查segment节点query tree时,如果发现树中还有非catalog类的对象,则报错。
可能是master节点对这种QUERY的处理没有彻底。

/**
 * Walker for querytree_safe_for_segment.
 */
bool querytree_safe_for_segment_walker(Node *expr, void *context)
{
        Assert(context == NULL);

        if (!expr)
        {
                /**
                 * Do not end recursion just because we have reached one leaf node.
                 */
                return false;
        }

        switch(nodeTag(expr))
        {
                case T_Query:
                        {
                                Query *q = (Query *) expr;

                                if (!allow_segment_DML &&
                                        (q->commandType != CMD_SELECT
                                         || q->intoClause != NULL
                                         || q->resultRelation > 0))
                                {
                                        elog(ERROR, "function cannot execute on segment because it issues a non-SELECT statement");
                                }

                                ListCell * f = NULL;
                                foreach(f,q->rtable)
                                {
                                        RangeTblEntry *rte = (RangeTblEntry *) lfirst(f);

                                        if (rte->rtekind == RTE_RELATION)
                                        {
                                                Assert(rte->relid != InvalidOid);

                                                Oid namespaceId = get_rel_namespace(rte->relid);

                                                Assert(namespaceId != InvalidOid);

                                                if (!(IsSystemNamespace(namespaceId) ||
                                                          IsToastNamespace(namespaceId) ||
                                                          IsAoSegmentNamespace(namespaceId)))
                                                {
                                                        elog(ERROR, "function cannot execute on segment because it accesses relation \"%s.%s\"",
                                                                        quote_identifier(get_namespace_name(namespaceId)), quote_identifier(get_rel_name(rte->relid)));
                                                }
                                        }
                                }
                                query_tree_walker(q, querytree_safe_for_segment_walker, context, 0);  
...

使用with也不能解决这个问题,因为不会等收到master节点后再调用f1

dwh=> with t as (select * from tab) select f1(id) from t;
ERROR:  XX000: function cannot execute on segment because it accesses relation "public.tab" (functions.c:155)  (seg0 slice1 e45f16674.cloud.nu17:3017 pid=26324) (cdbdisp.c:1326)
DETAIL:  SQL function "f1" during startup
LOCATION:  cdbdisp_finishCommand, cdbdisp.c:1326

dwh=> with t as (select * from tab) select * from t;
 id | std_name 
----+----------
  1 | abc
  2 | abc
(2 rows)

聚合后还是不行
dwh=> with t as (select array_agg(id) ag from tab) select unnest(ag) from t;
 unnest 
--------
      2
      1
(2 rows)

dwh=> with t as (select array_agg(id) ag from tab) select f1(unnest(ag)) from t;
ERROR:  XX000: query plan with multiple segworker groups is not supported (cdbdisp.c:302)
HINT:  likely caused by a function that reads or modifies data in a distributed table
CONTEXT:  SQL function "f1" statement 1
LOCATION:  cdbdisp_dispatchToGang, cdbdisp.c:302

怎么解决这个问题呢?
可以用子查询(括号中的部分)替代 function 。

dwh=> select *, (select std_name from tab where tab.id=t.id) from tab t;
 id | std_name | ?column? 
----+----------+----------
  1 | abc      | abc
(1 row)
目录
相关文章
|
存储 NoSQL 关系型数据库
|
Shell 网络安全 数据安全/隐私保护
|
9月前
|
人工智能 自然语言处理 搜索推荐
2025年AI Agent客服机器人深度测评:五款主流厂商对话流畅度、理解能力横向测评
2025年AI Agent客服进入“元年”,企业选型从简单问答转向深度理解与流畅交互。本文构建四大测评维度,横向对比五款主流产品,揭示AI客服向“可执行任务的AI员工”演进趋势,助力企业智能转型决策。
|
前端开发 容器
彻底理解粘性定位 - position: sticky
彻底理解粘性定位 - position: sticky
1477 154
|
存储 前端开发 JavaScript
React 文件上传组件 File Upload
本文介绍了如何在 React 中实现文件上传组件,包括基本的概念、实现步骤、常见问题及解决方案。通过 `<input type="file">` 元素选择文件,使用 `fetch` 发送请求,处理文件类型和大小限制,以及多文件上传和进度条显示等高级功能,帮助开发者构建高效、可靠的文件上传组件。
1176 3
|
数据采集 分布式计算 OLAP
最佳实践:AnalyticDB在企业级大数据分析中的应用案例
【10月更文挑战第22天】在数字化转型的大潮中,企业对数据的依赖程度越来越高。如何高效地处理和分析海量数据,从中提取有价值的洞察,成为企业竞争力的关键。作为阿里云推出的一款实时OLAP数据库服务,AnalyticDB(ADB)凭借其强大的数据处理能力和亚秒级的查询响应时间,已经在多个行业和业务场景中得到了广泛应用。本文将从个人的角度出发,分享多个成功案例,展示AnalyticDB如何助力企业在广告投放效果分析、用户行为追踪、财务报表生成等领域实现高效的数据处理与洞察发现。
1280 0
|
关系型数据库 PostgreSQL
PostgreSQL雕虫小技,分组TOP性能提升44倍
业务背景 按分组取出TOP值,是非常常见的业务需求。比如每位歌手的下载量TOP 10的曲目。 传统方法 传统的方法是使用窗口查询,PostgreSQL是支持窗口查询的。例子测试表和测试数据,生成10000个分组,1000万条记录。 postgres=# create table t
8270 1
|
监控 关系型数据库 数据库
RDS PostgreSQL内置连接池PgBouncer
2023年7月,阿里云RDS PostgreSQL支持内置数据库连接池PgBouncer,本篇文章从以下角度探讨PgBouncer:1. PgBouncer是什么;2. 应用场景 ;3. 性能对比;4. 如何使用;5. 总结
|
数据采集 存储 大数据
Python爬虫:数据获取与解析的艺术
本文介绍了Python爬虫在大数据时代的作用,重点讲解了Python爬虫基础、常用库及实战案例。Python因其简洁语法和丰富库支持成为爬虫开发的优选语言。文中提到了requests(发送HTTP请求)、BeautifulSoup(解析HTML)、Scrapy(爬虫框架)、Selenium(处理动态网页)和pandas(数据处理分析)等关键库。实战案例展示了如何爬取电商网站的商品信息,包括确定目标、发送请求、解析内容、存储数据、遍历多页及数据处理。最后,文章强调了遵守网站规则和尊重隐私的重要性。
400 2
|
SQL 缓存 PHP
【PHP开发专栏】PHP数据库查询优化技巧
【4月更文挑战第29天】本文探讨了PHP数据库查询优化技巧,包括数据库设计的规范化与反规范化,合理使用索引,优化查询逻辑,以及避免SELECT *。在SQL查询优化中,利用EXPLAIN分析查询、优化JOIN操作和子查询,以及改进WHERE条件。PHP层面的优化涉及预处理语句、缓存查询结果、分页查询优化和异步处理。此外,还提到了高级技术如数据库分区、读写分离和分布式数据库。通过这些方法,开发者能提升查询效率,优化应用性能和用户体验。
378 1