引言
上一篇文章中,我讲解了索引以及用到索引的IndexScan算子,这一篇文章我要讲述的TIDScan算子也和索引密不可分。
代码位置
src\gausskernel\runtime\executor\nodeTidscan.cpp
名词解释
TID
在GaussDB中,TID是指某一行记录所对应的地址,主要由两部分构成。分别是块地址和块内偏移地址。
在src\include\storage\item\itemptr.h
中找到其对应的结构体为ItemPointerData
,定义如下
//代码清单1
typedef struct ItemPointerData {
BlockIdData ip_blkid;
OffsetNumber ip_posid;
}
其中,ip_blkid代表块地址,ip_posid代表块内偏移地址。
聚集(聚簇)索引与非聚集(聚簇)索引
上一篇文章里对IndexScan算子的解析中我介绍了索引,但是并没有提到索引key-value中的value是什么。要弄清楚value对应的是什么内容,得先弄清楚聚集(聚簇)索引和非聚集(聚簇)索引。
简单地说,聚集(聚簇)索引是指直接定位到TID上的索引;非聚集(聚簇)索引是指间接定位到TID上的索引,通常其直接定位到主码。
下面我将通过一个具体例子来分析。
例如,有一个表如下所示:
Id | Name | Age |
---|---|---|
1 | Tom | 16 |
3 | Jack | 13 |
4 | Mary | 16 |
其中Id是主码(Primary Key)。并且每一个列上都建立了索引。
在此表中Id对应的索引是聚集(聚簇)索引,因为Id是主码,通过主码可以唯一找到一个行数据,因此通过Id可以查找到TID。而Name和Age所对应的索引是非聚集(聚簇)索引,非聚集(聚簇)索引通常定位到主码,例如,通过Name(Age)只能查找到Id,再通过Id查找TID对应的行数据。
过程可以通过一个简单的示意图说明。
非聚集(聚簇)索引寻找行数据花费了2次索引时间,为什么其索引直接定位到TID呢?
当TID发生改变时,需要对索引表进行修改,如果所有索引都采用聚集(聚簇)索引,那么所有需要维护所有索引,所消耗的成本极大。将一部分聚集(聚簇)索引改成非聚集(聚簇)索引,则其他字段到主码字段的索引不需要修改,只需要修改主码到TID的索引,大大减少了维护索引表的开销。
功能作用
TIDScan算子主要用于遍历元组的物理存储位置(TID表),读取一个个元组。
主要函数为:
ExecInitTidScan | 初始化TIDScan状态结点 |
---|---|
ExecTidScan | 迭代获取元组 |
ExecEndTidScan | 清理TIDSCan状态结点 |
ExecReScanTidScan | 重置TIDScan |
ExecTidScan
关键函数为ExecTidScan,其主要代码如下
//代码清单2
TupleTableSlot* ExecTidScan(TidScanState* node)
{
return ExecScan(&node->ss, (ExecScanAccessMtd)TidNext, (ExecScanRecheckMtd)TidRecheck);
}
输入参数
输入参数为TIDScan对应的状态结点TidScanState指针,查看其结构体定义
//代码清单3
typedef struct TidScanState {
ScanState ss;
List* tss_tidquals; /* 过滤表达式 */
bool tss_isCurrentOf; /* 游标是否在当前扫描表中 */
Relation tss_CurrentOf_CurrentPartition; /* 当前扫描分区*/
int tss_NumTids; /* TID列表元素个数*/
int tss_TidPtr; /* 当前扫描位置 */
int tss_MarkTidPtr; /* 标记的扫描位置 */
ItemPointerData* tss_TidList; /* TID列表*/
/* 堆元组 */
union {
HeapTupleData tss_htup;
UHeapTupleData tss_uhtup;
};
HeapTupleHeaderData tss_ctbuf_hdr; /* 堆元组头信息 */
} TidScanState;
执行过程
执行过程比较简单,通过ExecScan函数调用ExecScanFetch函数,在ExecScanFetch函数中调用调用TidNext函数返回一个元组,回到ExecScan函数再进行元组投影,然后返回符合条件的元组。 执行过程图解如下。
小结
本篇文章我学习了聚集(聚簇)索引和非聚集(聚簇)索引,以及TID的结构和TIDScan算子的内容。下一篇文章,我将讲解与索引有关的BitmapScan相关的两个算子。