执行ALTER TABLE语句时如何避免长时间阻塞并发查询

简介: 执行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 tablealter 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再执行selecthang住。

      那么,是否存在这样的语句,执行添加列时不申请长时间锁表的锁?pg_reorg/pg_repack

      首先设置事务超时时间,然后执行alter table语句:


      =$ 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

      超时时间保证alter table语句执行不超过50毫秒,然后通过psql执行:

        =$ 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

        语句执行很快失败,但是返回结果是0,标记成功了,我们需要修改下:

          =$ time printf "SET statement_timeout = 50;\nALTER TABLE test add column whatever2 INT4;\n" | psql -qX -v ON_ERROR_STOP=1ERROR:  canceling statement due to statement timeout real    0m0.054suser    0m0.002ssys     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/

            目录
            相关文章
            |
            4月前
            |
            人工智能 中间件 专有云
            12月20日|「Qoder Together 上海站」圆满落幕!
            2025年12月20日,「Qoder Together 上海站」在阿里中心圆满落幕。三位技术专家从实战出发,深入解析Qoder高效编程、CLI终端集成与Agentic Coding避坑指南,现场互动热烈。活动展现AI赋能开发的无限可能,传递“人机协同”新理念。下一站,继续同行,共赴智能编码未来。
            306 1
            |
            10月前
            |
            人工智能 运维 关系型数据库
            数据库运维:mysql 数据库迁移方法-mysqldump
            本文介绍了MySQL数据库迁移的方法与技巧,重点探讨了数据量大小对迁移方式的影响。对于10GB以下的小型数据库,推荐使用mysqldump进行逻辑导出和source导入;10GB以上可考虑mydumper与myloader工具;100GB以上则建议物理迁移。文中还提供了统计数据库及表空间大小的SQL语句,并讲解了如何使用mysqldump导出存储过程、函数和数据结构。通过结合实际应用场景选择合适的工具与方法,可实现高效的数据迁移。
            1567 1
            |
            算法 Unix Linux
            7z——拥有极高压缩比的开源压缩软件
            【11月更文挑战第6天】7z 是一种开源压缩软件,具有高压缩比、开源特性、功能丰富、跨平台支持和良好兼容性等特点。它采用先进的压缩算法,支持大文件、加密和多种压缩格式,广泛应用于个人和企业文件管理。
            1833 3
            |
            关系型数据库 MySQL
            Mysql 主键冲突(ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY')
            Mysql 主键冲突(ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY')
            2283 0
            |
            Java Maven
            Maven 引入外部依赖
            如果我们需要引入第三方库文件到项目,该怎么操作呢?
            315 5
            |
            Android开发
            Android Uri转File方法(适配android 10以上版本及android 10以下版本)
            Android Uri转File方法(适配android 10以上版本及android 10以下版本)
            1212 0
            |
            机器学习/深度学习 人工智能 自然语言处理
            【人工智能】学习人工智能需要学习哪些课程,从入门到进阶到高级课程区分
            基于人工智能的多学科特性和其广泛的应用领域,学习这一技术涉及从基础理论到实践应用的各个层面。入门阶段应重点掌握数学基础、编程语言学习以及数据结构和算法等。进阶阶段需要深入机器学习、深度学习以及自然语言处理等专题。高级课程则包括专业核心课程、认知心理学与神经科学基础以及计算机图形学等课程
            1415 1
            |
            机器学习/深度学习 算法 IDE
            一行代码加速sklearn运算上千倍
            一行代码加速sklearn运算上千倍
            430 0
            |
            Android开发 iOS开发 C#
            Xamarin:用C#打造跨平台移动应用的终极利器——从零开始构建你的第一个iOS与Android通用App,体验前所未有的高效与便捷开发之旅
            【8月更文挑战第31天】Xamarin 是一个强大的框架,允许开发者使用单一的 C# 代码库构建高性能的原生移动应用,支持 iOS、Android 和 Windows 平台。作为微软的一部分,Xamarin 充分利用了 .NET 框架的强大功能,提供了丰富的 API 和工具集,简化了跨平台移动应用开发。本文通过一个简单的示例应用介绍了如何使用 Xamarin.Forms 快速创建跨平台应用,包括设置开发环境、定义用户界面和实现按钮点击事件处理逻辑。这个示例展示了 Xamarin.Forms 的基本功能,帮助开发者提高开发效率并实现一致的用户体验。
            621 0

            热门文章

            最新文章

            下一篇
            开通oss服务