ITPub博客

首页 > Linux操作系统 > Linux操作系统 > TRUNCATE in postgresql

TRUNCATE in postgresql

原创 Linux操作系统 作者:babyyellow 时间:2012-06-08 14:08:31 0 删除 编辑
在我们的印象里,truncate 命令是 ddl 是没有事务的。
在mysql 跟oracle 里是这样的。

在pg 里truncate 是事务安全的,也就是是说是可以回滚的。

[code]
cyp_app=>     begin;
BEGIN
Time: 0.130 ms
cyp_app=> select count(*) from tmp_lsl;
 count
-------
   140
(1 row)

Time: 0.358 ms
cyp_app=> truncate table tmp_lsl ;
TRUNCATE TABLE
Time: 0.371 ms
cyp_app=> select count(*) from tmp_lsl;
 count
-------
     0
(1 row)

Time: 0.274 ms
cyp_app=> rollback;
ROLLBACK
Time: 91.841 ms
cyp_app=> select count(*) from tmp_lsl;
 count
-------
   140
(1 row)

Time: 0.401 ms
[/code]

这个功能得益于PG的mvcc 的实现。

但是truncate 操作不是MVCC-safe的。
什么意思呢?

我们看看先:
session A :
[code]
cyp_app=> begin;
BEGIN
Time: 0.122 ms
cyp_app=> select count(*) from tmp_lsl;
 count
-------
   140
(1 row)

Time: 0.282 ms
[/code]

session B :
[code]
BEGIN
cyp_app=> select count(*) from tmp_lsl ;
 count
-------
   140
(1 row)

[/code]

session A :  继续执行:
[code]
cyp_app=> truncate table tmp_lsl;
              
这个时候操作已经被挂起了,
[/code]

session B:

[code]
继续下一步操作

cyp_app=> select count(*) from tmp_lsl ;
 count
-------
   140
(1 row)

cyp_app=> delete from tmp_lsl;
DELETE 140
cyp_app=>

cyp_app=> rollback;
ROLLBACK

session B 可以执行删除。
[/code]

session A
 [code]
这个是sessiona 的truncate 返回了

cyp_app=> truncate table tmp_lsl;
                TRUNCATE TABLE
Time: 4953153.416 ms
cyp_app=>          
cyp_app=>                 rollback;
ROLLBACK
Time: 92.143 ms
cyp_app=>
[/code]

在看另一个
sessionA: 
[code]
cyp_app=> begin;
BEGIN
Time: 0.123 ms
cyp_app=> select count(*) from tmp_Lsl;
 count
-------
   140
(1 row)

Time: 0.377 ms
cyp_app=> truncate table tmp_lsl;
TRUNCATE TABLE
Time: 0.331 ms
cyp_app=>
表已经被truncate 了但是没有提交。
[/code]

开启session B
[code]
cyp_app=> begin;
BEGIN
cyp_app=> select count(*) from tmp_lsl;

sessionB  被挂起了,无法查询到结果:
[/code]

session  A 继续:
[code]
cyp_app=> commit;
COMMIT
Time: 92.136 ms
cyp_app=>
session A  提交数据库修改:
[/code]

sessionB :
[code]
cyp_app=> select count(*) from tmp_lsl;
 count
-------
     0
(1 row)

cyp_app=> commit;
COMMIT
cyp_app=>

sesssion B 返回了0行,session b 看到的是session A 执行完成后的数据快照。
[/code]

什么意思呢?  根据我们设置的readcommited 的事务隔离级别,sessionB 看到sessionA 提交的结果是对的。

主要的问题是truncate 不是mvcc-safe 的,就是truncate 的操作发生后,对所有的事务都返回一个空的结果集,不论这个事务是否在truncate 操作发生前还是发生后。

对于前面的那个,session b 不提交,则session a 的truncate 被挂起,则是因为session b 只有的access share 共享锁,阻止了truncate clusive 锁的获得。

truncate  不会带来任何数据一致性的问题。

因为这个原因,我们在在pg 同步oracle 的表的时候,本想直接在一个事务里truncate table  然后再insert 的做法,似乎就会有些行不通。

这回导致与阻止其他事务,或者被其他事务阻止,而insert 是全表数据,如果数据量比较大,阻塞其他事务的机会应该更大一些。 

比较靠谱的操作是用 a  b 表轮换的方式。


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/133735/viewspace-732292/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
oracle MySQL Postgresql 专职数据库dba。 系统架构师。 mysql 官方认知dba 。 15年专职dba 经验。

注册时间:2010-12-02

  • 博文量
    232
  • 访问量
    1418437