日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

KingbaseES CTID 与 Oracle ROWID

發(fā)布時(shí)間:2024/5/14 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 KingbaseES CTID 与 Oracle ROWID 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

熟悉oracle的人都知道ROWID可用于快速的數(shù)據(jù)訪問,KingbaseES 由于自身MVCC機(jī)制的原因,ctid 作為 oracle rowid 的替代方案不合適,但currtid 還是基本可以滿足rowid 的功能的。本文向大家介紹如何通過currtid 實(shí)現(xiàn)rowid 的功能。

一、Oracle ROWID

Oracle ROWID 記錄了tuple的物理存儲(chǔ)位置,通過ROWID可以非常快速地訪問tuple。因此,在極致性能的應(yīng)用設(shè)計(jì)里,經(jīng)常會(huì)使用到ROWID。典型的使用場景如下:

declare

? ? ? ? cursor cur01 as select rowid from tab1;

begin

? ? ? ? ......

? ? ? ? update tab1 where rowid='xxx';

end;

二、KingbaseES CTID

我們知道,對于Oracle ,一條tuple的ROWID正常是不會(huì)變化的(引發(fā)row movement的操作除外,如:跨分區(qū)遷移update,表shrink),因此,應(yīng)用設(shè)計(jì)上可以方便的使用rowid,加快訪問速度。而對于KingbaseES,也有類似Oracle ROWID的ctid,格式 “(blockid,slotid)”,同樣記錄了tuple存儲(chǔ)的物理位置,通過ctid也能快速的訪問數(shù)據(jù)。但由于KingbaseES的多版本(MVCC)讀實(shí)現(xiàn)機(jī)制的差異,ctid會(huì)隨update操作變化,這種情況下,使用ctid有可能因?yàn)閠uple被update,導(dǎo)致訪問不到數(shù)據(jù)。為了讓大家對于ctid有直觀認(rèn)識(shí),舉例如下:

A用戶B用戶
select ctid from t1 where id=1;返回 (0,1)
select ctid from t1 where id=1;返回 (0,1)
update t1 set name='aa' where ctid='(0,1)';
select ctid from t1 where id=1;返回 (0,2)
select * from t1 where ctid='(0,1)'; 無返回

可以看到,在有并發(fā)的情況下,用ctid訪問是不可靠的。例子中,B用戶通過ctid 訪問時(shí),就會(huì)發(fā)現(xiàn)找不到數(shù)據(jù)。

三、currtid 函數(shù)

KingbaseES的update操作實(shí)際delete and insert 的結(jié)合體。對于update操作完成后,在vacuum 之前,原始tuple是包含指向新tuple的ctid。函數(shù) currtid 可以通過舊ctid 取得updated tuple的最新ctid。具體見以下例子:

test=# insert into t1 values(1,'a'); INSERT 0 1 test=# select ctid from t1 where id=1;ctid -------(0,1) (1 row)test=# update t1 set name='aa' where id=1; UPDATE 1 test=# select ctid from t1 where id=1;ctid -------(0,2) (1 row)test=# select * from t1 where ctid='(0,1)';id | name ----+------ (0 rows)test=# select currtid('t1'::regclass,'(0,1)');currtid ---------(0,2) (1 row)test=# select * from t1 where ctid=currtid('t1'::regclass,'(0,1)');id | name ----+-----------1 | aa (1 row)

可以看到,通過將初始的 ctid 傳遞給 currtid 函數(shù),可以取得最新的 ctid 。

Note:currtid 有效的前提是update 后,多版本信息沒有被清理掉,也就是沒有進(jìn)行vacuum操作。

四、性能問題

從以上例子可以看到,使用currtid 可以避免期間數(shù)據(jù)被修改的問題。但實(shí)際上,這里有個(gè)性能的問題。請看實(shí)際例子:

test=# explain select * from t1 where ctid=currtid('t1'::regclass,'(0,1)');QUERY PLAN --------------------------------------------------------Seq Scan on t1 (cost=0.00..26.95 rows=1 width=44)Filter: (ctid = currtid('16387'::oid, '(0,1)'::tid)) (2 rows)test=# explain select * from t1 where ctid='(0,2)';QUERY PLAN ---------------------------------------------------Tid Scan on t1 (cost=0.00..4.01 rows=1 width=44)TID Cond: (ctid = '(0,2)'::tid) (2 rows)

可以看到,對于?ctid=currtid('t1'::regclass,'(0,1)') ,實(shí)際上采取的是 seqscan 。問題是currtid('t1'::regclass,'(0,1)') 是在等式右邊的,不涉及 ctid 的轉(zhuǎn)換,為什么無法使用 Tid Scan ??

我們來看currtid 函數(shù)屬性:

test=# select proname,provolatile from pg_proc where proname='currtid';proname | provolatile ---------+-------------currtid | v

函數(shù)是 volatile 。volatile 函數(shù)導(dǎo)致無法使用TID scan

五、修改函數(shù)屬性為immutable

把函數(shù)的屬性改成immutable 情況下的執(zhí)行計(jì)劃:

test=# update pg_proc set provolatile='i' where proname='currtid'; UPDATE 1 test=# explain select * from t1 where ctid=currtid('t1'::regclass,'(0,1)');QUERY PLAN ---------------------------------------------------Tid Scan on t1 (cost=0.00..4.01 rows=1 width=44)TID Cond: (ctid = '(0,2)'::tid) (2 rows)

可以看到,修改函數(shù)的屬性為 immutable后,可以走 Tid Scan了。

附:volatile 函數(shù)與 immutable函數(shù)差異

就本例而言,對于SQL:select * from t1 where ctid=currtid('t1'::regclass,'(0,1)', '(0,1)' )。

如果currtid是volatile 類型的函數(shù),優(yōu)化器采取 Seq Scan,針對每個(gè)tuple,都會(huì)執(zhí)行一次函數(shù)調(diào)用。函數(shù)調(diào)用是在訪問tuple之后,因此,能夠保證數(shù)據(jù)的絕對準(zhǔn)確性。

如果currtid是immutable 類型的函數(shù),針對整個(gè)查詢,只需調(diào)用一次函數(shù)。執(zhí)行SQL時(shí),先執(zhí)行函數(shù),再將結(jié)果以參數(shù)形式傳給SQL。這里的風(fēng)險(xiǎn)點(diǎn)是,如果從函數(shù)調(diào)用開始到SQL執(zhí)行完成之前,如果tuple被update,可能導(dǎo)致返回結(jié)果的不準(zhǔn)確。幸運(yùn)的是,無論函數(shù)調(diào)用,還是TID scan,都是非常快的(微秒級別),基本可以避免影響。

當(dāng)然,如果一定要考慮結(jié)果的絕對準(zhǔn)確,實(shí)際不管使用ROWID,還是 ctid , 都不是絕對安全。因?yàn)?#xff0c;即使oracle ,ROWID 也有可能發(fā)生變動(dòng)。

NOTE:以上的例子同時(shí)在 PostgreSQL12 和 KingbaseES V8R6進(jìn)行過驗(yàn)證。

從計(jì)算 currtid('t1'::regclass,'(0,1)') 的結(jié)果,傳給ctid,再執(zhí)行SQL。在這期間(從即使currtid,到訪問到實(shí)際的tuple,時(shí)間不確定,可能很長,也可能很短,看執(zhí)行計(jì)劃),如果該tuple被修改,則可能返回錯(cuò)誤的結(jié)果(無記錄)。如果采用全表,針對每個(gè)tuple,currtid('t1'::regclass,'(0,1)') 都要計(jì)算一次(volatile,即使參數(shù)值相同,不同時(shí)間返回的值是不同的),函數(shù) currtid('t1'::regclass,'(0,1)') 的結(jié)果運(yùn)算推遲到tuple訪問的同時(shí)進(jìn)行 ,避免了錯(cuò)誤的結(jié)果。

總結(jié)

以上是生活随笔為你收集整理的KingbaseES CTID 与 Oracle ROWID的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。