执行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/

            目录
            相关文章
            |
            6月前
            |
            人工智能 运维 关系型数据库
            数据库运维:mysql 数据库迁移方法-mysqldump
            本文介绍了MySQL数据库迁移的方法与技巧,重点探讨了数据量大小对迁移方式的影响。对于10GB以下的小型数据库,推荐使用mysqldump进行逻辑导出和source导入;10GB以上可考虑mydumper与myloader工具;100GB以上则建议物理迁移。文中还提供了统计数据库及表空间大小的SQL语句,并讲解了如何使用mysqldump导出存储过程、函数和数据结构。通过结合实际应用场景选择合适的工具与方法,可实现高效的数据迁移。
            1116 1
            |
            存储 监控 Java
            Java日志通关(三) - Slf4j 介绍
            作者日常在与其他同学合作时,经常发现不合理的日志配置以及五花八门的日志记录方式,后续作者打算在团队内做一次Java日志的分享,本文是整理出的系列文章第三篇。
            |
            SQL 人工智能 Java
            mybatis-plus配置sql拦截器实现完整sql打印
            _shigen_ 博主分享了如何在MyBatis-Plus中打印完整SQL,包括更新和查询操作。默认日志打印的SQL用?代替参数,但通过自定义`SqlInterceptor`可以显示详细信息。代码示例展示了拦截器如何替换?以显示实际参数,并计算执行时间。配置中添加拦截器以启用此功能。文章提到了分页查询时的限制,以及对AI在编程辅助方面的思考。
            2300 5
            mybatis-plus配置sql拦截器实现完整sql打印
            |
            XML JSON Java
            springboot文件上传,单文件上传和多文件上传,以及数据遍历和回显
            本文介绍了在Spring Boot中如何实现文件上传,包括单文件和多文件上传的实现,文件上传的表单页面创建,接收上传文件的Controller层代码编写,以及上传成功后如何在页面上遍历并显示上传的文件。同时,还涉及了`MultipartFile`类的使用和`@RequestPart`注解,以及在`application.properties`中配置文件上传的相关参数。
            springboot文件上传,单文件上传和多文件上传,以及数据遍历和回显
            |
            负载均衡 Java Nacos
            Nacos服务注册与发现
            【10月更文挑战第11天】Nacos 是一个开源平台,用于服务发现和配置管理,提供服务注册、发现及动态配置等功能,适用于微服务架构。其核心功能包括服务注册、服务发现和动态配置管理,支持多种语言如 Java、Go、Python 等,具备高可用性和易用性。Nacos 可用于微服务治理、动态扩展和跨语言服务调用等场景,简化了服务间的交互和管理。
            517 10
            |
            SQL 关系型数据库 MySQL
            一文速学-玩转MySQL中INTERVAL关键字和INTERVAL()函数用法讲解
            一文速学-玩转MySQL中INTERVAL关键字和INTERVAL()函数用法讲解
            1253 0
            一文速学-玩转MySQL中INTERVAL关键字和INTERVAL()函数用法讲解
            |
            监控 安全 数据挖掘
            企业异地组网一般选用什么方案比较好?
            企业异地组网可选用SD-WAN,它提供灵活、低成本且快速的解决方案。除此之外,还有光纤互联(费用高昂,不适合中小企业)和MPLS VPN(费用高,组网复杂)。SD-WAN能精准划分流量、支持多种接入方式、保障稳定性、简化部署并实现全局监控,是企业广域网建设的理想选择。
            463 2
            |
            存储 SQL
            离线数仓(九)【DWS 层开发】(1)
            离线数仓(九)【DWS 层开发】
            |
            Android开发
            Android Uri转File方法(适配android 10以上版本及android 10以下版本)
            Android Uri转File方法(适配android 10以上版本及android 10以下版本)
            1103 0