はち 函数编写

文章目录

  • 8.1 Postgresql函数功能剖析
    • 8.1.1函数功能基础知识介绍
    • 8.1.2触发器和触发器函数
  • 8.2使用SQL语言来编写函数
    • 8.2.1编写基本的SQL函数
  • 8.3用PL/ pgsql编写函数
    • 8.3.1编写基础的PL/pgSQLI函数
    • 8.3.2 PL/pgSQL编写触发器函数
  • 8.4 用PL/Python编写函数
    • 编写基本的 Python函数

  • 把若干SQL组合一起,将其作为一个单元,且每次运行时可以输入不同的参数。
  • 存储过程,用户自定义函数
  • Postgresql称函数。

  • 函数不是仅仅将一堆SQL语句编排在一起即可,其中还需要使用PL来对SQL语句的执行过程控制
  • 可用不同语言来编写函数,其中SQL,C、PL/pgSQL、 PL/Perl及 PL/Python一般都会随 Postgresql安装包附带。
  • 还支持PL/V8,通过它你可以使用 Javascript来编写函数
  • PL/V8是Web开发最爱
    • 因为JSON 、JSONB数据类型和Javascript是绝配。
  • JSON和 JSONB数据类型的详情,参考5.6

  • 还可按需安装PL/R、 PL/Java、PL/sh、 PL/TSQL等语言扩展,
  • 还有一些用于高端数据处理以及人工智能处理的试验性语言,如PL/Scheme和PL/Opencl
  • 官方手册的“过程式语言”一节査到Postgresql支持的完整语言列表

8.1 Postgresql函数功能剖析

  • 函数分基本函数、聚合函数、窗口函数和触发器函数
  • 先函数的基础知识,再详细每类函数特性

8.1.1函数功能基础知识介绍

  • 不管用何种语言,写出来的函数的结构都类似,如8-1

はち 函数编写_第1张图片

  • 参数可有默认值
  • 可选参数必须排列在必选参数的后面

  • 入参支持命名参数和匿名参数,前者必须为参数起个名字,而后者不需要。
  • 建议用命名参数,因为这样可以在函数体内通过参数名引用它,非常方便和直观。
  • 定义了一个可以接受三个入参的函数(两个是可选的)

在这里插入图片描述

  • 函数体内部通过参数名引用这些入参(ear_size、skin_ color等)。
  • 如果参数是匿名,只能通过序列号的方式来访问它:$1、$2和$3。

  • 参数输入顺序与定义时的顺序不必完全相同:

在这里插入图片描述

  • 也可

在这里插入图片描述

  • 如果函数有多个入参,且大部分是可选的,那此时适合使用带参数名的调用方式。
  • 该方式可覆盖参数默认值,且参数的输入顺序与定义时的顺序不必相同。
  • skin_ color参数未出现,因此会取默认’bLue’
  • name会覆盖默认值,且nane定义时在最后,调用时却放在了第一

はち 函数编写_第2张图片

  • 一些标记符来优化执行效率或者提升安全性
  • LANGUAGE
  • 指明本函数使用的编程语言,该语言须在当前函数所在的 database中已安装。

在这里插入图片描述

  • VOLATILITY(结果的稳定性)

  • 告诉査询规划器,当该函数执行完毕后,得到的结果是否可以缓存下来以供下次使用。它有以下几个可选值。

  • IMMUTABLE

    • 该函数的内部逻辑对外界完全无依赖。
    • 数学计算函数。
    • 定义函数索引时必须用 IMMUTABLE函数。
  • STABLE

    • 如果在同一个査询语句中多次调用该函数,
    • 则每次调用时只要使用相同的输入就总会得到相同的输出。
    • 函数内部逻辑在当前SQL的上下文环境内是有恒定输出的。
  • VOLATILE

    • 毎次都用相同的输入也是这样。
    • 那些更改数据的函数和那些依赖系统时间这类环境设置的函数就属VOLATILE
    • 是默认值。
  • VOLATILITY仅给规划器提供了一个提示信息,规划器并不一定
    会按照此设置来处理。

  • 如果函数被标记为 VOLATILE,那么规划器每次遇到此函数都会重新解析并重新执行一遍;

  • 如果为别的类型,那么规划器也可能不会对其执行结果进行缓存,因为规划器可能认为重新计算一遍反而会更快。

  • STRICT
  • 如果有任何输入为NUL,则规划器根本不会执行这个函数,直接返回NUL。
  • 如果未显式指定为 STRICT模式,则函数默认都是非严格模式的。
  • 务必慎用 STRICT,因为用了以后可能会导致规划器不使用索引。请参考我们的博文“ STRICT on SQL Functions”以获取更多细节。

  • C0ST
  • 这是标记函数中计算操作密集程度的一个相对度量值。如果使用的是SQL或 PL/PGSQL
    语言,为100;如果使用C,则该值为1。
  • 该值会影响到规划器执行 WHERE中的函数时的优先级,也会影响到是否对此函数进行结果集缓存的可能性判定。
  • 越大,则规划器会认为执行该函数需要耗费的时间越多。

  • ROWS
  • 仅当函数返回的是一个结果集时,此标记符才有用。
  • 该值是返回的结果集中记录数的一个估计
  • 规划器用来为此函数分析得出最佳的执行策略。

  • SECURITY DEFINER
  • 如果设置,则会以创建此函数的用户的权限执行此函数:
  • 未设置,则会以调用此函数的用户的权限执行此函数。
  • 如果某用户对某张表没有操作权限而又需要操作该表,
    • 就让创建该表的用户提供一个带 SECURITY DEFINER标识的函数来对此表操作。
  • 当需要进行表的访问权控制时,这个安全控制符还是很有用的。

  • PARALLEL

  • 9.6新引入

  • 允许规划器以并行模式运行。默认情况,函数会被设置为 PARALLEL UNSAFE,任何调用该函数的语句都不会被分布到多个工作进程上去并发执行。

  • 详情请参考官方手册“并行安全性”

  • SAFE

    • 允许该函数被并行执行。
    • 如果函数是IMMUTABLE,或函数不更新数据或不会修改事务状态或其他变量值,那将其设为SAFE没问题
  • UNSAFE

    • 如果函数会修改非临时数据、访问序列号生成器或者事务状态,
    • 那都应被设为UNSAFE。
    • UNSAFE的函数如果以并行模式执行可能会导致表数据被破坏或者其他系统状态被破坏
  • RESTRICTED

  • 对于使用临时表、预解析语句或者客户端连接状态的函数可以使用该选项。设为RESTRICTED的语句不会被禁止并行执行,但它只能运行在并行组中的领导组(lead)中,也就是说该函数本身不会被并行执行,但它不会阻止调用它的SL语句被并行执行。

  • 本章很多例子中都带有 PARALLEL,

    • 如果9.6之前,
    • 执行例子时把 PARALLEL去掉

8.1.2触发器和触发器函数

  • 健全的数据库都支持触发器
  • 借助它,可自动捕捉数据变化事件并处理
  • Pg对表创建触发器,
    • 也对视图创建触发器

  • 可指定触发器在语句级或记录级被触发
  • 语句级触发器,每执行一条SQL,只会被触发一次
  • 记录级触发器,SQL每修改一条记录就会被触发一次
  • 你对某表执行一个UPDATE,更新1500条记录
  • 该表上的语句级触发器只会触发一
    • 记录级触发器会触发1500

  • 还可更精细设置触发器的触发时机,
    • 支持BEFORE、 AFTER及INSTEAD OF
  • BEFORE类触发器会在语句执行前或记录行被修改前触发,
    • 取消此次修改或对要修改的数据预先备份
  • AFTER类触发器语句执行后或记录行被修改后触发,
    • 借此来获得修改后的新值,用于记录修改日志或者进行数据复制
  • INSTEAD OF类触发器会将原语句的操作内容替换掉
  • BEFORE和 AFTER类触发器只能用于表,INSTEAD OF类触发器只能用于视图

  • 如果要在触发器函数中进行数据修改,那么该触发器的触发时机只能是BEFORE类,因为在AFTER阶段所有针对新记录的修改操作都会被忽略

  • 还可在定义触发器时加上WHEN条件,
    • 限定只有那些满足筛选条件的记录被修改时才激活该触发器
  • 也可加上“ UPDATE OF+字段列表”指定只有修改了特定的列时才激活该触发器
  • 触发器与主体语句之间的触发联动机制,参考官方手册中的“触发器行为概览”一节
  • 示例7-5中演示一个视图触发器

here

8.2使用SQL语言来编写函数

  • Pg中,将现有的一条SQL语句改造为函数是又快又简单:
  • 只需在现成的SQL基础上加上函数头和函数尾
  • SQL不是过程式语言
    • 无法用上条件分支判断、循环或者定义变量等过程式语言的特性
  • 无法执行使用函数入参动态拼装的SQL语句。

  • SQL函数也有优点。
  • 査询规划器可深入到SQL函数内部,并对其中每一条SQL语句分析和优化,称inlining,即内联处理。
  • 对于别的语言编写的函数,规划器只能将其当成黑盒处理。
  • 只有SQL函数可以被内联处理,这使得SQL函数能够充分利用索引并减少重复计算。

8.2.1编写基本的SQL函数

はち 函数编写_第3张图片

  • 调用语法

在这里插入图片描述

  • 也可在SQL函数中更新数据并返回一个标量或不返回
  • 例8-3

はち 函数编写_第4张图片

8.3用PL/ pgsql编写函数

  • SQL不能满足你编写函数的需求,
  • 常见的解决方案是用PL/PGSQL。
  • 它支持通过 DECLARE语法定义本地变量及支持流程控制语法

8.3.1编写基础的PL/pgSQLI函数

  • PL/PGSQL与SQL区别,
  • 用PL/pgSQL重写8-4

はち 函数编写_第5张图片

8.3.2 PL/pgSQL编写触发器函数

  • Pg不支持SQL编写触发器函数,PL/PGSQL成编写触发器函数的首选

  • 第一步写一个触发器函数,
  • 第二步将此触发器函数显式附加到合适的触发器
  • 第二步将处理触发器的函数与触发器本身分离开,这是Pg一个强大功能
  • 可将同一个触发器函数附加到多个触发器上,从而实现触发器函数逻辑的重用
  • 该模式是Pg独创,没有任何别的数据库支持该特性。
  • 触发器函数之间完全独立,可为每个触发器函数选不同语言,这些不同语言编写的触发器可协同工作。
  • Pg支持通过一个触发事件( INSERT、 UPDATE、 DELETE)激活多个触发器,每个触发器基于不同的语言
  • 设数据库中发生某一事件时你需要将其记录下来,另外还需要发邮件通知你。
  • PL/PythonU或PL/PerlU写一个具备发送邮件功能的触发器;
  • 用PL/PGSQL语言编写一个记录日志的触发器
  • 发生指定事件时,这两个触发器会同时被触发

はち 函数编写_第6张图片

  • 1 定义触发器函数。
    • 该函数适用于任何带有upd_ts字段的表。
    • 该函数先将upd_ts的值更新为当前时间戳,然后再返回修改后的记录
  • 2“字段级触发”是9.0版支持的特性,通过可将触发器的触发时机精确到字段级别
  • 9.0版前,只要发生UPDATE或者 INSERT,上面示例中的触发器都会被触发。
  • 如果要实现字段级触发控制,就必须拿OLD.sone_column和NEM.sone_ column对比,找到发生变化的字段,然后判定是否要“字段级触发”。(INSTEAD OF触发器不支持该特性。)

8.4 用PL/Python编写函数

  • 据我所知,Pg是唯一允许用户用Python编写函数的
  • 9.0版同时支持 Python2和 Python3

はち 函数编写_第7张图片

  • 用PL/Python之前,先在服务器上搭好Python运行环境。
  • Windows和Mac Python安装包从htp:/ww. python.org/ download下载。
  • Linux/Unix各种发行版上一般都已附带Python环境,无须额
  • 官方手册中对PL/Python详情。
  • 搭建好 Python运行环境之后,需为Pg安装 Python语言扩展包

在这里插入图片描述

  • Pg上安装 Python扩展包前,确保服务器操作系统上的 Python运行环境已正常,否会遇到奇奇

  • Pg的PL/Python语言扩展包是基于某个具体版本的 Python语言包编译出来的,你需要保证服务器上的 Python版本与 plpythonu扩展包的版本是匹配的。
  • 假设你的python2u扩展包是基于 Python2.7编译,服务器上就需安装好Python2.7

编写基本的 Python函数

  • Pg会自动在Postgresql数据类型与 Python数据类型间双向转换。
  • PL/Python编写的函数支持返回数组和复合数据类型。
  • 可用PL/Python来编写触发器函数和聚合函数
  • Postgresonline站点上提供一系列介绍PL/Python的文章

  • Python可实现一些通过 PL/pgsql语言无法实现的功能。
  • 用PL/Python来编写一个文本搜索函数,实现对 Postgresql在线官方手册的内容检索。

はち 函数编写_第8张图片

你可能感兴趣的:(pg纪学即用)