PostgreSQL 源码解读(24)- 查询语句#9(查询重写)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PostgreSQL 源码解读(24)- 查询语句#9(查询重写)相关的知识,希望对你有一定的参考价值。
参考技术A本节简单介绍了PG查询语句优化部分查询重写相关的内容。查询重写在pg_rewrite_query函数中实现,该函数位于文件postgres.c中。
可以把查询重写系统当作某种宏展开的机制。
创建视图的SQL命令:
与下面两个命令相比没有什么不同:
查询重写前的Query结构:
查询重写后的Query结构:
pg_rewrite_query
QueryRewrite
fireRIRrules
ApplyRetrieveRule
SQL语句:
启动gdb,跟踪调试:
RewriteRule
1、查询重写:简单介绍了查询重写的基本概念以及改写前后的异同;
2、重写实现:通过跟踪分析,PG利用系统定义的规则进行重写,定义的规则Actions为Query结构,重写后在Query中把视图转变为子查询。
查询返回语句 - PostgreSQL
【中文标题】查询返回语句 - PostgreSQL【英文标题】:Query on Return Statement - PostgreSQL 【发布时间】:2020-04-17 14:09:00 【问题描述】:我有这个问题,我正在从 SQL Server 迁移到 PostgreSQL 12。
我正在尝试完成的场景:
函数应该有一个 RETURN 语句,无论是 SETOF 'tableType' 还是 RETURN TABLE(一些列数)
正文以记录计数开始,如果根据输入参数没有找到记录,则简单地返回零(0
),否则返回 RETURN 语句中定义的整个记录集。
SQL Server 或 Oracle 中的等效部分是:他们只需将 SELECT 语句放入过程中即可完成此操作。但是,对于 PostgreSQL 来说,这有点困难。
任何建议,请。
我现在仍然可以完成的工作 - 如果没有找到记录,它将简单地返回 NULL,可能正在使用 PERFORM,或者可能选择 NULL 作为返回 tableType 列的列名。
希望我清楚!
我想要的是-
================================================ ==============
CREATE OR REPLACE FUNCTION public.get_some_data(
id integer)
RETURNS TABLE ( id_1 integer, name character varying )
LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
p_id alias for $1;
v_cnt integer:=0;
BEGIN
SELECT COUNT(1) FROM public.exampleTable e
WHERE id::integer = e.id::integer;
IF v_cnt= 0 THEN
SELECT 0;
ELSE
SELECT
a.id, a.name
public.exampleTable a
where a.id = p_id;
END;
$BODY$;
【问题讨论】:
这是一个函数还是一个过程?您甚至使用什么语言,SQL 或 PL/PGSQL?请给我们看看你的代码好吗? 我无法真正显示我的代码。但是,迁移是从 SQL Server 过程到 POstgrSQL 函数。我使用的语言是 pgplsql。如果你愿意,我可以写一个简短的程序让你明白,我想问什么。 如果您对下面无名马的回答不满意,这可能会有所帮助。 如果你的返回类型是多行,你不能返回数字0
。
是的..就是这样!我知道,只要检查一下,是否有任何解决方法。我知道它不是 PostgrSQL 的工作方式。
【参考方案1】:
如果只想返回一组单表,使用returns setof some_table
确实是最简单的方法。最基本的 SQL 函数是:
create function get_data()
returns setof some_table
as
$$
select *
from some_table;
$$
language sql;
PL/pgSQL 并不是真正需要将 SELECT 语句放入函数中,但如果您需要做其他事情,则需要在 PL/pgSQL 函数中使用 RETURN QUERY:
create function get_data()
returns setof some_table
as
$$
begin
return query
select *
from some_table;
end;
$$
language plpgsql;
一个函数正好是 one 返回类型。你不能有一个函数有时返回一个整数,有时返回数千行和十几列。
如果你坚持返回某物,你唯一能做的就是这样:
create function get_data()
returns setof some_table
as
$$
begin
return query
select *
from some_table;
if not found then
return query
select (null::some_table).*;
end if;
end;
$$
language plpgsql;
但我认为上述解决方案非常丑陋和令人困惑(不是说愚蠢)。我当然不会让它通过代码审查。
函数的调用者可以测试是否返回了某些东西,就像我实现那个丑陋的黑客一样:使用函数后检查found
变量。
【讨论】:
呐!这可以。我想要的是 - 我在主查询上方进行了编辑。无论如何,谢谢你的帮助。 如果我找不到记录,根据输入参数,我只想返回一个零,不为空,不为空,一个数字零。这就是问题所在。我们可以在 SQL Server 过程中执行此操作,或者通过 select 语句在 plsql 过程中执行此操作,但在 Postgresql 中,它变得越来越困难。否则,它很简单,返回查询、setof 等。 @SayanB:你根本做不到。与 one 返回类型完全相同的函数。您不能即时更改该返回类型。您可以返回一个带有空值的虚拟行,但这将是一件非常奇怪的事情(我当然不会让类似的事情通过代码审查)。为什么你还需要那个?如果没有返回任何内容,调用者将知道这一点。 问题不是“为什么”。我在问,有没有办法解决这个问题。有没有其他方法可以在 PostgreSQL 中放置一种动态返回类型。我也知道这是不可能的,正在检查是否有人这样做.. @SayanB:答案是否定的,你不能那样做。我会考虑一个解决方案,一个丑陋的黑客,它也不会通过我为 Oracle 程序进行的代码审查。这样的事情最好由调用者完成。数据库迁移不仅仅是代码重写,还需要migrate your mindset to。这不是在 Postgres 中是如何完成的【参考方案2】:还有一个技巧可以尽可能接近您想要的。但我会重复其他人告诉你的内容:你不能直接做你想做的事。仅仅因为 MS SQL Server 让您摆脱糟糕的编码并不意味着 Postgres 有义务这样做。正如@a_horse_with_no_name 的链接所暗示的那样,转换代码很容易,一旦您首先迁移您对问题的看法。你能得到的最接近的是返回一个 0 id 的元组。以下是一种方式。
create or replace function public.get_some_data(
p_id integer)
returns table ( id integer, name character varying )
language plpgsql
as $$
declare
v_at_least_one boolean = false;
v_exp_rec record;
begin
for v_exp_rec in
select a.id, a.name
from public.exampletable a
where a.id = p_id
union all
select 0,null
loop
if v_exp_rec.id::integer > 0
or (v_exp_rec.id::integer = 0 and not v_at_least_one)
then
id = v_exp_rec.id;
name = v_exp_rec.name;
return next;
v_at_least_one = true;
end if;
end loop ;
return;
end
$$;
但这仍然只是一个 hack,并假设存在 id=0 的无效行。一个更好的方法是让调用路由检查函数返回的内容(无论如何它必须以一种或另一种方式这样做)并让函数只返回找到的数据而不是组成数据。那就是心态转变。这样做可以将此函数简化为一个简单的选择语句:
create or replace function public.get_some_data2(
p_id integer)
returns table ( id integer, name character varying )
language sql strict
as $$
select a.id, a.name
from public.exampletable a
where a.id = p_id;
$$;
或提供的其他解决方案之一。
【讨论】:
以上是关于PostgreSQL 源码解读(24)- 查询语句#9(查询重写)的主要内容,如果未能解决你的问题,请参考以下文章
跟我一起读postgresql源码——Executor(查询执行模块之——可优化语句的执行)
PostgreSQL 源码解读(111)- WAL#7(Insert&WAL - XLogRecordAssemble-FPW)
跟我一起读postgresql源码——Executor(查询执行模块之——Scan节点(上))