GreenPlum教程FG013-GreenPlum事务与并发控制实战
本文档风哥主要介绍GreenPlum事务与并发控制,包括事务概念、隔离级别、事务最佳实践、事务操作、锁机制、死锁处理等内容,风哥教程参考GreenPlum官方文档Administrator Guide、Concurrency Control等内容编写,适合DBA人员在学习和测试中使用。
Part01-基础概念与理论知识
1.1 GreenPlum事务概念
事务是数据库操作的逻辑单位,具有ACID特性。GreenPlum基于PostgreSQL,支持完整的事务机制。更多视频教程www.fgedu.net.cn
1.1.1 ACID特性
1. 原子性(Atomicity)
– 事务是不可分割的工作单位
– 要么全部执行,要么全部不执行
– 通过WAL日志保证
2. 一致性(Consistency)
– 事务执行前后数据库状态一致
– 满足所有约束和规则
– 通过约束和触发器保证
3. 隔离性(Isolation)
– 多个事务并发执行互不干扰
– 通过锁机制和MVCC保证
– 支持多种隔离级别
4. 持久性(Durability)
– 事务提交后永久保存
– 通过WAL日志保证
– 即使系统故障也能恢复
1.2 GreenPlum隔离级别
GreenPlum支持多种事务隔离级别,控制并发事务之间的可见性。学习交流加群风哥微信: itpux-com
1.2.1 隔离级别类型
1. Read Uncommitted(读未提交)
– 可能读到未提交的数据
– 不推荐使用
– GreenPlum不支持真正的读未提交
2. Read Committed(读已提交)
– 只能读到已提交的数据
– GreenPlum默认级别
– 每个查询看到最新的快照
3. Repeatable Read(可重复读)
– 同一事务内多次读取结果相同
– 基于事务开始时的快照
– 防止不可重复读
4. Serializable(可串行化)
– 最高隔离级别
– 完全隔离并发事务
– 性能影响较大
设置隔离级别:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Part02-生产环境规划与建议
2.1 GreenPlum事务最佳实践
- 事务要短小精悍,避免长事务
- 合理设置隔离级别
- 避免在事务中执行耗时操作
- 及时提交或回滚事务
- 监控长事务和锁等待
Part03-生产环境项目实施方案
3.1 GreenPlum事务操作实战
3.1.1 基本事务操作
$ psql -d fgedudb -U fgedu
psql (9.4.26)
Type “help” for help.
fgedudb=>
# 创建测试表
fgedudb=> CREATE TABLE fgedu.fgedu_account (
fgedudb(> account_id INT PRIMARY KEY,
fgedudb(> account_name VARCHAR(100),
fgedudb(> balance NUMERIC(18,2)
fgedudb(> ) DISTRIBUTED BY (account_id);
CREATE TABLE
fgedudb=> INSERT INTO fgedu.fgedu_account VALUES
fgedudb-> (1, ‘账户A’, 10000.00),
fgedudb-> (2, ‘账户B’, 5000.00);
INSERT 0 2
# 开始事务
fgedudb=> BEGIN;
BEGIN
# 执行转账操作
fgedudb=> UPDATE fgedu.fgedu_account SET balance = balance – 1000 WHERE account_id = 1;
UPDATE 1
fgedudb=> UPDATE fgedu.fgedu_account SET balance = balance + 1000 WHERE account_id = 2;
UPDATE 1
# 提交事务
fgedudb=> COMMIT;
COMMIT
# 查看结果
fgedudb=> SELECT * FROM fgedu.fgedu_account;
account_id | account_name | balance
————+————–+———-
1 | 账户A | 9000.00
2 | 账户B | 6000.00
(2 rows)
学习交流加群风哥QQ113257174
3.1.2 事务回滚
fgedudb=> BEGIN;
BEGIN
fgedudb=> UPDATE fgedu.fgedu_account SET balance = balance – 5000 WHERE account_id = 1;
UPDATE 1
# 发现余额不足,回滚事务
fgedudb=> ROLLBACK;
ROLLBACK
# 查看结果(数据未改变)
fgedudb=> SELECT * FROM fgedu.fgedu_account WHERE account_id = 1;
account_id | account_name | balance
————+————–+———-
1 | 账户A | 9000.00
(1 row)
# 使用保存点
fgedudb=> BEGIN;
BEGIN
fgedudb=> INSERT INTO fgedu.fgedu_account VALUES (3, ‘账户C’, 3000.00);
INSERT 0 1
# 设置保存点
fgedudb=> SAVEPOINT sp1;
SAVEPOINT
fgedudb=> UPDATE fgedu.fgedu_account SET balance = 0 WHERE account_id = 3;
UPDATE 1
# 回滚到保存点
fgedudb=> ROLLBACK TO SAVEPOINT sp1;
ROLLBACK
fgedudb=> COMMIT;
COMMIT
更多学习教程公众号风哥教程itpux_com
3.2 GreenPlum锁机制实战
3.2.1 锁类型
1. 表级锁
– ACCESS SHARE:SELECT
– ROW SHARE:SELECT FOR UPDATE/SHARE
– ROW EXCLUSIVE:INSERT/UPDATE/DELETE
– SHARE UPDATE EXCLUSIVE:VACUUM
– SHARE:创建索引(非并发)
– SHARE ROW EXCLUSIVE:排他锁
– EXCLUSIVE:排他锁
– ACCESS EXCLUSIVE:ALTER TABLE/DROP TABLE
2. 行级锁
– FOR UPDATE:排他行锁
– FOR SHARE:共享行锁
– FOR NO KEY UPDATE:非键更新锁
– FOR KEY SHARE:键共享锁
3. 查看锁信息
SELECT * FROM pg_locks;
SELECT * FROM pg_stat_activity;
3.2.2 锁监控
fgedudb=> SELECT
fgedudb-> l.locktype,
fgedudb-> l.database,
fgedudb-> l.relation,
fgedudb-> l.page,
fgedudb-> l.tuple,
fgedudb-> l.virtualxid,
fgedudb-> l.transactionid,
fgedudb-> l.classid,
fgedudb-> l.objid,
fgedudb-> l.objsubid,
fgedudb-> l.virtualtransaction,
fgedudb-> l.pid,
fgedudb-> l.mode,
fgedudb-> l.granted
fgedudb-> FROM pg_locks l
fgedudb-> WHERE l.database = (SELECT oid FROM pg_database WHERE datname = ‘fgedudb’);
locktype | database | relation | page | tuple | virtualxid | transactionid | classid | objid | objsubid | virtualtransaction | pid | mode | granted
———-+———-+———-+——+——-+————+—————+———+——-+———-+——————–+——-+———————+———
relation | 16384 | 16385 | | | | | | | | 3/12345 | 12345 | AccessShareLock | t
virtualxid| | | | | 3/12345 | | | | | 3/12345 | 12345 | ExclusiveLock | t
(2 rows)
# 查看阻塞会话
fgedudb=> SELECT
fgedudb-> blocked_locks.pid AS blocked_pid,
fgedudb-> blocked_activity.usename AS blocked_user,
fgedudb-> blocking_locks.pid AS blocking_pid,
fgedudb-> blocking_activity.usename AS blocking_user,
fgedudb-> blocked_activity.query AS blocked_statement
fgedudb-> FROM pg_catalog.pg_locks blocked_locks
fgedudb-> JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid
fgedudb-> JOIN pg_catalog.pg_locks blocking_locks ON blocking_locks.locktype = blocked_locks.locktype
fgedudb-> AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
fgedudb-> AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
fgedudb-> AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
fgedudb-> AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
fgedudb-> AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
fgedudb-> AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
fgedudb-> AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
fgedudb-> AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
fgedudb-> AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
fgedudb-> AND blocking_locks.pid != blocked_locks.pid
fgedudb-> JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
fgedudb-> WHERE NOT blocked_locks.GRANTED;
blocked_pid | blocked_user | blocking_pid | blocking_user | blocked_statement
————-+————–+————–+—————+——————-
(0 rows)
from GreenPlum视频:www.itpux.com
Part04-生产案例与实战讲解
4.1 GreenPlum死锁处理案例
4.1.1 死锁场景模拟
# 会话1:
fgedudb=> BEGIN;
BEGIN
fgedudb=> UPDATE fgedu.fgedu_account SET balance = balance – 100 WHERE account_id = 1;
UPDATE 1
# 会话2:
fgedudb=> BEGIN;
BEGIN
fgedudb=> UPDATE fgedu.fgedu_account SET balance = balance – 100 WHERE account_id = 2;
UPDATE 1
# 会话1继续:
fgedudb=> UPDATE fgedu.fgedu_account SET balance = balance + 100 WHERE account_id = 2;
— 等待会话2释放锁…
# 会话2继续:
fgedudb=> UPDATE fgedu.fgedu_account SET balance = balance + 100 WHERE account_id = 1;
ERROR: deadlock detected
DETAIL: Process 12345 waits for ShareLock on transaction 67890; blocked by process 12346.
HINT: See server log for query details.
CONTEXT: while updating tuple (0,1) in relation “fgedu_account”
# 会话1自动回滚:
fgedudb=> ROLLBACK;
ROLLBACK
# 解决方法:
# 1. 按相同顺序访问表
# 2. 减少事务持有锁的时间
# 3. 使用较低的隔离级别
Part05-风哥经验总结与分享
5.1 GreenPlum并发控制技巧
1. 事务设计原则
– 事务要短小
– 避免长事务
– 及时提交
– 合理使用保存点
2. 锁优化建议
– 减少锁持有时间
– 避免锁升级
– 使用合适的隔离级别
– 监控锁等待
3. 死锁预防
– 按相同顺序访问资源
– 减少事务大小
– 避免用户交互
– 设置锁超时
4. 监控与诊断
– 监控长事务
– 监控锁等待
– 分析死锁日志
– 定期清理死锁
5. 参数调优
– deadlock_timeout
– lock_timeout
– idle_in_transaction_session_timeout
– max_locks_per_transaction
本文档介绍了GreenPlum事务与并发控制的核心内容,包括事务操作、锁机制、死锁处理等,希望对大家有所帮助。
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
