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

背景

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

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

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)
时间: 2024-09-27 23:34:25

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

javascript嵌套函数和在函数内调用外部函数的区别分析_javascript技巧

我们都知道在函数中定义的局部变量在声明他的函数体以及其嵌套的函数内始终是有定义的,并且在函数的作用域链上始终会有个对象指向全局对象,使函数能够访问到全局变量. var ga = 'global'; var func = function() { var la = 'local'; return function() { return function() { return function() { alert(la);alert(ga); } } } } a = func(); a()()();

数据库查询优化:嵌套查询

Table of Contents 1. 嵌套查询的分类和优化概述 2. Kim: On Optimizing an SQL-like Nested Query 2.1. 嵌套查询的分类 2.1.1. A 类 2.1.2. N 类 2.1.3. J 类 2.1.4. JA 类 2.1.5. D 类 2.2. 嵌套查询的优化 3. Kiessling, SQL-Like and Quel-like correlation queries with aggregates revisited 4. G

在html中调用js文件(无路径错误和书写错误),但js中的函数无法执行

问题描述 在html中调用js文件(无路径错误和书写错误),但js中的函数无法执行 我在html中调用js文件 这个文件中有5个函数,其中有一个函数已经可以用了,但是这个文件中的另外两个函数在调用的时候却没有反映,具体代码如下html代码 <form name=""form_dx"" action=""#"" method=""post"" onSubmit=""

sqlite3-android中sqlite内联查询

问题描述 android中sqlite内联查询 private List<Map<String, Object>> getData(){ List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); Map<String, Object> map; String[] columns=new String[]{"a.name"

请问如何在混编oc文件中的c++函数内调用另一个oc函数?

问题描述 请问如何在混编oc文件中的c++函数内调用另一个oc函数? 代码文件主要以oc编写,其中有一个函数是以C++的方式编写的,因此不知应该如何在这个函数中调用类中定义的函数和变量了,求教. 头文件都正确导入了,应该没有问题的. @interface QuickConfigurationController () --@property (nonatomicstrong) NSString *nsip;@end @implementation QuickConfigurationContro

非递归二叉树遍历-c语言中函数指针作为参数与函数的嵌套

问题描述 c语言中函数指针作为参数与函数的嵌套 函数指针作为另一函数的参数和函数的嵌套的区别,感觉都是调用,有什么不一样呢?他们都适用在什么情况下!(我是在学非递归遍历二叉树时看到的) Status Visit(TElemType e){ printf("%cn",e); return OK; } Status InOrderTraverse(BiTree T ,Status(*Visit)(TElemType e)){ SqStack S; InitStack(S); Push(S,

link中的委托为什么可以调用静态函数?不是说成员函数内不能直接调用静态函数么?

问题描述 link中的委托为什么可以调用静态函数?不是说成员函数内不能直接调用静态函数么? link中的委托为什么可以调用静态函数?不是说成员函数内不能直接调用静态函数么? 解决方案 说反了吧.是静态函数不能调用成员函数. 解决方案二: 你说反了,是静态函数,不能直接调用成员函数

怎么理解:c++不允许讲函数定义嵌套在另一函数定义中

问题描述 怎么理解:c++不允许讲函数定义嵌套在另一函数定义中 怎么理解:c++不允许讲函数定义嵌套在另一函数定义中能否简单说明一下,拜托! 解决方案 C++ 11开始,允许嵌套定义了,C++ 现在支持Lambda表达式. 解决方案二: http://www.cnblogs.com/haippy/archive/2013/05/31/3111560.html #include <vector>#include <iostream>#include <algorithm>

在smarty中调用php内置函数的方法_php技巧

相信有很多朋友还不知道,可以在smarty模板里调用php的内置函数,我们一起来看看它的用法. 模板书写: {'param1'|functionName:'param2':'param3'} php函数原型: echo functionName('param1','param2','param3'); 实例: {'1234567'|substr:'1':'2'} 下面这个和函数的参数顺序有关系 {'a'|str_replace:'A':'abcd'} 直接延伸到,直接在php中写一个函数调用,不