排查 Postgres 中的慢 SQL,别漏了条件表达式

数据库 PostgreSQL
条件中的AND​并没有出错,而是将其作为了SELECT​表达式的一部分,让 PostgreSQL 灵活地计算它。这种方法允许开发者将各种SELECT表达式直接融入到条件计算中,从而提供了其他的方法,可在 PL/pgSQL 中无缝构建和测试复杂逻辑。​

介绍

最近,在 PostgreSQL 社区中,一位用户发布了一块 PL/pgSQL 代码(如下所示),惊讶地发现它没有产生语法错误:

DO $$
DECLARE i INT;
BEGIN
  i = 0;
  IF i = 0 AND THEN
    RAISE NOTICE 'i = 0';
  END IF;
END; $$;

乍一看,这个代码块似乎并不完整。请注意IF条件:它在AND运算符后面似乎缺少了一个额外的条件。从逻辑上讲,这应该会出现异常,因为AND后面的条件不完整。

IF i = 0 AND THEN

但是,在 PL/pgSQL 执行期间,条件被评估,并没有出现任何语法错误或警告。这就提出了一个关键问题:

• PostgreSQL 在内部如何处理这个条件?

• 是什么让这个看似不完整的表达式正常工作的呢?

• 条件 “i = 0 AND” 是如何被处理的?

在检视此类 PL/pgSQL 代码时,它看起来不完整,假设它应该失败的情况下,会令人惊讶。

在本文中,我们将深入研究 PL/pgSQL 的内部结构,以了解此条件语句的处理方式,以及为什么 PostgreSQL 没有将其标记为错误。

PL/pgSQL 内部的代码实现

开源软件的一个最大优势是,能够直接检查代码库。这为我们理解事物的运作方式,或在某些情况下为什么它们没有按预期中断,提供了基础。

我们的调查从PLPGSQL_STMT_IF结构开始,通过在pl_exec.c文件中的调用栈进行跟踪。

通过浏览代码,我们发现IF语句及其条件是使用exec_run_select进行求值的,它有效地执行了一条返回一个布尔结果的SELECT语句。

作为 SELECT 子句的 PL/pgSQL 条件

回顾原始的示例,条件i = 0 AND是在一个SELECT子句中处理的。在这里,AND本质上充当一个占位符,允许 PL/pgSQL 引擎在不触发语法错误的情况下计算条件。

-- the condition is evaluated as SQL,
-- "and" is treated as column alias

SELECT 0 = 0 AND;
 and
-----
 t
(1 row)

这种见解 — 条件表达式作为SELECT语句进行计算 — 开辟了新的可能性。这意味着,我们可以在 PL/pgSQL 的条件中利用各种函数,如以下示例所示。

以下代码片段说明了,在 PL/pgSQL 中计算条件表达式的不同方式:

条件

SQL

PL/pgSQL

计数求值

select count(1) = 1;

do $$
begin
if count(1) = 1 and then
raise notice '%','Matched If Clause';
else raise notice 'Not Match If Clase';
end if;
end;$$;

不区分大小写的匹配

select ('a' ilike 'A');

do $$
begin
if ('a' ilike 'A') and then
raise notice '%','Matched If Clause';
else raise notice 'Not Match If Clase';
end if;
end;$$;

复杂的 unnest – 基于数组的条件

select COUNT(col1) filter(where col1 = 'A') = 2 from (select unnest(ARRAY['A','B','A']) col1)

do $$
begin
if COUNT(col1) filter(where col1 = 'A') = 2 from (select unnest(ARRAY['A','B','A']) col1) then
raise notice '%', 'Matched If Clause';
else raise notice 'Not Match If Clase';
end if;
end;$$;

行存在性检查

select exists (select 1 from generate_series(1,10000));

do $$
begin
if exists (select 1 from generate_series(1, 10000)) then
raise notice '%', 'Matched If Clause';
else raise notice 'Not Match If Clase';
end if;
end;$$;

结论

PL/pgSQL 使用SELECT语句处理条件表达式,允许不完整的条件(如IF i = 0 AND)无错误地执行。

条件中的AND并没有出错,而是将其作为了SELECT表达式的一部分,让 PostgreSQL 灵活地计算它。这种方法允许开发者将各种SELECT表达式直接融入到条件计算中,从而提供了其他的方法,可在 PL/pgSQL 中无缝构建和测试复杂逻辑。

责任编辑:武晓燕 来源: 红石PG
相关推荐

2009-03-23 10:47:43

数据库SQLLINQ

2024-10-09 08:15:19

2010-09-10 15:20:11

SQL函数计算表达式

2024-03-25 13:46:12

C#Lambda编程

2024-10-17 17:03:43

SQL正则表达式MySQL

2010-11-12 13:20:31

SQL Server

2024-01-05 17:41:36

Rust编程循环

2014-01-05 17:41:09

PostgreSQL表达式

2009-09-16 18:03:05

Java正则表达式正则表达式实现

2009-07-09 09:51:07

Lambda表达式C#

2009-03-16 14:01:24

正则表达式函数SQL

2009-07-21 14:03:00

Scalaif表达式while循环

2022-01-14 07:56:39

C#动态查询

2020-11-04 09:23:57

Python

2024-06-27 00:36:06

2024-09-18 06:10:00

条件表达式判断代码Python

2018-09-27 15:25:08

正则表达式前端

2010-09-07 16:51:22

SQL语句表达式

2010-10-21 10:56:29

SQL Server查

2011-08-12 10:31:01

T-SQL查询基于列的逻辑表达式
点赞
收藏

51CTO技术栈公众号