當(dāng)多個(gè)會(huì)話同時(shí)訪問數(shù)據(jù)庫(kù)的同一數(shù)據(jù)時(shí),理想狀態(tài)是為所有會(huì)話提供高效的訪問,同時(shí)還要維護(hù)嚴(yán)格的數(shù)據(jù)一致性。那這數(shù)據(jù)一致性通過什么來(lái)維護(hù)呢?就是之前文章多次提到的MVCC(多版本并發(fā)控制),可以點(diǎn)擊下列文章標(biāo)題回顧早前發(fā)布的內(nèi)容:
PostgreSQL提供了多種鎖模式用于控制對(duì)表中數(shù)據(jù)的并發(fā)訪問,其中最主要的是表級(jí)鎖與行級(jí)鎖,此外還有頁(yè)級(jí)鎖,咨詢鎖等等,接下來(lái)主要介紹表級(jí)鎖與行級(jí)鎖。
通過上面2個(gè)案例我們應(yīng)該比較了解各種鎖模式?jīng)_突的情況了。接下來(lái)我們介紹行級(jí)鎖。
鎖目標(biāo)存在的數(shù)據(jù)庫(kù)的OID,如果目標(biāo)是一個(gè)共享對(duì)象則為0,如果目標(biāo)是一個(gè)事務(wù)ID則為空。
作為鎖目標(biāo)的關(guān)系的OID,如果目標(biāo)不是一個(gè)關(guān)系或者只是關(guān)系的一部分則此列為空。
作為鎖目標(biāo)的頁(yè)在關(guān)系中的頁(yè)號(hào),如果目標(biāo)不是一個(gè)關(guān)系頁(yè)或元組則此列為空。
作為鎖目標(biāo)的元組在頁(yè)中的元組號(hào),如果目標(biāo)不是一個(gè)元組則此列為空。
作為鎖目標(biāo)的事務(wù)虛擬ID,如果目標(biāo)不是一個(gè)虛擬事務(wù)ID則此列為空。
作為鎖目標(biāo)的事務(wù)ID,如果目標(biāo)不是一個(gè)事務(wù)ID則此列為空ID。
包含鎖目標(biāo)的系統(tǒng)目錄的OID,如果目標(biāo)不是一個(gè)普通數(shù)據(jù)庫(kù)對(duì)象則此列為空。
鎖目標(biāo)在它的系統(tǒng)目錄中的OID,如果目標(biāo)不是一個(gè)普通數(shù)據(jù)庫(kù)對(duì)象則為空。
鎖的目標(biāo)列號(hào)(classid和objid指表本身),如果目標(biāo)是某種其他普通數(shù)據(jù)庫(kù)對(duì)象則此列為0,如果目標(biāo)不是一個(gè)普通數(shù)據(jù)庫(kù)對(duì)象則此列為空。
保持這個(gè)鎖或者正在等待這個(gè)鎖的事務(wù)的虛擬ID。
保持這個(gè)鎖或者正在等待這個(gè)鎖的服務(wù)器進(jìn)程的PID,如果此鎖被一個(gè)預(yù)備事務(wù)所持有則此列為空。
此進(jìn)程已持有或者希望持有的鎖模式的名稱。
如果鎖已授予則為真,如果鎖被等待則為假。
with
t_wait as
(
select a.mode,a.locktype,a.database,a.relation,a.page,a.tuple,a.classid,a.granted,
a.objid,a.objsubid,a.pid,a.virtualtransaction,a.virtualxid,a.transactionid,a.fastpath,
b.state,b.query,b.xact_start,b.query_start,b.usename,b.datname,b.client_addr,b.client_port,b.application_name
from pg_locks a,pg_stat_activity b where a.pid=b.pid and not a.granted
),
t_run as
(
select a.mode,a.locktype,a.database,a.relation,a.page,a.tuple,a.classid,a.granted,
a.objid,a.objsubid,a.pid,a.virtualtransaction,a.virtualxid,a.transactionid,a.fastpath,
b.state,b.query,b.xact_start,b.query_start,b.usename,b.datname,b.client_addr,b.client_port,b.application_name
from pg_locks a,pg_stat_activity b where a.pid=b.pid and a.granted
),
t_overlap as
(
select r.* from t_wait w join t_run r on
(
r.locktype is not distinct from w.locktype and
r.database is not distinct from w.database and
r.relation is not distinct from w.relation and
r.page is not distinct from w.page and
r.tuple is not distinct from w.tuple and
r.virtualxid is not distinct from w.virtualxid and
r.transactionid is not distinct from w.transactionid and
r.classid is not distinct from w.classid and
r.objid is not distinct from w.objid and
r.objsubid is not distinct from w.objsubid and
r.pid <> w.pid
)
),
t_unionall as
(
select r.* from t_overlap r
union all
select w.* from t_wait w
)
select locktype,datname,relation::regclass,page,tuple,virtualxid,transactionid::text,classid::regclass,objid,objsubid,
string_agg(
Pid: ||case when pid is null then NULL else pid::text end||chr(10)||
Lock_Granted: ||case when granted is null then NULL else granted::text end|| , Mode: ||case when mode is null then NULL else mode::text end|| , FastPath: ||case when fastpath is null then NULL else fastpath::text end|| , VirtualTransaction: ||case when virtualtransaction is null then NULL else virtualtransaction::text end|| , Session_State: ||case when state is null then NULL else state::text end||chr(10)||
Username: ||case when usename is null then NULL else usename::text end|| , Database: ||case when datname is null then NULL else datname::text end|| , Client_Addr: ||case when client_addr is null then NULL else client_addr::text end|| , Client_Port: ||case when client_port is null then NULL else client_port::text end|| , Application_Name: ||case when application_name is null then NULL else application_name::text end||chr(10)||
Xact_Start: ||case when xact_start is null then NULL else xact_start::text end|| , Query_Start: ||case when query_start is null then NULL else query_start::text end|| , Xact_Elapse: ||case when (now()-xact_start) is null then NULL else (now()-xact_start)::text end|| , Query_Elapse: ||case when (now()-query_start) is null then NULL else (now()-query_start)::text end||chr(10)||
SQL (Current SQL in Transaction): ||chr(10)||
case when query is null then NULL else query::text end,
chr(10)||--------||chr(10)
order by
( case mode
when INVALID then 0
when AccessShareLock then 1
when RowShareLock then 2
when RowExclusiveLock then 3
when ShareUpdateExclusiveLock then 4
when ShareLock then 5
when ShareRowExclusiveLock then 6
when ExclusiveLock then 7
when AccessExclusiveLock then 8
else 0
end ) desc,
(case when granted then 0 else 1 end)
) as lock_conflict
from t_unionall
group by
locktype,datname,relation,page,tuple,virtualxid,transactionid::text,classid,objid,objsubid ;
with recursive tmp_lock as (
select distinct
--w.mode w_mode,w.page w_page,
--w.tuple w_tuple,w.xact_start w_xact_start,w.query_start w_query_start,
--now()-w.query_start w_locktime,w.query w_query
w.pid as id,--w_pid,
r.pid as parentid--r_pid,
--r.locktype,r.mode r_mode,r.usename r_user,r.datname r_db,
--r.relation::regclass,
--r.page r_page,r.tuple r_tuple,r.xact_start r_xact_start,
--r.query_start r_query_start,
--now()-r.query_start r_locktime,r.query r_query,
from (
select a.mode,a.locktype,a.database,
a.relation,a.page,a.tuple,a.classid,
a.objid,a.objsubid,a.pid,a.virtualtransaction,a.virtualxid,
a.transactionid,
b.query as query,
b.xact_start,b.query_start,b.usename,b.datname
from pg_locks a,
pg_stat_activity b
where a.pid=b.pid
and not a.granted
) w,
(
select a.mode,a.locktype,a.database,
a.relation,a.page,a.tuple,a.classid,
a.objid,a.objsubid,a.pid,a.virtualtransaction,a.virtualxid,
a.transactionid,
b.query as query,
b.xact_start,b.query_start,b.usename,b.datname
from pg_locks a,
pg_stat_activity b -- select pg_typeof(pid) from pg_stat_activity
where a.pid=b.pid
and a.granted
) r
where 1=1
and r.locktype is not distinct from w.locktype
and r.database is not distinct from w.database
and r.relation is not distinct from w.relation
and r.page is not distinct from w.page
and r.tuple is not distinct from w.tuple
and r.classid is not distinct from w.classid
and r.objid is not distinct from w.objid
and r.objsubid is not distinct from w.objsubid
and r.transactionid is not distinct from w.transactionid
and r.pid <> w.pid
),tmp0 as (
select *
from tmp_lock tl
union all
select t1.parentid,0::int4
from tmp_lock t1
where 1=1
and t1.parentid not in (select id from tmp_lock)
),tmp3 (pathid,depth,id,parentid) as (
SELECT array[id]::text[] as pathid,1 as depth,id,parentid
FROM tmp0
where 1=1
and parentid=0
union
SELECT t0.pathid||array[t1.id]::text[] as pathid,t0.depth+1 as depth,t1.id,t1.parentid
FROM tmp0 t1,
tmp3 t0
where 1=1
and t1.parentid=t0.id
)
select distinct
/||array_to_string(a0.pathid,/) as pathid,
a0.depth,
a0.id,a0.parentid,lpad(a0.id::text, 2*a0.depth-1+length(a0.id::text), ) as tree_id,
--select pg_cancel_backend(||a0.id|| ); as cancel_pid,
--select pg_terminate_backend(||a0.id|| ); as term_pid,
case when a0.depth =1 then select pg_terminate_backend(|| a0.id || ); else null end as term_pid,
case when a0.depth =1 then select cancel_backend(|| a0.id || ); else null end as cancel_pid
,a2.datname,a2.usename,a2.application_name,a2.client_addr,a2.wait_event_type,a2.wait_event,a2.state
--,a2.backend_start,a2.xact_start,a2.query_start
from tmp3 a0
left outer join (select distinct /||id||/ as prefix_id,id
from tmp0
where 1=1 ) a1
on position( a1.prefix_id in /||array_to_string(a0.pathid,/)||/ ) >0
left outer join pg_stat_activity a2 -- select * from pg_stat_activity
on a0.id = a2.pid
order by /||array_to_string(a0.pathid,/),a0.depth;
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/129295.html
摘要:由此可見,自旋鎖和各有優(yōu)劣,他們分別適用于競(jìng)爭(zhēng)不多和競(jìng)爭(zhēng)激烈的場(chǎng)景中。每一個(gè)試圖進(jìn)入同步代碼塊的線程都會(huì)被封裝成對(duì)象,它們或在對(duì)象的中,或在中,等待成為對(duì)象的成為的對(duì)象即獲取了監(jiān)視器鎖。 前言 系列文章目錄 前面兩篇文章我們介紹了synchronized同步代碼塊以及wait和notify機(jī)制,大致知道了這些關(guān)鍵字和方法是干什么的,以及怎么用。 但是,知其然,并不知其所以然。 例如...
摘要:刪除在使用實(shí)現(xiàn)分布式鎖的時(shí)候,主要就會(huì)使用到這三個(gè)命令。其實(shí),使用的可靠性是要大于使用實(shí)現(xiàn)的分布式鎖的,但是相比而言,的性能更好。 選用Redis實(shí)現(xiàn)分布式鎖原因 Redis有很高的性能 Redis命令對(duì)此支持較好,實(shí)現(xiàn)起來(lái)比較方便 使用命令介紹 SETNX SETNX key val當(dāng)且僅當(dāng)key不存在時(shí),set一個(gè)key為val的字符串,返回1;若key存在,則什么都不做,返回...
摘要:創(chuàng)建測(cè)試表會(huì)話一備注會(huì)話一在事務(wù)里更新的記錄,并不提交。會(huì)話二備注會(huì)話二刪除的記錄,此時(shí)由于這條記錄之前被并沒有提交,這句仍然處于等待狀態(tài)。 PosttgreSQL 的SQL被鎖情況在數(shù)據(jù)庫(kù)維護(hù)過程中非常常見,之前博客 PostgreSQL 鎖分析 演示了 PostgreSQL 鎖的一些場(chǎng)景,在開始本文的介紹之前特做以下說明,假如會(huì)話A堵住會(huì)話B,我們稱會(huì)話B為 blocked 會(huì)話...
閱讀 1356·2023-01-11 13:20
閱讀 1707·2023-01-11 13:20
閱讀 1215·2023-01-11 13:20
閱讀 1906·2023-01-11 13:20
閱讀 4165·2023-01-11 13:20
閱讀 2757·2023-01-11 13:20
閱讀 1402·2023-01-11 13:20
閱讀 3671·2023-01-11 13:20