1. 程式人生 > >修改表結構DDL語句與鎖

修改表結構DDL語句與鎖

--當pg開啟一個事務,執行dml操作時,如果另一個事務要修改表結構,其不得不等待
--session1 中執行dml
postgres=# begin;
BEGIN
postgres=# select pg_backend_pid();
 pg_backend_pid 
----------------
           4144
(1 row)


postgres=# insert into t values(2,'rudy2');
INSERT 0 1
postgres=# 




--在session2 中執行ddl語句,發現其要等待
postgres=# begin;
BEGIN
postgres=# select pg_backend_pid();
 pg_backend_pid 
----------------
           3128
(1 row)


postgres=# alter table t add password1 varchar(50);                            




--在session3中可以發現session2發等待session 1
postgres=# SELECT locktype,       
postgres-#         pg_locks.pid,
postgres-#          virtualtransaction,
postgres-#          transactionid,
postgres-#          nspname,
postgres-#          relname,
postgres-#          mode,
postgres-#          granted,
postgres-#     CASE
postgres-#     WHEN granted='f' THEN
postgres-#     'get_lock'
postgres-#     WHEN granted='t' THEN
postgres-#     'wait_lock'
postgres-#     END lock_satus,
postgres-#     CASE
postgres-#     WHEN waiting='f' THEN
postgres-#     'waiting'
postgres-#     WHEN waiting='t' THEN
postgres-#     'executing'
postgres-#     END lock_satus, cast(date_trunc('second',query_start) AS timestamp) AS query_start, substr(query,1,25) AS query
postgres-# FROM pg_locks LEFT OUTER
postgres-# JOIN pg_class
postgres-#     ON (pg_locks.relation = pg_class.oid) LEFT OUTER
postgres-# JOIN pg_namespace
postgres-#     ON (pg_namespace.oid = pg_class.relnamespace), pg_stat_activity
postgres-# WHERE NOT pg_locks.pid=pg_backend_pid()
postgres-#         AND pg_locks.pid=pg_stat_activity.pid
postgres-#         AND transactionid is NOT null
postgres-# ORDER BY  query_start;
   locktype    | pid  | virtualtransaction | transactionid | nspname | relname |     mode      | granted | lock_satus | lock_satus |     query_start     |           query           
---------------+------+--------------------+---------------+---------+---------+---------------+---------+------------+------------+---------------------+---------------------------
 transactionid | 4144 | 8/3137             |       4638456 |         |         | ExclusiveLock | t       | wait_lock  | waiting    | 2015-10-21 20:29:58 | insert into t values(2,'r'
 transactionid | 3128 | 2/14315            |       4638461 |         |         | ExclusiveLock | t       | wait_lock  | executing  | 2015-10-21 20:30:32 | alter table t add passwor
 
 
 
 
 
 
 
 
 
 
 
 
 --在修改表結構時,如果把ddl放在一個事務中,如果事務沒有提交,則其它的事務必須等待,包括查詢
 
 
--在session2事務中執行一個ddl
postgres=# begin;
BEGIN
postgres=# select pg_backend_pid();                
 pg_backend_pid 
----------------
           3128
(1 row)


postgres=# alter table t add password2 varchar(50);
ALTER TABLE
 
 
 --在session1事務中執行dml發生等待
 postgres=# begin;
BEGIN
postgres=# insert into t values(2,'rudy2');




--在session3中可以發現session1在等待session2
   locktype    | pid  | virtualtransaction | transactionid | nspname | relname |     mode      | granted | lock_satus | lock_satus |     query_start     |           query           
---------------+------+--------------------+---------------+---------+---------+---------------+---------+------------+------------+---------------------+---------------------------
 transactionid | 3128 | 2/14316            |       4638466 |         |         | ExclusiveLock | t       | wait_lock  | waiting    | 2015-10-21 20:37:38 | alter table t add passwor




 --在session4中的查詢也發生了等待
postgres=# select * from t limit 1;


--故最好不要把ddl語句放在一個事務中,如果該事務沒有提交,否則其會造成後續的查詢與修改都等待


















--如果一個session中有一個大的查詢在執行,此時最好不要在另一個session中修改表結構,因為查詢會阻塞ddl語句
--在session1中執行一個大的查詢
postgres=# select count(*) from t,t t1;


--在session2中的ddl語句不得不等待
postgres=# alter table t add password3 varchar(50);


--在session3中可以檢視到等待的鎖
   locktype    | pid  | virtualtransaction | transactionid | nspname | relname |     mode      | granted | lock_satus | lock_satus |     query_start     |           query           
---------------+------+--------------------+---------------+---------+---------+---------------+---------+------------+------------+---------------------+---------------------------
 transactionid | 3128 | 2/14317            |       4638470 |         |         | ExclusiveLock | t       | wait_lock  | executing  | 2015-10-21 20:46:09 | alter table t add passwor


--此時如果有其它session的dml操作,又不得不等待session2的ddl語句執行結束,也不得不等待,進而造成排對等待
--由此展開,在主從複製過程中,如果從庫再進行類似報表的查詢,主庫有一個修改表結構的動作,wal日誌複製到從庫,但其卻不得不等待從庫查詢語句執行完成,才能應用日誌,進而造成主從之間的延遲


--故最好在修改表結構時觀察下是否有大的查詢在發生