TRUNCATE in postgresql

babyyellow發表於2012-06-08
在我們的印象裡,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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章