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节点(上))

24HSpring源码解读与设计详析

如何将此 postgresql 滞后语句移植到 mysql?

Juc24_AQS的概述体系架构深入源码解读(非公平)源码总结