圈子推荐
查看所有吧>>
活跃用户
    HOT技术(heap only tuple)

    AtlasDB实现了MVCC,但是没有引入undo表空间,为实现多版本读,所有的update操作都插入一个新版本行(delete-marked-old + insert-new),数据行的各个版本从老到新形成一个单向链表,即update chain

    例如

    t有两个列(id , name),其中name上有索引 ind_name,现在表有2个数据行,分别称为tuple1tuple2

    (1, 'a')

    (0, 'b')

    执行update t set id =id+ 1 where name = 'a'

    现在表上有3个数据行

    (1, 'a') ---> (2, 'a')  这个是update chain(1, 'a')此时被标记为deleted,且其指向(2, 'a')

    (0, 'b')

     

    update语句同时满足下述两个条件时,索引不会新增entry

    1 update没有更新索引列;

    2 表块有足够空间容纳update产生的新版本行,即同一update chain上的所有版本必须位于同一个数据块中。

    同样的例子,执行update t set id =id+ 1 where name = 'a'

    现在表上有3个数据行

    (1, 'a') ---> (2, 'a')

    (0, 'b')

    而索引ind_name没有改变

    ('a', tuple1_pos)

    ('b', tuple2_pos)

     

    尽管数据行从(1, 'a')变成了(2, 'a'),但是ind_name的索引项仍然指向(1, 'a'),回表时通过遍历update chain找到(2, 'a')

     

    AtlasDB数据块由几部分组成: 块头;行指针;数据行;块尾

    其中行指针指向对应行物理位置,其组成为(lp_offset, lp_flags, lp_len) = (15b, 2b, 15b) 

    lp_offset为元组在块内偏移量,2^15=32768,因此PG的数据块最大为32K

    lp_flags描述元组的状态,有4个候选值:未使用;正常使用;hot重定向;死亡

    lp_len为元组的长度

    每个数据行都有一个行指针,当全表扫描时,会读取块内的所有行指针以获取数据行。

     

    数据行的头部包含一些元数据字段,其中ctid标注该行物理位置(offset, len),和行指针有重复嫌疑,当形成update chain时,ctid指向的是链表中下一个版本的位置,依靠它才能完成遍历。

     

    同时,AtlasDB不允许有行链接出现,因为这样会导致索引回表访问时产生额外IO,所以当数据块不足以容纳一个update chain上的所有元素时,便会在其他数据块新建一条update chain,相应的索引也会新增一个entry

     

    block 1

    (1, 'a') ---> (2, 'a') ---> .......

    (0, 'b')

     

    block 2

    (N, 'a') ---> (N + 1, 'a')

    此时索引会新增一个entry

    ('a', tuple1_pos)   -->  ('a', tuple3_pos)

    ('b', tuple2_pos)


    • 分享到:
    排序方式:回复时间 共有3条评论

    weixin_33832142 发表于 2020-05-22 15:04 1 楼

    一直更新操作会不会把block给撑爆呀

    | 回复

    十亿少女的梦 发表于 2020-05-22 16:32 2 楼

    为什么没有讲到回收或者重新标记无效的tuple后,数据dml操作对索引的影响呢

    | 回复

    呼哈哈呼 发表于 2020-05-24 15:34 3 楼

    回复@weixin_33832142 :当然要清理的呀

    | 回复