【问题标题】:Limits on PostgreSQL schema changes inside transactions?事务内 PostgreSQL 模式更改的限制?
【发布时间】:2010-11-09 16:10:28
【问题描述】:

我的数据库背景是 Oracle,所以我惊讶地发现 Postgres 在事务中包含模式更改 - 如果您开始一个,创建一个表然后回滚,该表就会消失。它也适用于添加和删除列。显然这是非常好的。

我们即将对部署依赖此功能的架构增量的方式进行一些更改。在此之前,我想了解交易保证的延伸范围,但我在文档中找不到任何相关信息。我假设我只是使用了错误的搜索词——我的搜索只是转到包含“事务”、“创建”和“表”等词的大命令列表。

谁能给我一些关于 Postgres 中事务模式更改的文档或讨论的指针? (我们使用的是 8.2.13,尽管我们将在不久的将来升级。)或者只是一些关于不会包含在事务中的语句的详细信息?

【问题讨论】:

  • 是的 - 该功能对于编写升级脚本非常有用。
  • 嘎——这些都是很好的答案。最后,决定因素是 grep 希望是一个更详尽的列表。 (虽然它没有提到 REINDEX。)谢谢。
  • depesz 为 postgresql 社区做出了巨大贡献,例如通过他的博客。如果你问我 - 他应该得到很高的声誉分数!
  • SQL Server 还可以从同一事务中回滚 DDL 和数据更改。但是每条 DDL 语句必须在批处理中首先出现(由 GO 分隔)。 DDL 没有与其他事务正确隔离,例如在 postgres 中,但重要的是在发生错误时完全回滚。

标签: postgresql transactions schema ddl


【解决方案1】:

来自手册,section 13.5(货币控制:注意事项):

一些 DDL 命令,目前只有 TRUNCATE 和 table-rewriting ALTER TABLE 的形式不是 MVCC 安全的。这意味着,在 截断或重写提交,表将显示为空 并发事务,如果它们使用的是在 DDL 命令已提交。这只是交易的问题 在 DDL 命令之前没有访问有问题的表 开始 […]

关于表重写ALTER TABLE部分提到

使用 DEFAULT 子句添加列或更改类型 现有列将要求整个表 [...] 重写。作为更改现有类型的例外 列,如果 USING 子句不更改列内容并且 旧类型要么是二进制可强制转换为新类型,要么是 在新类型上不受约束的域,不需要表重写 […] 或删除系统 oid 列也需要重写整个 表。

【讨论】:

    【解决方案2】:

    同时运行“CREATE TABLE”的两个会话有点不雅:

    http://postgresql.1045698.n5.nabble.com/Errors-on-CREATE-TABLE-IF-NOT-EXISTS-td5659080.html

    CREATE TABLE 进行初步检查以查看名称是否冲突 存在。如果是这样,它要么出错(通常),要么退出并发出通知 (在 IF NOT EXISTS 的情况下)。但是有一个竞争条件:a 在我们进行检查后,冲突的事务可以创建表 在我们自己创建它之前。

    链接的线程发起者和我都在自动化测试环境中遇到了这个问题, 所以这只不过是那里的烦恼。 (我怀疑它会影响您的架构迁移,但它可以被视为对 ddl 更改的限制)

    perl -MDBI -E 'fork; fork; $d=DBI->connect("dbi:Pg:dbname=$ENV{USER}");' \
     $d->do("CREATE TABLE a (b int)")'
    DBD::Pg::db do failed: ERROR:
       duplicate key value violates unique constraint "pg_type_typname_nsp_index"
    DETAIL:  Key (typname, typnamespace)=(a, 2200) already exists. at -e line 1.
    

    【讨论】:

      【解决方案3】:

      从 PosgreSQL 9.1 版开始,模式创建语句似乎确实是事务性的。

      select * from pg_namespace where nspname = 'foo';
       nspname | nspowner | nspacl 
      ---------+----------+--------
      (0 rows)
      
      begin;
      create schema foo;
      rollback;
      
      select * from pg_namespace where nspname = 'foo';
       nspname | nspowner | nspacl 
      ---------+----------+--------
      (0 rows)
      
      begin;
      create schema foo;
      commit;
      
      select * from pg_namespace where nspname = 'foo';
       nspname | nspowner | nspacl 
      ---------+----------+--------
       foo     |       10 | NULL
      (1 row)
      

      【讨论】:

      • 这种情况已经很多年了,没什么新意,也和9.1版本无关
      • 感谢您就 postgresql 版本澄清这一点。
      • 在 PostgreSQL 8.4(来自 RHEL6 的版本)中测试。它有效! :-) 谢谢。
      【解决方案4】:
      • 序列上的nextvalsetval 操作永远不会回滚。
      • REINDEX DATABASE
      • REINDEX SYSTEM

      有一个article about transactional DDL on the PostgreSQL Wiki

      【讨论】:

        【解决方案5】:

        根据 quick grep on docs,这些命令不能在事务中执行:

        • 集群
        • 准备提交
        • 创建数据库
        • 创建表空间
        • 丢弃
        • 删除数据库
        • 删除表空间
        • 准备回滚
        • 真空

        【讨论】:

        • 确定:grep '不能在事务中执行' sql-*html
        • 谢谢。重新索引文档在这些单词之间有更多空白。
        • CLUSTER 可以在事务块内运行,只要您指定要 CLUSTER 的表。
        猜你喜欢
        • 2010-12-11
        • 1970-01-01
        • 1970-01-01
        • 2021-02-04
        • 1970-01-01
        • 2016-05-25
        • 1970-01-01
        • 1970-01-01
        • 2015-03-26
        相关资源
        最近更新 更多