數據庫併發事務控制四:postgresql數據庫的鎖機制二:表鎖


在博文《數據庫併發事務控制四:postgresql數據庫的鎖機制 》
http://blog.csdn.net/beiigang/article/details/43302947
中後面提到:


常規鎖機制可以參考pg的官方手冊,章節和內容見下面
13.3. Explicit Locking
http://www.postgresql.org/docs/9.4/static/explicit-locking.html
這節分爲:表鎖、行鎖、頁鎖、死鎖、Advisory鎖(這個名字怎麼翻譯好??? 忠告鎖,公告鎖,諮詢鎖???)。

後面的內容提綱就是:
表鎖、
行鎖、
頁鎖、
死鎖、
Advisory鎖(這個名字怎麼翻譯好??? 忠告鎖,公告鎖,諮詢鎖???)、
查看鎖。


感覺有些累了,懶了,不想寫了,後面看情況到網上找些同仁同志同學朋友們的文章,放到這兒歸類,如有需要待下次按我的思路再整理組織,今次先把題目做完整吧。


這兒繼續,下面的內容轉自下面,只是小改了幾處手誤的地方,把第三節的圖換成了官網上的

http://francs3.blog.163.com/blog/static/40576727201082134343604/

原文標題:Postgresql 鎖淺析


一、概述
此文檔主要對Postgresql 鎖機制進行分析,在講解的過程中結合實驗,理解Postgresql的鎖機制。

二、表級鎖類型
表級鎖類型分爲八種,以下對各種表級鎖類型進行簡單介紹下, 鎖的衝突模式可以參考3.1的圖一:表級鎖衝突模式。

2.1 ACCESS SHARE
“ACCESS SHARE”鎖模式只與“ACCESS EXCLUSIVE” 鎖模式衝突;
查詢命令(Select command)將會在它查詢的表上獲取”Access Shared” 鎖,一般地,任何一個對錶上的只讀查詢操作都將獲取這種類型的鎖。

2.2 ROW SHARE
 “Row Share” 鎖模式與”Exclusive’和”Access Exclusive”鎖模式衝突;
”Select for update”和”Select for share”命令將獲得這種類型鎖,並且所有被引用但沒有 FOR UPDATE 的表上會加上”Access shared locks”鎖。

2.3 ROW EXCLUSIVE
 “Row exclusive” 與 “Share,Shared roexclusive,Exclusive,Access exclusive”模式衝突;
“Update,Delete,Insert”命令會在目標表上獲得這種類型的鎖,並且在其它被引用的表上加上”Access shared”鎖,一般地,更改表數據的命令都將在這張表上獲得”Row exclusive”鎖。

2.4 SHARE UPDATE EXCLUSIVE
”Share update exclusive,Share,Share row ,exclusive,exclusive,Access exclusive”模式衝突,這種模式保護一張表不被併發的模式更改和VACUUM;
 “Vacuum(without full), Analyze ”和 “Create index concurrently”命令會獲得這種類型鎖。

2.5 SHARE
與“Row exclusive,Shared update exclusive,Share row exclusive ,Exclusive,Access exclusive”鎖模式衝突,這種模式保護一張表數據不被併發的更改;
“Create index”命令會獲得這種鎖模式。

2.6 SHARE ROW EXCLUSIVE
與“Row exclusive,Share update exclusive,Shared,Shared row exclusive,Exclusive,Access Exclusive”鎖模式衝突;
任何Postgresql 命令不會自動獲得這種鎖。

2.7 EXCLUSIVE
與” ROW SHARE, ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE, ACCESS EXCLUSIVE”模式衝突,這種索模式僅能與Access Share 模式併發,換句話說,只有讀操作可以和持有”EXCLUSIVE”鎖的事務並行;
任何Postgresql 命令不會自動獲得這種類型的鎖;

2.8 ACCESS EXCLUSIVE
與所有模式鎖衝突(ACCESS SHARE, ROW SHARE, ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE, and ACCESS EXCLUSIVE),這種模式保證了當前只有一個事務訪問這張表;
“ALTER TABLE, DROP TABLE, TRUNCATE, REINDEX, CLUSTER, VACUUM FULL” 命令會獲得這種類型鎖,在Lock table 命令中,如果沒有申明其它模式,它也是缺省模式。

三、表級鎖衝突模式
3.1  Conflicting lock modes

Table 13-2. Conflicting Lock Modes

Requested Lock Mode Current Lock Mode ACCESS SHARE ROW SHARE ROW EXCLUSIVE SHARE UPDATE EXCLUSIVE SHARE SHARE ROW EXCLUSIVE EXCLUSIVE ACCESS EXCLUSIVE ACCESS SHARE






X ROW SHARE





X X ROW EXCLUSIVE



X X X X SHARE UPDATE EXCLUSIVE


X X X X X SHARE

X X
X X X SHARE ROW EXCLUSIVE

X X X X X X EXCLUSIVE
X X X X X X X ACCESS EXCLUSIVE X X X X X X X X

備註: 上圖是pg 表級鎖的各種衝突模式對照表,‘X’表示衝突項, 在章節四中會對其中典型的鎖模式進行模似演示。

四、實驗
在這一章節中將會對圖一中比較典型的鎖衝突進行模似演練,瞭解這些在Postgresql DBA的日常維護工作中很有幫助,同時也能減少人爲故障的發生。

4.1  Access exclusive 鎖與Access share鎖衝突
       在日常維護中,大家應該執行過’ALTER TABLE’更改表結構的DDL,例如加字段,更改字段數據類型等,根據章節二的理論,在執行’ALTER TABLE’命令時將申請一個Access exclusive鎖, 根據圖一,大家知道Access exclusive 鎖和所有的鎖模式都衝突,那麼,它將會’Select’命令衝突,因爲Select 加的是Access share鎖,那麼真的會與‘SELECT‘命令衝突嗎,接下來給大家演示下:

--創建一張測試表 test_2 並插入測試數據
mydb=> create table test_2 (id integer,name varchar(32));
CREATE TABLE
mydb=> insert into test_2 values (1,'franc');
INSERT 0 1
mydb=> insert into test_2 values (2,'tan');
INSERT 0 1
mydb=> select * from test_2;
 id | name
----+-------
  1 | franc
  2 | tan
(2 rows)

--會話一 查詢表數據 ( 這裏獲得Access Shared 鎖)
mydb=> begin;
BEGIN
mydb=> select * from test_2 where id=1;
 id | name
----+-------
  1 | franc
(1 row)
注意:這裏begin開始事務,沒有提交;

--會話二 更改表結構 (這裏申請 Access Exclusive鎖 )
mydb=> alter table test_2 add column sex char(1);
發現,命令一直等侍,執行不下去;

--會話三 查詢狀態
mydb=# select oid,relname from pg_class where relname='test_2';
  oid  | relname
-------+---------
 33802 | test_2
mydb=# select locktype,database,relation,pid,mode from pg_locks where relation='33802';
 locktype | database | relation |  pid  |        mode        
----------+----------+----------+-------+---------------------
 relation |    16466 |    33802 | 18577 | AccessShareLock
 relation |    16466 |    33802 | 18654 | AccessExclusiveLock
mydb=# select datname,procpid,usename,current_query from pg_stat_activity where procpid in (18577,18654);
 datname | procpid | usename |               current_query               
---------+---------+---------+--------------------------------------------
 mydb    |   18577 | skytf   | <IDLE> in transaction
 mydb    |   18654 | skytf   | alter table test_2 add column sex char(1);
(2 rows)
     這裏可以看出會話一(pid=18577) 獲取的是 “AccessShareLock”鎖,
會話二(pid=18654 ) 獲取的是 “AccessExclusiveLock”鎖。

--再次回到會話一,執行'end'結束事務後會發生什麼結果
注意,此時會話二還處於等侍狀態
mydb=> end;
COMMIT

--回到會話二發現 原來處於等侍狀態的'ALTER TABLE'命令執行成功
mydb=> alter table test_2 add column sex char(1);
ALTER TABLE
mydb=> \d test_2
            Table "skytf.test_2"
 Column |         Type          | Modifiers
--------+-----------------------+-----------
 id     | integer               |
 name   | character varying(32) |
 sex    | character(1)          |

--回到會話三,鎖已經釋放
mydb=# select locktype,database,relation,pid,mode from pg_locks where relation='33802';
 locktype | database | relation | pid | mode
----------+----------+----------+-----+------
(0 rows)
mydb=# select datname,procpid,usename,client_addr,current_query from pg_stat_activity where procpid in (18577,18654);
 datname | procpid | usename | client_addr | current_query
---------+---------+---------+-------------+---------------
 mydb    |   18577 | skytf   |             | <IDLE>
 mydb    |   18654 | skytf   |             | <IDLE>
(2 rows)
實驗說明: 這個實驗說明了 'ALTER TABLE'命令與'SELECT'命令會產生衝突,證實了開始的結論,即"Access exclusive"鎖模式與申請"Access shared"鎖模式的'SELECT'命令相沖突。

4.2  Share 鎖與 Row Exclusive 鎖衝突
在數據庫的維護過程中,創建索引也是經常做的工作,別小看創建索引,如果是一個很繁忙的系統,索引不一定能創建得上,可能會發生等侍, 嚴重時造成系統故障;根據章節二的理論,’Create Index’ 命令需要獲取Share 鎖模式。
根據圖一,”Share” 鎖和”Row Exclusive”鎖衝突,下面來驗證一下:
根據圖一可以看出,share鎖模式和多種鎖模式衝突,有可能會問我,爲什麼單獨講share鎖和Row Exclusive衝突呢?因爲” Update,Delete,Insert”命令獲取的是Row Exclusive 操作,而這種操作在生產過程中非常頻繁;這個實驗正是模似生產維護過程。
 
--會話一, 向 test_2 上插入一條數據
mydb=> select * from test_2;
 id | name  | sex
----+-------+-----
  1 | franc |
  2 | tan   |
(2 rows)
mydb=> begin;
BEGIN
mydb=> insert into test_2 values (3,'fpzhou');
INSERT 0 1
mydb=>
說明: 這個Insert 操作放在一個事務裏,注意此時事務尚未提交。

--會話二,在表test_2上創建索引
mydb=> \d test_2;
            Table "skytf.test_2"
 Column |         Type          | Modifiers
--------+-----------------------+-----------
 id     | integer               |
 name   | character varying(32) |
 sex    | character(1)          |
mydb=> create unique index idx_test_2_id  on test_2 (id);
說明: 創建索引命令發生等侍

--會話三,查詢狀態
mydb=# select locktype,database,relation,pid,mode from pg_locks where relation='33802';
 locktype | database | relation |  pid  |       mode      
----------+----------+----------+-------+------------------
 relation |    16466 |    33802 | 18577 | RowExclusiveLock
 relation |    16466 |    33802 | 18654 | ShareLock
(2 rows)
mydb=# select datname,procpid,usename,client_addr,current_query from pg_stat_activity where procpid in (18577,18654);
 datname | procpid | usename | client_addr |                   current_query                   
---------+---------+---------+-------------+----------------------------------------------------
 mydb    |   18577 | skytf   |             | <IDLE> in transaction
 mydb    |   18654 | skytf   |             | create unique index idx_test_2_id  on test_2 (id);
 說明:  這裏可以看出"Insert into"(procpid=18577) 命令獲取"RowExclusiveLock”,而"Create Index"(procpid=18654)操作獲取的是"Sharelock", 並且創建索引操作發了等侍,因爲這兩種鎖模式是衝突的。

--回到會話一,提交事務,看看會發生什麼
注意,此時創建索引的會話二仍處於等侍狀態
mydb=> end;
COMMIT

--回到會話二,發現創建索引命令成功,等侍消失
mydb=> create unique index idx_test_2_id  on test_2 (id);
CREATE INDEX
實驗結論:1 上述實驗說明 "Create index "操作和"Insert"操作衝突;也就是 "Share"鎖和"RowExclusive"鎖衝突。
          2 在生產庫上應該避免在業務高峯期執行新建索引操作,因爲如果在張大表上新建索引,消耗時間較長,在這個過程中會阻塞業務的DML操作。

4.3  SHARE UPDATE EXCLUSIVE 與自身衝突
       根據章節二,大家知道 VACUUM(Without full), Analyze 和 Create index (Concurently)操作會申請獲得”Shared update Exclusive 鎖”。根據圖一,”Shared update Exclusive 鎖”與本身也是會衝突的,下面實驗驗證一下:

--會話一,分析表test_2

mydb=> select * from test_2;
 id |  name  | sex
----+--------+-----
  1 | franc  |
  2 | tan    |
  3 | fpzhou |
(3 rows)
mydb=>
mydb=>
mydb=> begin;
BEGIN
mydb=> analyze test_2;
ANALYZE      
注意: 表分析放在一個事務裏,此時並沒有提交;

--會話二 對錶 test_2 做 vacuum
mydb=> \d test_2;
            Table "skytf.test_2"
 Column |         Type          | Modifiers
--------+-----------------------+-----------
 id     | integer               |
 name   | character varying(32) |
 sex    | character(1)          |
Indexes:
    "idx_test_2_id" UNIQUE, btree (id)
mydb=> vacuum test_2;
注意: 當對錶 test_2 執行 vacuum操作時,操作等侍,

--會話三,觀察系統哪裏鎖住了
[postgres@pg1 ~]$ psql -d mydb
psql (9.0beta3)
Type "help" for help.
mydb=# select datname,procpid,waiting,current_query from pg_stat_activity where waiting='t';
 datname | procpid | waiting | current_query
---------+---------+---------+----------------
 mydb    |   20625 | t       | vacuum test_2;
(1 row)
這裏說明會話 vacuum test_2 在等侍

mydb=# select oid,relname from pg_class where relname='test_2';
  oid  | relname
-------+---------
 33802 | test_2
(1 row)
mydb=# select locktype,database,relation,pid,mode from pg_locks where relation='33802';
 locktype | database | relation |  pid  |           mode          
----------+----------+----------+-------+--------------------------
 relation |    16466 |    33802 | 20625 | ShareUpdateExclusiveLock
 relation |    16466 |    33802 | 20553 | ShareUpdateExclusiveLock
 (2 rows)
 說明: 這裏可以看出 'Analyze'操作 (pid=20553) 和'Vacuum'操作 (pid=20625)都是加的"ShareUpdateExclusiveLock"。

mydb=# select datname,procpid,waiting,current_query from pg_stat_activity where procpid in (20625,20553);
 datname | procpid | waiting |     current_query    
---------+---------+---------+-----------------------
 mydb    |   20553 | f       | <IDLE> in transaction
 mydb    |   20625 | t       | vacuum test_2;
(2 rows)
說明: 結束上面查詢可以看出會話20625在等侍會話20553,也就是說"vacuum test_2" 被事務堵住了,

--再次回到會話一,提交會話,注意此時會話二處於等侍姿態;
mydb=> end;
COMMIT

 

--再次回到會話二,發現 vacuum命令執行下去了,等侍消失。
mydb=> vacuum test_2;
VACUUM
mydb=>  select datname,procpid,waiting,current_query from pg_stat_activity where waiting='t';
 datname | procpid | waiting | current_query
---------+---------+---------+---------------
(0 rows)
實驗結論 1 Analyze 和 Vacuum 操作都會申請獲得 "ShareUpdateExclusiveLock"。
         2 ShareUpdateExclusiveLoc與ShareUpdateExclusiveLock是衝突的。




-----------------

轉載請著明出處:
blog.csdn.net/beiigang



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章