2-6.pg特性功能之系列规则介绍和使用

PostgreSQL 规则系统介绍与使用

什么叫规则?

规则系统,更准确地说是查询重写规则系统,是 PostgreSQL 中一种在 SQL 命令执行前根据内部规则定义将其改写为另一个 SQL 命令的机制。


SELECT 规则

PostgreSQL 的视图是通过 SELECT 规则实现的。视图本质上是一个 SELECT 规则。

示例

sql 复制代码
-- 创建表
CREATE TABLE t (id INT, name VARCHAR);

-- 创建视图
CREATE VIEW myview AS SELECT * FROM t;

等价于:

sql 复制代码
CREATE TABLE myview (same column list as t);
CREATE RULE "_RETURN" AS
    ON SELECT TO myview
    DO INSTEAD SELECT * FROM t;

使用 \dt\dv 查看表和视图,会发现视图实际上是一张表,并在其上附加了一个 SELECT 规则。

SELECT 规则的限制

  1. 后续动作只能是 INSTEAD
  2. 规则的名称只能是 "_RETURN"
  3. 只能创建在空表上。
错误示例
sql 复制代码
CREATE TABLE mytab1(id INT, note VARCHAR(40));
CREATE TABLE mytab2(id INT, note VARCHAR(40));

-- 错误1:SELECT 规则必须使用 INSTEAD
CREATE RULE myrule AS ON SELECT TO mytab2 DO ALSO SELECT * FROM mytab1;

-- 错误2:规则名称必须为 "_RETURN"
CREATE RULE myrule AS ON SELECT TO mytab2 DO INSTEAD SELECT * FROM mytab1;

-- 正确:将 mytab2 变为一个视图
CREATE RULE "_RETURN" AS ON SELECT TO mytab2 DO INSTEAD SELECT * FROM mytab1;

更新规则

更新规则指的是针对 INSERTUPDATEDELETE 这 3 种 DML 操作的规则。

动作类型:ALSO 与 INSTEAD

  • ALSO:执行原操作后,额外执行规则中的动作。
  • INSTEAD:不执行原操作,只执行规则中的动作。

示例1:创建 INSERT 规则禁止插入数据

sql 复制代码
CREATE TABLE t (id INT, name VARCHAR);
INSERT INTO t VALUES (1, 'aaa'), (2, 'aaadd');

-- 创建规则:执行 INSERT 时什么都不做
CREATE RULE t_r AS ON INSERT TO t DO INSTEAD NOTHING;

-- 尝试插入,不会插入数据
INSERT INTO t VALUES (7, 'cha');

示例2:记录表的所有 DML 操作

sql 复制代码
-- 创建主表
CREATE TABLE mytab (
    id INT PRIMARY KEY,
    note TEXT
);

-- 创建操作记录表
CREATE TABLE mytab_log (
    seq BIGSERIAL PRIMARY KEY,
    oprtype CHAR(1),
    oprtime TIMESTAMP,
    old_id INT,
    new_id INT,
    old_note TEXT,
    new_note TEXT
);

-- 创建 INSERT 规则
CREATE RULE rule_mytab_insert AS
    ON INSERT TO mytab
    DO ALSO
        INSERT INTO mytab_log (oprtype, oprtime, new_id, new_note)
        VALUES ('i', NOW(), NEW.id, NEW.note);

-- 创建 UPDATE 规则
CREATE RULE rule_mytab_update AS
    ON UPDATE TO mytab
    DO ALSO
        INSERT INTO mytab_log (oprtype, oprtime, old_id, new_id, old_note, new_note)
        VALUES ('u', NOW(), OLD.id, NEW.id, OLD.note, NEW.note);

-- 创建 DELETE 规则
CREATE RULE rule_mytab_delete AS
    ON DELETE TO mytab
    DO ALSO
        INSERT INTO mytab_log (oprtype, oprtime, old_id, old_note)
        VALUES ('d', NOW(), OLD.id, OLD.note);

对原表操作

sql 复制代码
INSERT INTO mytab VALUES (1, 'note1');
UPDATE mytab SET note = 'updated' WHERE id = 1;
DELETE FROM mytab WHERE id = 1;

每条操作都会在 mytab_log 中留下记录。


规则与权限

规则从属于表或视图。如果一张表属于某个用户,则该表上的所有规则都属于该用户。用户只需要对查询中明确指定的表拥有所需权限即可进行操作。

示例

sql 复制代码
-- 用户 osdba 创建视图
CREATE VIEW myview AS SELECT id FROM mytab;
GRANT SELECT ON myview TO user01;

如果用户 user01 对底层表 mytab 没有权限,但拥有视图 myview 的查询权限,则仍可通过视图访问数据。


修改规则

sql 复制代码
ALTER RULE name ON table_name RENAME TO new_name;
  • name:现有规则的名称。
  • table_name:规则所属的表或视图(可模式限定)。
  • new_name:规则的新名称。

删除规则

sql 复制代码
DROP RULE t_rule ON t;

规则与触发器的比较

特性 规则 触发器
实现方式 查询重写 逐行触发
适用场景 批量操作、查询改写 行级操作、复杂逻辑
概念复杂度 较高 较低
性能影响 可能生成更优计划 逐行处理可能较慢

何时使用规则?何时使用触发器?

  • 规则:适用于批量操作或需要查询重写的场景,可能生成更好的执行计划,效率更高。
  • 触发器:适用于逐行处理的复杂逻辑,概念简单,易于理解和维护。

总结

功能 说明
SELECT 规则 用于实现视图,必须命名为 _RETURN,只能使用 INSTEAD
更新规则 支持 INSERT/UPDATE/DELETE,可使用 ALSOINSTEAD
权限控制 规则从属于表/视图的所有者,用户只需显式权限
与触发器对比 规则更适合批量操作与查询重写,触发器更适合行级逻辑

相关推荐
倒流时光三十年4 小时前
PostgreSQL Semi-Join(半连接)通俗讲解
数据库·postgresql
IvorySQL8 小时前
PostgreSQL 日报| RI 快速路径并发读取缺陷(8 月 13 日)
数据库·postgresql
一只fish1 天前
优化器架构对比:Oracle vs PostgreSQL vs MySQL
mysql·postgresql·oracle
ClouGence1 天前
PostgreSQL 同步到 Iceberg:开源、私有部署与 SaaS 方案对比
数据库·postgresql·开源
l1t1 天前
DeepSeek总结的在 pg_stat_statements 中诊断高基数工作负载
数据库·缓存·postgresql
测试运维日常笔记1 天前
PostgreSQL 数据库磁盘空间占用排查手顺
数据库·postgresql·oracle
IvorySQL2 天前
PostgreSQL 日报|PG18.5 回归测试崩溃问题(8 月 12 日)
大数据·数据库·人工智能·postgresql
叶 落2 天前
Ubuntu24 安装 PostgreSQL
数据库·postgresql·安装教程
copyer_xyf3 天前
Agentic RAG 实战:PostgreSQL + LangGraph 一条链路
python·postgresql·agent
jnrjian3 天前
EDB PEM 安装加强 curl
postgresql