当前位置:网站首页>PostgreSQL V14中更好的SQL函数
PostgreSQL V14中更好的SQL函数
2022-08-03 14:04:00 【PostgreSQLChina】
SQL 函数作为一种方便的快捷方式,一直为人所知和受到重视。PostgreSQL v14 引入了一种新的、更好的编写 SQL 函数的方法。本文将展示新语法的优点。
让我们使用“经典”语法创建一个简单的 SQL 函数示例,以便我们有一些演示材料:
CREATE EXTENSION unaccent;
CREATE FUNCTION mangle(t text) RETURNS text
LANGUAGE sql
AS 'SELECT lower(unaccent(t))';
``
您可以像使用其他数据库函数一样使用新函数:
SELECT mangle('Schön dumm');
mangle
════════════
schon dumm
(1 row)
``
你可能会问 SQL 函数有什么好处。毕竟,数据库函数的主要目的是能够在数据库中运行过程代码,这是 SQL 无法做到的。但是 SQL 函数有它们的用途:
不同 SQL 语句中频繁使用的表达式的代码重用;
通过将部分代码分解为具有有意义名称的函数来使 SQL 语句更具可读性;
于语法原因需要函数,例如CREATE AGGREGATE或CREATE OPERATOR。
此外,可以内联简单的 SQL 函数,即优化器可以在查询计划时将函数调用替换为函数定义。这可以使 SQL 函数异常高效:它消除了实际函数调用的开销。因为大部分函数是优化器的黑匣子,用函数的定义替换函数通常会给你更好的估计。
如果我们EXPLAIN (VERBOSE)在示例函数上使用,我们可以看到函数内联:
EXPLAIN (VERBOSE, COSTS OFF) SELECT mangle('Schön dumm');
QUERY PLAN
══════════════════════════════════════
Result
Output: lower(unaccent('Schön dumm'::text))
(2 rows)
``
PostgreSQL 函数很棒。一个好的方面是您不限于单一的编程语言。PostgreSQL 支持用 SQL、C、PL/pgSQL(Oracle 的 PL/SQL 的克隆)、Perl、Python 和 Tcl 编写的函数,开箱即用。
但这还不是全部:在 PostgreSQL 中,您可以编写一个插件,允许您在数据库中使用您选择的任何语言。为了实现这种灵活性,PostgreSQL函数的函数体只是一个字符串常量,当 PostgreSQL 执行函数时,过程语言的调用处理程序会解释该字符串常量。这有一些不良副作用:缺乏依赖跟踪。
PostgreSQL跟踪pg_depend和pg_shdepend目录表中数据库对象之间的依赖关系。这样,数据库就知道对象之间的关系:它要么阻止您删除其他对象所依赖的对象(如具有外键引用的表),要么自动删除依赖对象(如删除被删除表上的所有索引)。
由于函数体只是 PostgreSQL 无法解释的字符串常量,因此它不会跟踪函数和函数中使用的对象之间的依赖关系。过程语言可以提供一个验证器来检查函数体的语法正确性(如果check_function_bodies = on)。验证器还可以测试函数中引用的对象是否存在,但它不能阻止您以后删除函数使用的对象。
让我们用例子来证明:
DROP EXTENSION unaccent;
SELECT mangle('boom');
ERROR: function unaccent(text) does not exist
LINE 1: SELECT lower(unaccent(t))
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
QUERY: SELECT lower(unaccent(t))
CONTEXT: SQL function "mangle" during inlining
``
我们将通过再次创建扩展来解决问题。但是,最好在DROP EXTENSION不使用CASCADE选项的情况下运行时收到错误消息。
由于 PostgreSQL 在查询执行时解析函数体,它使用当前设置search_path来解析对不使用模式名称限定的数据库对象的所有引用。这不仅限于表和视图,还扩展到函数和运算符。我们可以使用示例函数来演示这个问题:
SET search_path = pg_catalog;
SELECT public.mangle('boom');
ERROR: function unaccent(text) does not exist
LINE 1: SELECT lower(unaccent(t))
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
QUERY: SELECT lower(unaccent(t))
CONTEXT: SQL function "mangle" during inlining
``
在我们的示例中,我们可以通过在函数调用中使用public.unaccent()来避免这种烦恼。但它可能比这更糟,特别是对于SECURITY DEFINER函数。由于对每个函数和运算符进行模式限定很麻烦,推荐的解决方案是search_path在函数上强制指定模式名:
1 ALTER FUNCTION mangle(text) SET search_path = public;
``
请注意,search_path上的模式应该只允许用户使用CREATE特权,因此这对于 v15 之前的版本不是一个好主意!设置search_path的一个令人不快的缺点是它会阻止 SQL 函数的内联。
从 PostgreSQL v14 开始,SQL 函数和过程的主体不再是字符串常量。您现在可以对函数体使用以下形式之一:
CREATE FUNCTION function_name(...) RETURNS ...
RETURN expression;
CREATE FUNCTION function_name(...) RETURNS ...
BEGIN ATOMIC
statement;
...
END;
``
第一种形式要求函数体是一个表达式。因此,如果要执行查询,则必须将其包装在括号中(将其转换为子查询,这是一个有效的表达式)。例如:
CREATE FUNCTION get_data(v_id bigint) RETURNS text
RETURN (SELECT value FROM data WHERE is = v_id);
``
第二种形式允许您编写具有多个 SQL 语句的函数。与过去使用多语句 SQL 函数一样,函数的结果将是最终 SQL 语句的结果。您可以使用新语法的第二种形式来创建 SQL 过程。第一种形式显然不适合过程,因为过程没有返回值。
我们可以轻松地重写示例函数以使用新语法:
CREATE OR REPLACE FUNCTION mangle(t text) RETURNS text
RETURN lower(unaccent(t));
``
请注意,这些新的 SQL 函数可以像旧的函数一样内联到 SQL 语句中!
主要区别在于:新式SQL函数和过程在函数定义时解析,并以解析后的形式存储在系统目录表pg_proc的prosqlbody列中。结果,上面提到的两个缺点就消失了:
1、使用新型 SQL 函数进行依赖跟踪
因为函数体以解析的形式提供,所以 PostgreSQL 可以跟踪依赖关系。让我们用重新定义的示例函数来试试:
DROP EXTENSION unaccent;
ERROR: cannot drop extension unaccent because other objects depend on it
DETAIL: function mangle(text) depends on function unaccent(text)
HINT: Use DROP ... CASCADE to drop the dependent objects too.
``
2、用新型 SQL 函数修复search_path
search_path仅在解析 SQL 时才相关。由于现在在CREATE FUNCTION运行时会发生这种情况,因此我们不必担心函数执行时该参数的当前设置:
SET search_path = pg_catalog;
SELECT public.mangle('Schön besser');
mangle
══════════════
schon besser
(1 row)
``
这不仅会混淆像HeidiSQL(从来没有学过美元引用)这样的常见问题,而且对于任何将分号识别为SQL语句之间分隔符的客户机来说都是一个问题。甚至旧版本的psql也有这样的语法问题:
您可能会注意到用于定义 SQL 函数的多语句包含用于终止 SQL 语句的分号。这不仅会混淆像HeidiSQL(从来没有学过美元引用)这样的常见问题,而且对于任何将分号识别为SQL语句之间分隔符的客户机来说都是一个问题。甚至旧版本的psql也有这样的语法问题:
psql (13.7, server 15beta2)
WARNING: psql major version 13, server major version 15.
Some psql features might not work.
Type "help" for help.
test=> CREATE FUNCTION tryme() RETURNS integer
BEGIN ATOMIC
SELECT 42;
END;
ERROR: syntax error at end of input
LINE 3: SELECT 42;
^
WARNING: there is no transaction in progress
COMMIT
``
psql认为“ SELECT 42”之后的分号终止CREATE FUNCTION语句。被截断的语句会导致错误。最后的END被视为它自己的语句,它是COMMIT同义词并导致警告。
在 v14 及更高版本中,psql正确处理此类语句。pgAdmin 4 学习了 6.3 版的新语法。但我确信有很多客户还没有收到消息。
PostgreSQL v14 引入新的 SQL 函数语法在可用性和安全性方面具有很大的优势。获取支持新语法的客户端并开始将其用于您的SQL 函数。您应该考虑重写现有函数以利用这些优势。
本文分享自微信公众号 - 开源软件联盟PostgreSQL分会(kaiyuanlianmeng)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
边栏推荐
- LARS(最小角回归)
- 第07章 InnoDB数据存储结构【2.索引及调优篇】【MySQL高级】
- 爬虫——代理搭建、爬取视频网站、爬取新闻、BeautifulSoup4介绍、bs4 遍历文档树、bs4搜索文档树、bs4使用选择器
- Nanoprobes Ni-NTA-Nanogold——用于 His 标签标记和检测
- 【二叉树】从二叉树一个节点到另一个节点每一步的方向
- How to connect a VMware virtual machine to the network "recommended collection"
- Forrester:行业云帮助中国企业更快适应未来的发展
- 数据科学家 Agnis Liukis :在ML领域,初学者踩过的5个坑
- Lecture 2 Software Life Cycle
- 如何把MapGIS的区文件转为ArcGIS的SHAPE面文件
猜你喜欢
随机推荐
Ansible中的角色使用
servlet与jsp区别_servlet和class的区别
工具模板 | 用APOEM方法消除对用户行为的偏见
HCIP Fifteenth Day Notes (Three-layer Architecture of Enterprise Network, VLAN and VLAN Configuration)
15 years of software architect experience summary: In the ML field, 5 pits that beginners have stepped on
驻尼日利亚使馆发布阿布贾祖玛岩附近地区紧急安全预警
leetcode 448. Find All Numbers Disappeared in an Array 找到所有数组中消失的数字(简单)
工作流自动化,低代码是解决关键
函数在结构体中的应用练习
Nanoprobes金脂质偶联物的相关应用
MMA安装及使用优化
爱可可AI前沿推介(8.3)
atrace和systrace的基本使用方法
使用域名注册服务 Domains配置域名【华为云至简致远】
PMP每日一练 | 考试不迷路-8.3(包含敏捷+多选)
利用华为云ECS服务器搭建安防视频监控平台【华为云至简致远】
【二叉树】统计最高分的节点数目
c语言结构体知识总结
STL——vector
js \n\r 换行失败 :【white-space: pre-line;】${} Template Literals