执行ALTER TABLE语句时如何避免长时间阻塞并发查询
最近看到这样的案例:
1、应用需要为现有的表添加列
2、应用执行ALTER TABLE ADD COLUMN语句
3、其他每个查询都需要被阻塞几分钟甚至更长时间
为什么出现这种情况?如果避免?
首先看下执行ALTER TABLE ADD COLUMN时发生了什么?
# ALTER TABLE test ADD COLUMN whatever int4;
ALTER TABLE
TIME: 12.662 ms
可以看到该语句执行的非常快,在看下alter table获取的锁:
=# BEGIN;
BEGIN
=# ALTER TABLE test ADD COLUMN whatever2 int4;
ALTER TABLE
=# SELECT * FROM pg_locks WHERE pid = pg_backend_pid();
locktype | DATABASE | relation | page | tuple | virtualxid | transactionid | classid | objid | objsubid | virtualtransaction | pid | mode | GRANTED | fastpath
---------------+----------+----------+------+-------+------------+---------------+---------+-------+----------+--------------------+-------+---------------------+---------+----------
relation | 165725 | 12143 | | | | | | | | 3/2594 | 32470 | AccessShareLock | t | t
virtualxid | | | | | 3/2594 | | | | | 3/2594 | 32470 | ExclusiveLock | t | t
transactionid | | | | | | 1422 | | | | 3/2594 | 32470 | ExclusiveLock | t | f
relation | 165725 | 166142 | | | | | | | | 3/2594 | 32470 | AccessExclusiveLock | t | f
(4 ROWS)
=# ROLLBACK;
ROLLBACK
需要注意,有一个AccessExclusiveLock,直到事务提交或者回滚才能释放,此间会锁表。
但是alter table add column只花费12ms,哪来的几分钟?这种事情发生在有其他查询在这个表上,然后在执行alter table,alter table需要等待之前的锁释放:
(SESSION 1) =# BEGIN;
BEGIN
(SESSION 1) =# SELECT COUNT(*) FROM test;
COUNT
-------
0
(1 ROW)
会话1不关闭,同时不用关闭事务。
(SESSION 2) =# ALTER TABLE test ADD COLUMN whatever2 int4;
会话2执行alter 语句时由于需要等待会话1释放锁被阻塞,但是他已经获取这个表上的AccessExclusiveLock了,其他select不能执行了。
(SESSION 3) =# depesz=# SELECT * FROM test LIMIT 1;
会话3再执行select被hang住。
那么,是否存在这样的语句,执行添加列时不申请长时间锁表的锁?pg_reorg/pg_repack。
首先设置事务超时时间,然后执行alter table语句:
=$ printf "SET statement_timeout = 50;nALTER TABLE test add column whatever2 INT4;n"
SET statement_timeout = 50;
ALTER TABLE test add column whatever2 INT4;
超时时间保证alter table语句执行不超过50毫秒,然后通过psql执行:
=$ time printf "SET statement_timeout = 50;nALTER TABLE test add column whatever2 INT4;n" | psql -qX
ERROR: canceling statement due to statement timeout
real 0m0.054s
user 0m0.000s
sys 0m0.002s
=$ echo $?
0
语句执行很快失败,但是返回结果是0,标记成功了,我们需要修改下:
=$ time printf "SET statement_timeout = 50;nALTER TABLE test add column whatever2 INT4;n" | psql -qX -v ON_ERROR_STOP=1
ERROR: canceling statement due to statement timeout
real 0m0.054s
user 0m0.002s
sys 0m0.000s
=$ echo $?
3
这样就合理了:
=$ printf "SET statement_timeout = 50;nALTER TABLE test add column whatever2 INT4;n" > alter.sql
然后:
=$ while true; do date; psql -qX -v ON_ERROR_STOP=1 -f alter.sql && break; sleep 1; done
Thu 26 Sep 2019 03:43:52 PM CEST
psql:alter.sql:2: ERROR: canceling statement due to statement timeout
Thu 26 Sep 2019 03:43:53 PM CEST
psql:alter.sql:2: ERROR: canceling statement due to statement timeout
Thu 26 Sep 2019 03:43:54 PM CEST
psql:alter.sql:2: ERROR: canceling statement due to statement timeout
Thu 26 Sep 2019 03:43:55 PM CEST
psql:alter.sql:2: ERROR: canceling statement due to statement timeout
Thu 26 Sep 2019 03:43:56 PM CEST
=$
While循环:
while true
do
date
psql -qX -v ON_ERROR_STOP=1 -f alter.sql && break
sleep 1
done
可以看到开始时间和结束时间。
需要注意,如果想对这个表进行更多操作,需要使用事务:
BEGIN;
SET statement_timeout = 50;
LOCK TABLE ONLY test IN ACCESS EXCLUSIVE MODE;
SET statement_timeout = 0;
ALTER TABLE test ....;
-- do whatever you want, timeout is removed.
commit;
但是需要注意,一旦获取了这个锁,其他链接就不能使用这个表了。
原文:
https://www.depesz.com/2019/09/26/how-to-run-short-alter-table-without-long-locking-concurrent-queries/
- Facebook开源游戏平台ELF:一个用于实时战略游戏研究的轻量级平台
- 用不到50行的Python代码构建最小的区块链
- 学习笔记CB002:词干提取、词性标注、中文切词、文档分类
- 深入浅出 Retrofit,这么牛逼的框架你们还不来看看?
- 用Python从零开始构建反向传播算法
- 备战CDA数据分析竞赛!Kaggle赛题大揭秘
- 如何用Python将时间序列转换为监督学习问题
- Spring MVC的配置和使用
- Java可以如何实现文件变动的监听
- 借助GitHub搭建属于自己的maven仓库
- 如何使用 scikit-learn 为机器学习准备文本数据
- Hyperledger Fabric Chaincode 开发
- 使用VS Code开发asp.net core
- 以太坊·将自定义数据写入到区块链中
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- R语言线性模型臭氧预测: 加权泊松回归,普通最小二乘,加权负二项式模型
- R语言中回归和分类模型选择的性能指标
- R语言 线性混合效应模型实战案例
- R语言中敏感性和特异性、召回率和精确度作为选型标准的华夫图案例
- R语言中的多类别问题的绩效衡量:F1-score 和广义AUC
- Dart语言基础Map、List、Set操作合辑
- 2.2.2 类反射场景与使用 -《SSM深入解析与项目实战》
- 每天手撕一道算法-64. 最小路径和
- Flutter 1.20 下的 Hybrid Composition 深度解析
- Flutter 1.17 对列表图片的优化解析
- SQL注入常用函数和关键字总结
- 用遗传算法求解函数
- javafx框架tornadofx实战-益智游戏-找出指定的内容1
- Qt音视频开发8-ffmpeg保存裸流
- PyTorch6:nn.Linear&常用激活函数