行链接和toast
1、
1)行迁移:
当一个行上的更新操作(原来的数据存在且没有减少)导致当前的数据不能在容纳在当前块,我们需要进行行迁移。一个行迁移意味着整行数据将会移动,仅仅保留的是一个转移地址。因此整行数据都被移动,原始的数据块上仅仅保留的是指向新块的一个地址信息。
2)迁移行不影响全表扫描
当使用全表扫描时,转移地址被忽略。因为我们最终能够获得所有的数据,所以能够忽略其转移地址。因此行迁移并不会对全表扫描产生额外的操作。
迁移行对索引读产生额外的I/O:当使用索引读取数据时将产生额外的I/O。这是由于索引告诉我们通过文件X,块Y,slot槽Z可以获得该行数据。但是当我们根据地址信息达到所在位置时,从其转移地址得知,其真实的数据是存储在文件A,块B,slot槽C上。因此为了寻找该行数据不得不产生额外的逻辑或物理I/O。
3)行链接:当一行数据太大而不能在一个单数据块容纳时,行链接由此产生。行链接有着不同于行迁移的影响,取决于我们所需的数据。如果我们有一行数据有两个列且跨越两个数据块。
4)行迁移影响OLTP系统使用索引读取单行。最糟糕的情形所对所有的读都增加额外的I/O。而行链接则影响索引读和全表扫描。
基于行链接或行迁移的查询或创建(如索引)由于需要更多的I/O将降低数据库的性能。
移出行链接或行迁移使用更大的pctfree参数或使用alter table move命令。
5)Oracle似乎是从后向前进行的写操作,Oracle存储数据是从后往前的,比如一行数据分配了 block #1,2,3,那么存储起来就是先写3,然后2,写不下了再写1 之所以这样说是因为这个块被写满了,而前一块并没有被写满。根据两个BLOCK结构的分析,基本上确认了文章开始的分析,也就是Oracle一个块无法写下全部记录的时候,会通过行链接实现,而实现的方式就是在块头处通过ROWID的方式之处下一个存放记录的块的位置。
6)Oracle并不是以列作为划分记录的单位,一列的数据可能分布到多个BLOCK上,比如这个例子。那么Oracle是如何确定当前BLOCK存放最后一列记录是否完整呢?
所有的块头都包括H和F,而所有的结尾块都包含L,那么显然H或者F标识的是行头信息,而L标识行尾信息。推测H这里表示HIGN END或者HEADING,而L表示LOW END或者LEAF。如果当前块包含的最后一个COLUMN的内容没有结束,会在标识中包含一个N,应该表示NEXT的含义。而对应的下一个BLOCK,如果列不是从头开始,会在标识中包含一个P,应该是PRIOR的含义。
https://www.cnblogs.com/buro79xxd/archive/2011/02/16/1956327.html
https://cloud.tencent.com/developer/article/1953001
2、postgresql toast
Toast 在存储大型数据时,会将它存储在单独的表中(称为 toast 表)。postgresql 不允许 tuple 跨页存储,所以当一行数据的某个列数据过大时,比如 text 类型的数据,超过了单页的大小,那么 postgresql 会将它压缩,切分,并且存储在另外的位置。这种技术就是称为 Toast。
toast表字段:chunk_id、chunk_seq、chunk_data, 索引为chunk_id + chunk_seq。
假设现在向 mytable 表插入一条大型数据,长度为3MB,里面存储了一张图片,采用了base64格式。
postgresql 在处理这条请求时,发现 name 是 text 类型,并且这次插入的数据过大。那么首先它会被压缩,假设被压缩成 1MB,压缩后仍然不满足大小,然后按照指定的大小(默认为 2048 byte)切分成 512 份。每一份切片对应 toast 表的一行数据,它们的 chunk_id 都是相同的,因为属于同一个数据,只是 chunk_seq 不同,对应着切片位置。chunk_data 列就是存储着切片的数据。
3、
postgresql 并没有使用跨页存储的方案,而是将大型数据单独放到其余地方存储。这样在条件过滤时,会比较好,因为它不需要读取这些大的数据,而且只有当该列被选中时,才会在返回数据时去读取。这种场景下,减少了磁盘 IO 的读取,提升了性能。
同样它也有对应的缺点,那就是写入大型的数据时,会比较慢。因为它需要切片,然后插入到 toast 表中,还要更新 toast 表的索引。
如果采用跨页存储,那么还可以利用磁盘顺序写的高性能。
在读取整行数据时候,还需要先去寻找 toast 表的索引,然后再去读取 toast 表的数据,相比较跨页存储,仍然无法使用磁盘顺序读的高性能。
- 点赞
- 收藏
- 关注作者
评论(0)