KingbaseES CTID 与 Oracle ROWID
熟悉oracle的人都知道ROWID可用于快速的数据访问,KingbaseES 由于自身MVCC机制的原因,ctid 作为 oracle rowid 的替代方案不合适,但currtid 还是基本可以满足rowid 的功能的。本文向大家介绍如何通过currtid 实现rowid 的功能。
一、Oracle ROWID
Oracle ROWID 记录了tuple的物理存储位置,通过ROWID可以非常快速地访问tuple。因此,在极致性能的应用设计里,经常会使用到ROWID。典型的使用场景如下:
declare
cursor cur01 as select rowid from tab1;
begin
......
update tab1 where rowid='xxx';
end;
二、KingbaseES CTID
我们知道,对于Oracle ,一条tuple的ROWID正常是不会变化的(引发row movement的操作除外,如:跨分区迁移update,表shrink),因此,应用设计上可以方便的使用rowid,加快访问速度。而对于KingbaseES,也有类似Oracle ROWID的ctid,格式 “(blockid,slotid)”,同样记录了tuple存储的物理位置,通过ctid也能快速的访问数据。但由于KingbaseES的多版本(MVCC)读实现机制的差异,ctid会随update操作变化,这种情况下,使用ctid有可能因为tuple被update,导致访问不到数据。为了让大家对于ctid有直观认识,举例如下:
| 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)'; 无返回 |
可以看到,在有并发的情况下,用ctid访问是不可靠的。例子中,B用户通过ctid 访问时,就会发现找不到数据。
三、currtid 函数
KingbaseES的update操作实际delete and insert 的结合体。对于update操作完成后,在vacuum 之前,原始tuple是包含指向新tuple的ctid。函数 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 函数,可以取得最新的 ctid 。
Note:currtid 有效的前提是update 后,多版本信息没有被清理掉,也就是没有进行vacuum操作。
四、性能问题
从以上例子可以看到,使用currtid 可以避免期间数据被修改的问题。但实际上,这里有个性能的问题。请看实际例子:
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)') ,实际上采取的是 seqscan 。问题是currtid('t1'::regclass,'(0,1)') 是在等式右边的,不涉及 ctid 的转换,为什么无法使用 Tid Scan ?
我们来看currtid 函数属性:
test=# select proname,provolatile from pg_proc where proname='currtid';
proname | provolatile
---------+-------------
currtid | v
函数是 volatile 。volatile 函数导致无法使用TID scan
五、修改函数属性为immutable
把函数的属性改成immutable 情况下的执行计划:
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)
可以看到,修改函数的属性为 immutable后,可以走 Tid Scan了。
附:volatile 函数与 immutable函数差异
就本例而言,对于SQL:select * from t1 where ctid=currtid('t1'::regclass,'(0,1)', '(0,1)' )。
如果currtid是volatile 类型的函数,优化器采取 Seq Scan,针对每个tuple,都会执行一次函数调用。函数调用是在访问tuple之后,因此,能够保证数据的绝对准确性。
如果currtid是immutable 类型的函数,针对整个查询,只需调用一次函数。执行SQL时,先执行函数,再将结果以参数形式传给SQL。这里的风险点是,如果从函数调用开始到SQL执行完成之前,如果tuple被update,可能导致返回结果的不准确。幸运的是,无论函数调用,还是TID scan,都是非常快的(微秒级别),基本可以避免影响。
当然,如果一定要考虑结果的绝对准确,实际不管使用ROWID,还是 ctid , 都不是绝对安全。因为,即使oracle ,ROWID 也有可能发生变动。
NOTE:以上的例子同时在 PostgreSQL12 和 KingbaseES V8R6进行过验证。
从计算 currtid('t1'::regclass,'(0,1)') 的结果,传给ctid,再执行SQL。在这期间(从即使currtid,到访问到实际的tuple,时间不确定,可能很长,也可能很短,看执行计划),如果该tuple被修改,则可能返回错误的结果(无记录)。如果采用全表,针对每个tuple,currtid('t1'::regclass,'(0,1)') 都要计算一次(volatile,即使参数值相同,不同时间返回的值是不同的),函数 currtid('t1'::regclass,'(0,1)') 的结果运算推迟到tuple访问的同时进行 ,避免了错误的结果。
KingbaseES CTID 与 Oracle ROWID的更多相关文章
- oracle rowid 详解
oracle rowid详解 今天是2013-09-15,存储在数据库中的每一行数据都有一个地址,oracle使用rowid数据类型在存储地址.rowid有如下类别: 1)physical rowid ...
- ORACLE rowid,file# 和 rfile#
rowid简介 rowid就是唯一标志记录物理位置的一个id,在oracle 8版本以前,rowid由file#+block#+row#组成,占用6个bytes的空间,10 bit 的 file# , ...
- Oracle rowid
本文讨论的是关于oracle从8i开始引进object的概念后的rowid,即扩展(extended)的rowid:1.rowid的介绍先对rowid有个感官认识:SQL> select ROW ...
- oracle rowid 使用
ROWID是数据的详细地址,通过rowid,oracle可以快速的定位某行具体的数据的位置. ROWID可以分为物理rowid和逻辑rowid两种.普通的堆表中的rowid是物理rowid,索引组织表 ...
- Oracle ROWID具体解释
1.ROWID定义 ROWID:数据库中行的全局唯一地址 对于数据中的每一行,rowid伪列返回行的地址.rowid值主要包括下面信息: 对象的数据对象编号 该行所在的数据文件里的数据块 该行中数据块 ...
- oracle rowid 研究
SQL> create table tab01(id integer,val varchar(4)); Table created. SQL> insert into tab01 valu ...
- KingbaseES V8R6兼容Oracle的exp-imp导出导入工具使用
说明: KingbaseES V8R6版本中的兼容Oracle的exp-imp导入导出工具,支持完全模式.用户模式和表模式的导出功能. 本次案例数据库版本: test=# select version ...
- KingbaseES 如何实现Oracle pipelined 功能
管道函数即是可以返回行集合(可以使嵌套表nested table 或数组 varray)的函数,我们可以像查询物理表一样查询它或者将其赋值给集合变量.KingbaseES 数据库可以用 setof 实 ...
- ORACLE rowid切分大表
通过如下sql获取rowid切分范围 ) || dbms_rowid.rowid_create(, DOI, lo_fno, lo_block, ) ) || ) || dbms_rowid.rowi ...
随机推荐
- 『忘了再学』Shell流程控制 — 39、特殊流程控制语句
目录 1.特殊流程控制语句介绍 2.exit语句 3.break语句 4.continue语句 1.特殊流程控制语句介绍 Shell程序或者说其他的程序,都是顺序执行的,也就是第一行执行完再执行第二行 ...
- CAP:多重注意力机制,有趣的细粒度分类方案 | AAAI 2021
论文提出细粒度分类解决方案CAP,通过上下文感知的注意力机制来帮助模型发现细微的特征变化.除了像素级别的注意力机制,还有区域级别的注意力机制以及局部特征编码方法,与以往的视觉方案很不同,值得一看 来源 ...
- SAP Tree
Effect picture Code as bellow *&---------------------------------------------------------------- ...
- jvm jni 及 pvm pybind11 大批量数据传输及优化
PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明 本文作为本人csdn blog的主站的备份.(Bl ...
- Throwable类中3个异常处理的方法和finally代码块
/* Throwable类中定义了3个异常处理的方法 String getMessage() 返回此 throwable 的简短描述. String toString() 返回此 throwable ...
- 你有没有想过用电子表格也能做MES、WMS、SRM和MRP
曾几何时,小微企业多半选择excel和WPS等电子表格,中小企业更喜欢选择用友金蝶和浪潮这样的国产大品牌软件,而大型企业则偏爱SAP.oracle这样的国外大品牌. 时至今日,风向却变了,品牌软件已不 ...
- 绝对路径和相对路径和File类的构造方法
路径: 绝对路径:是一个完整的路径 以盼复(C:,D:)开始的路径 c:\a.txt C:\User\itcast\IdeaProjects\shungyuan\123.txt D:\demo\b.t ...
- Vnc自动登录器-多国语言绿色版
推荐:介绍一个VNC连接工具:iis7服务器管理工具.IIs7服务器管理工具可以批量连接并管理VNC服务器.作为服务器集成管理器,它最优秀的功能就是批量管理windows与linux系统服务器.vps ...
- vscode 源代码不能自动stage change
前言 vscode的强大不用赘述了,当你开始使用自然就会爱上他.围绕着IDE的编写体验,有很多强大的自带或者第三方插件,可以做到,编码,git管理,甚至部署一条龙[我司就有这样的插件],让大家沉迷其中 ...
- Java集合容器的深度理解
Java容器里有很多写好的容器API,这使我们很方便的可以存储.操作我们的数据. 下面是我写的容器的特点,一些容器的不同之处,从底层源码解析一下容器实现原理 一.常用的容器目录 上图可以看出,java ...