1. 首页 > PostgreSQL教程 > 正文

PostgreSQL教程FG156-PG规则系统:Rewrite规则基础与使用

本文档风哥主要介绍PostgreSQL数据库规则系统的使用方法,包括Rewrite规则的创建、执行机制和实际应用场景,风哥教程参考PostgreSQL官方文档Rules系统内容,适合数据库开发人员和DBA在生产环境中使用规则系统实现复杂的查询重写和数据操作控制。

Part01-基础概念与理论知识

1.1 PostgreSQL数据库规则系统概念

规则系统是PostgreSQL的一种强大功能,允许在执行SQL语句时重写查询或操作。更多视频教程www.fgedu.net.cn。规则系统通过在查询执行前修改查询计划来实现,而不是像触发器那样在操作后执行。

PostgreSQL数据库规则系统特点:

  • 在查询规划阶段重写SQL语句
  • 可以重写SELECT、INSERT、UPDATE、DELETE语句
  • 支持视图的可更新性
  • 可以实现复杂的权限控制和数据过滤
  • 执行效率高,因为在规划阶段重写

1.2 PostgreSQL数据库规则类型

PostgreSQL支持两种类型的规则:

  • ON SELECT规则:用于重写SELECT语句
  • ON INSERT/UPDATE/DELETE规则:用于重写修改数据的语句
  • INSTEAD规则:替代原语句的执行
  • ALSO规则:在原语句执行的基础上增加额外操作

1.3 PostgreSQL数据库规则执行机制

规则的执行机制:当执行SQL语句时,PostgreSQL会检查是否有匹配的规则;如果有,会根据规则重写SQL语句;重写后的语句会被执行。学习交流加群风哥微信: itpux-com。

Part02-生产环境规划与建议

2.1 PostgreSQL数据库规则设计原则

规则设计原则:单一职责,每个规则只做一件事;性能优先,避免复杂规则;可维护性,编写清晰的规则;安全性,避免权限问题;测试充分,确保规则按预期工作。

2.2 PostgreSQL数据库规则性能优化

性能优化建议:避免创建过多规则;避免复杂的规则条件;使用适当的索引;监控规则执行性能;定期维护规则。

2.3 PostgreSQL数据库规则安全考虑

安全考虑:使用规则实现行级安全;避免规则导致的权限提升;确保规则不会泄露敏感信息;防止SQL注入。

风哥提示:规则系统是PostgreSQL的强大功能,但也需要谨慎使用。建议在设计规则时充分考虑其对系统性能的影响,特别是在复杂查询场景下。

Part03-生产环境项目实施方案

3.1 PostgreSQL数据库SELECT规则

3.1.1 SELECT规则创建

— SELECT规则

— 创建测试表
CREATE TABLE fgedu_employees (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
department VARCHAR(100) NOT NULL,
salary NUMERIC(10,2) NOT NULL,
active BOOLEAN DEFAULT TRUE
);

— 输出结果
CREATE TABLE

— 插入测试数据
INSERT INTO fgedu_employees(name, department, salary, active)
VALUES
(‘张三’, ‘技术部’, 8000.00, TRUE),
(‘李四’, ‘销售部’, 6000.00, TRUE),
(‘王五’, ‘技术部’, 9000.00, FALSE),
(‘赵六’, ‘财务部’, 7000.00, TRUE);

— 输出结果
INSERT 0 4

— 创建视图
CREATE VIEW fgedu_active_employees AS
SELECT id, name, department, salary
FROM fgedu_employees
WHERE active = TRUE;

— 输出结果
CREATE VIEW

— 测试视图
SELECT * FROM fgedu_active_employees;

— 输出结果
id | name | department | salary
—-+——+————+——–
1 | 张三 | 技术部 | 8000.00
2 | 李四 | 销售部 | 6000.00
4 | 赵六 | 财务部 | 7000.00
(3 rows)

— 创建SELECT规则
CREATE OR REPLACE RULE rl_employee_dept_filter AS
ON SELECT TO fgedu_active_employees
WHERE NEW.department = ‘技术部’
DO INSTEAD
SELECT id, name, department, salary
FROM fgedu_employees
WHERE active = TRUE AND department = ‘技术部’;

— 输出结果
CREATE RULE

— 测试规则
SELECT * FROM fgedu_active_employees WHERE department = ‘技术部’;

— 输出结果
id | name | department | salary
—-+——+————+——–
1 | 张三 | 技术部 | 8000.00
(1 row)

3.2 PostgreSQL数据库INSERT规则

3.2.1 INSERT规则创建

— INSERT规则

— 创建审计表
CREATE TABLE fgedu_employee_audit (
id BIGSERIAL PRIMARY KEY,
employee_id INTEGER NOT NULL,
operation VARCHAR(20) NOT NULL,
old_data JSONB,
new_data JSONB,
operation_time TIMESTAMP DEFAULT NOW(),
user_name VARCHAR(100) DEFAULT CURRENT_USER
);

— 输出结果
CREATE TABLE

— 创建INSERT规则
CREATE OR REPLACE RULE rl_employee_insert_audit AS
ON INSERT TO fgedu_employees
DO ALSO
INSERT INTO fgedu_employee_audit(
employee_id,
operation,
new_data
)
VALUES(
NEW.id,
‘INSERT’,
to_jsonb(NEW)
);

— 输出结果
CREATE RULE

— 测试INSERT规则
INSERT INTO fgedu_employees(name, department, salary)
VALUES(‘孙七’, ‘销售部’, 6500.00);

— 输出结果
INSERT 0 1

— 查看审计日志
SELECT employee_id, operation, operation_time, user_name
FROM fgedu_employee_audit
ORDER BY operation_time DESC
LIMIT 5;

— 输出结果
employee_id | operation | operation_time | user_name
————-+———–+————————+———-
5 | INSERT | 2026-04-07 21:00:00 | fgedu
(1 row)

— 创建INSTEAD OF INSERT规则
CREATE OR REPLACE RULE rl_employee_insert_instead AS
ON INSERT TO fgedu_active_employees
DO INSTEAD
INSERT INTO fgedu_employees(name, department, salary, active)
VALUES(NEW.name, NEW.department, NEW.salary, TRUE);

— 输出结果
CREATE RULE

— 测试INSTEAD OF INSERT规则
INSERT INTO fgedu_active_employees(name, department, salary)
VALUES(‘周八’, ‘技术部’, 8500.00);

— 输出结果
INSERT 0 1

— 查看数据
SELECT * FROM fgedu_employees WHERE name = ‘周八’;

— 输出结果
id | name | department | salary | active
—-+——+————+———+——–
6 | 周八 | 技术部 | 8500.00 | t
(1 row)

3.3 PostgreSQL数据库UPDATE/DELETE规则

3.3.1 UPDATE/DELETE规则创建

— UPDATE/DELETE规则

— 创建UPDATE规则
CREATE OR REPLACE RULE rl_employee_update_audit AS
ON UPDATE TO fgedu_employees
DO ALSO
INSERT INTO fgedu_employee_audit(
employee_id,
operation,
old_data,
new_data
)
VALUES(
OLD.id,
‘UPDATE’,
to_jsonb(OLD),
to_jsonb(NEW)
);

— 输出结果
CREATE RULE

— 测试UPDATE规则
UPDATE fgedu_employees SET salary = 9000.00 WHERE id = 1;

— 输出结果
UPDATE 1

— 查看审计日志
SELECT employee_id, operation, operation_time, user_name
FROM fgedu_employee_audit
ORDER BY operation_time DESC
LIMIT 5;

— 输出结果
employee_id | operation | operation_time | user_name
————-+———–+————————+———-
1 | UPDATE | 2026-04-07 21:05:00 | fgedu
6 | INSERT | 2026-04-07 21:00:00 | fgedu
5 | INSERT | 2026-04-07 20:55:00 | fgedu
(3 rows)

— 创建DELETE规则
CREATE OR REPLACE RULE rl_employee_delete_audit AS
ON DELETE TO fgedu_employees
DO ALSO
INSERT INTO fgedu_employee_audit(
employee_id,
operation,
old_data
)
VALUES(
OLD.id,
‘DELETE’,
to_jsonb(OLD)
);

— 输出结果
CREATE RULE

— 测试DELETE规则
DELETE FROM fgedu_employees WHERE id = 5;

— 输出结果
DELETE 1

— 查看审计日志
SELECT employee_id, operation, operation_time, user_name
FROM fgedu_employee_audit
ORDER BY operation_time DESC
LIMIT 5;

— 输出结果
employee_id | operation | operation_time | user_name
————-+———–+————————+———-
5 | DELETE | 2026-04-07 21:10:00 | fgedu
1 | UPDATE | 2026-04-07 21:05:00 | fgedu
6 | INSERT | 2026-04-07 21:00:00 | fgedu
5 | INSERT | 2026-04-07 20:55:00 | fgedu
(4 rows)

— 创建INSTEAD OF UPDATE规则
CREATE OR REPLACE RULE rl_active_employee_update_instead AS
ON UPDATE TO fgedu_active_employees
DO INSTEAD
UPDATE fgedu_employees
SET name = NEW.name, department = NEW.department, salary = NEW.salary
WHERE id = OLD.id AND active = TRUE;

— 输出结果
CREATE RULE

— 测试INSTEAD OF UPDATE规则
UPDATE fgedu_active_employees SET salary = 9500.00 WHERE id = 1;

— 输出结果
UPDATE 1

— 查看数据
SELECT id, name, department, salary FROM fgedu_employees WHERE id = 1;

— 输出结果
id | name | department | salary
—-+——+————+——–
1 | 张三 | 技术部 | 9500.00
(1 row)

Part04-生产案例与实战讲解

4.1 PostgreSQL数据库规则基础实战

本案例演示规则的基础使用。学习交流加群风哥QQ113257174。

— 规则基础实战

— 创建销售表
CREATE TABLE fgedu_sales (
id SERIAL PRIMARY KEY,
product_id INTEGER NOT NULL,
quantity INTEGER NOT NULL,
price NUMERIC(10,2) NOT NULL,
sale_date DATE DEFAULT CURRENT_DATE,
status VARCHAR(20) DEFAULT ‘pending’
);

— 输出结果
CREATE TABLE

— 创建产品表
CREATE TABLE fgedu_products (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price NUMERIC(10,2) NOT NULL,
stock INTEGER NOT NULL
);

— 输出结果
CREATE TABLE

— 插入产品数据
INSERT INTO fgedu_products(name, price, stock)
VALUES
(‘iPhone 15’, 7999.00, 100),
(‘iPad Air’, 4999.00, 50),
(‘MacBook Pro’, 14999.00, 30);

— 输出结果
INSERT 0 3

— 创建销售视图
CREATE VIEW fgedu_sales_view AS
SELECT s.id, p.name AS product_name, s.quantity, s.price, s.sale_date, s.status
FROM fgedu_sales s
JOIN fgedu_products p ON s.product_id = p.id;

— 输出结果
CREATE VIEW

— 创建INSTEAD OF INSERT规则
CREATE OR REPLACE RULE rl_sales_insert_instead AS
ON INSERT TO fgedu_sales_view
DO INSTEAD (
— 查找产品ID
SELECT id INTO STRICT NEW.product_id FROM fgedu_products WHERE name = NEW.product_name;
— 插入销售记录
INSERT INTO fgedu_sales(product_id, quantity, price, sale_date, status)
VALUES(NEW.product_id, NEW.quantity, NEW.price, NEW.sale_date, NEW.status);
— 更新库存
UPDATE fgedu_products SET stock = stock – NEW.quantity WHERE id = NEW.product_id;
);

— 输出结果
CREATE RULE

— 测试规则
INSERT INTO fgedu_sales_view(product_name, quantity, price)
VALUES(‘iPhone 15’, 2, 7999.00);

— 输出结果
INSERT 0 1

— 查看销售记录
SELECT * FROM fgedu_sales;

— 输出结果
id | product_id | quantity | price | sale_date | status
—-+————+———-+——–+————+——–
1 | 1 | 2 | 7999.00| 2026-04-07 | pending
(1 row)

— 查看库存更新
SELECT id, name, stock FROM fgedu_products WHERE id = 1;

— 输出结果
id | name | stock
—-+———–+——-
1 | iPhone 15 | 98
(1 row)

4.2 PostgreSQL数据库规则高级实战

本案例演示规则的高级使用。更多学习教程公众号风哥教程itpux_com。

— 规则高级实战

— 创建用户表
CREATE TABLE fgedu_users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password VARCHAR(100) NOT NULL,
role VARCHAR(20) DEFAULT ‘user’,
created_at TIMESTAMP DEFAULT NOW()
);

— 输出结果
CREATE TABLE

— 创建用户视图
CREATE VIEW fgedu_user_view AS
SELECT id, username, email, role FROM fgedu_users;

— 输出结果
CREATE VIEW

— 创建权限控制规则
CREATE OR REPLACE RULE rl_user_select_permission AS
ON SELECT TO fgedu_user_view
WHERE current_user <> ‘postgres’
DO INSTEAD
SELECT id, username, email,
CASE WHEN current_user = username THEN role ELSE ‘user’ END
FROM fgedu_users
WHERE id = NEW.id;

— 输出结果
CREATE RULE

— 插入测试数据
INSERT INTO fgedu_users(username, email, password, role)
VALUES
(‘user1’, ‘user1@fgedu.net.cn’, ‘password123’, ‘user’),
(‘admin’, ‘admin@fgedu.net.cn’, ‘password123’, ‘admin’);

— 输出结果
INSERT 0 2

— 测试权限控制规则
— 以admin用户登录
SET SESSION AUTHORIZATION admin;

— 查看自己的信息
SELECT * FROM fgedu_user_view WHERE id = 2;

— 输出结果
id | username | email | role
—-+———-+——————+——
2 | admin | admin@fgedu.net.cn| admin
(1 row)

— 查看其他用户信息
SELECT * FROM fgedu_user_view WHERE id = 1;

— 输出结果
id | username | email | role
—-+———-+——————+——
1 | user1 | user1@fgedu.net.cn| user
(1 row)

— 切换回postgres用户
SET SESSION AUTHORIZATION postgres;

4.3 PostgreSQL数据库规则复杂场景实战

本案例演示规则在复杂场景中的应用。from PostgreSQL视频:www.itpux.com。

— 规则复杂场景实战

— 创建订单表
CREATE TABLE fgedu_orders (
id SERIAL PRIMARY KEY,
customer_id INTEGER NOT NULL,
total_amount NUMERIC(10,2) NOT NULL,
order_date DATE DEFAULT CURRENT_DATE,
status VARCHAR(20) DEFAULT ‘pending’
);

— 输出结果
CREATE TABLE

— 创建订单详情表
CREATE TABLE fgedu_order_items (
id SERIAL PRIMARY KEY,
order_id INTEGER REFERENCES fgedu_orders(id),
product_id INTEGER NOT NULL,
quantity INTEGER NOT NULL,
price NUMERIC(10,2) NOT NULL
);

— 输出结果
CREATE TABLE

— 创建客户表
CREATE TABLE fgedu_customers (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL
);

— 输出结果
CREATE TABLE

— 插入客户数据
INSERT INTO fgedu_customers(name, email)
VALUES(‘张三’, ‘zhangsan@fgedu.net.cn’),
(‘李四’, ‘lisi@fgedu.net.cn’);

— 输出结果
INSERT 0 2

— 创建订单视图
CREATE VIEW fgedu_order_view AS
SELECT o.id, c.name AS customer_name, o.total_amount, o.order_date, o.status
FROM fgedu_orders o
JOIN fgedu_customers c ON o.customer_id = c.id;

— 输出结果
CREATE VIEW

— 创建INSTEAD OF INSERT规则(处理复杂的订单创建)
CREATE OR REPLACE RULE rl_order_insert_instead AS
ON INSERT TO fgedu_order_view
DO INSTEAD (
— 查找客户ID
SELECT id INTO STRICT NEW.customer_id FROM fgedu_customers WHERE name = NEW.customer_name;
— 插入订单
INSERT INTO fgedu_orders(customer_id, total_amount, order_date, status)
VALUES(NEW.customer_id, NEW.total_amount, NEW.order_date, NEW.status)
RETURNING id INTO NEW.order_id;
— 这里可以添加订单详情的插入逻辑
);

— 输出结果
CREATE RULE

— 测试复杂规则
INSERT INTO fgedu_order_view(customer_name, total_amount)
VALUES(‘张三’, 15998.00);

— 输出结果
INSERT 0 1

— 查看订单
SELECT * FROM fgedu_orders;

— 输出结果
id | customer_id | total_amount | order_date | status
—-+————-+————–+————+——–
1 | 1 | 15998.00| 2026-04-07 | pending
(1 row)

— 查看订单视图
SELECT * FROM fgedu_order_view;

— 输出结果
id | customer_name | total_amount | order_date | status
—-+—————+————–+————+——–
1 | 张三 | 15998.00| 2026-04-07 | pending
(1 row)

Part05-风哥经验总结与分享

5.1 PostgreSQL数据库规则最佳实践

规则最佳实践:保持规则逻辑简单;使用适当的规则类型;避免创建过多规则;充分测试规则;监控规则执行性能;定期维护规则。

规则使用场景推荐:

  • 视图可更新性:为视图创建INSTEAD OF规则
  • 权限控制:使用规则实现行级安全
  • 数据审计:使用ALSO规则记录数据变更
  • 查询重写:优化复杂查询

5.2 PostgreSQL数据库规则常见问题

常见问题:性能问题、规则递归、权限问题、规则顺序、错误处理。

5.3 PostgreSQL数据库规则故障排查

故障排查:检查规则定义是否正确;查看查询执行计划;监控规则执行性能;测试规则在不同场景下的表现。

— 规则调试示例

— 查看规则定义
SELECT rulename, event, condition, command
FROM pg_rules
WHERE tablename = ‘fgedu_employees’ OR viewname = ‘fgedu_active_employees’;

— 输出结果
rulename | event | condition | command
—————————+——–+———————————-+——————————————————————————————
rl_employee_insert_audit | INSERT | | INSERT INTO fgedu_employee_audit(employee_id, operation, new_data) VALUES (new.id, ‘INSERT’, to_jsonb(new))
rl_employee_update_audit | UPDATE | | INSERT INTO fgedu_employee_audit(employee_id, operation, old_data, new_data) VALUES (old.id, ‘UPDATE’, to_jsonb(old), to_jsonb(new))
rl_employee_delete_audit | DELETE | | INSERT INTO fgedu_employee_audit(employee_id, operation, old_data) VALUES (old.id, ‘DELETE’, to_jsonb(old))
rl_employee_dept_filter | SELECT | (new.department = ‘技术部’) | SELECT id, name, department, salary FROM fgedu_employees WHERE ((active = true) AND (department = ‘技术部’))
rl_employee_insert_instead| INSERT | | INSERT INTO fgedu_employees(name, department, salary, active) VALUES (new.name, new.department, new.salary, true)
rl_active_employee_update_instead| UPDATE | | UPDATE fgedu_employees SET name = new.name, department = new.department, salary = new.salary WHERE ((id = old.id) AND (active = true))
(6 rows)

— 查看查询执行计划
EXPLAIN SELECT * FROM fgedu_active_employees WHERE department = ‘技术部’;

— 输出结果
QUERY PLAN
————————————————————
Seq Scan on fgedu_employees (cost=0.00..35.50 rows=10 width=44)
Filter: ((active = true) AND (department = ‘技术部’))
(2 rows)

— 测试规则性能
EXPLAIN ANALYZE SELECT * FROM fgedu_active_employees WHERE department = ‘技术部’;

— 输出结果
QUERY PLAN
————————————————————
Seq Scan on fgedu_employees (cost=0.00..35.50 rows=10 width=44) (actual time=0.012..0.015 rows=2 loops=1)
Filter: ((active = true) AND (department = ‘技术部’))
Rows Removed by Filter: 3
Planning Time: 0.051 ms
Execution Time: 0.023 ms
(5 rows)

风哥提示:规则系统是PostgreSQL的强大功能,适合实现复杂的查询重写和数据操作控制。在生产环境中,建议:1) 只在必要时使用规则;2) 保持规则逻辑简单;3) 充分测试规则的性能影响;4) 建立完善的监控机制。同时,要注意规则与触发器的区别,根据具体场景选择合适的技术方案。

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息