postgreSQL源码分析——索引的建立与使用——B-Tree索引(3)

2021SC@SDUSC

B-Tree的插入

讲完了B-Tree树的创建过程,我们来讲一下B-Tree树在postgreSQL的插入操作的相关源码。B-Tree的插入是由bt_insert等函数完成的,下面我们就分析一下其源代码。

bt_insert

该函数相当于插入操作的入口函数

bool
btinsert(Relation rel, Datum *values, bool *isnull,
		 ItemPointer ht_ctid, Relation heapRel,
		 IndexUniqueCheck checkUnique,
		 IndexInfo *indexInfo)
{
   
	bool		result;
	IndexTuple	itup;

	/* 得到索引元组 */
	itup = index_form_tuple(RelationGetDescr(rel), values, isnull);
	itup->t_tid = *ht_ctid;

	result = _bt_doinsert(rel, itup, checkUnique, heapRel);//调用 _bt_doinsert函数进行插入

	pfree(itup);

	return result;//返回插入是否成功
}

_bt_doinsert

首先介绍一下相关的重要数据结构BTInsertStateData,该数据结构设计的时候被认为是_bt_doinsert的函数的私有。

BTInsertStateData

typedef struct BTInsertStateData
{
   
	IndexTuple	itup;			//正在插入的索引元组
	Size		itemsz;			//itup大小
	BTScanInsert itup_key;		/* 插入的扫描键值*/

	/*插入的包含叶子节点的区域 */
	Buffer		buf;

/*当前的缓冲区的边界缓存,仅用于插入时刻*/
	bool		bounds_valid;//边界是否有效
	OffsetNumber low;//low-high 边界区域
	OffsetNumber stricthigh;
} BTInsertStateData;

接下来介绍_bt_doinsert函数的相关内容,源代码较长,我在这提前介绍一下该函数的流程
1:调用_bt_mkscankey计算元组的扫描键值
2:计算fastpath,即是否可以通过缓冲区来走捷径降低时间复杂度,比如多次插入单调递增的值时,就可利用缓冲区获取上一次插入的位置
3:并行操作的相关检查
4:唯一索引的相关检查
5:利用_bt_findinsertloc函数寻找插入位置
6:利用_bt_insertonpg进行插入
7:相关栈和锁的释放
以下是该函数的源码,相关解析在源码中进行了注释

bool
_bt_doinsert(Relation rel, IndexTuple itup,
			 IndexUniqueCheck checkUnique, Relation heapRel)
{
   
	bool		is_unique = false;//是否为唯一索引
	BTInsertStateData insertstate; 
	BTScanInsert itup_key;
	BTStack		stack = NULL;
	Buffer		buf;
	bool		fastpath;
	bool		checkingunique = (checkUnique != UNIQUE_CHECK_NO);

	/* 插入扫描键 */
	itup_key = _bt_mkscankey(rel, itup);

	if (checkingunique)//检查是否为唯一索引
	{
   
		if (!itup_key->anynullkeys)
		{
   
		
			itup_key->scantid = NULL;
		}
		else
		{
   
	
			checkingunique = false;
			Assert(checkUnique != UNIQUE_CHECK_EXISTING);//调用assert函数
			//如果该唯一索引不存在那么就赋值is_unique为true,否则就报错
			is_unique = true;
		}
	}

	//填写BTinsertState区域,跟踪当前页面和插入位置
	insertstate.itup = itup;//索引元组赋值
	/* PageAddItem will MAXALIGN(), but be consistent */
	insertstate.itemsz = MAXALIGN(IndexTupleSize(itup)); //该索引元组的大小
	insertstate.itup_key = itup_key;
	insertstate.bounds_valid = false;//设置边界无效
	insertstate.buf = InvalidBuffer;


top:
//设定fastpath快速路径,通过查找缓存块来加速插入的过程,初始值为false
	fastpath = false;
	if (RelationGetTargetBlock(rel) != InvalidBlockNumber)//如果可以获取缓冲块上的排它锁
	//排它锁有效遵循快速路径
	{
   
		Page		page;
		BTPageOpaque lpageop;
       
		buf = ReadBuffer(rel, RelationGetTargetBlock(rel));
      
		if (ConditionalLockBuffer(buf))
		{
   
			_bt_checkpage(rel, buf);
      //用于检查该页面正确性,含有零页或者破损返回
			page = BufferGetPage(buf);
       //通过缓冲区得到page
			lpageop = (BTPageOpaque) PageGetSpecialPointer(page);

			/*
	  查看该页面是否为最右边的页,以及它的空间能否容纳插入一个新元组,以及插入scan键值大于页面的第一个键值
			 */
			if (P_ISLEAF(lpageop) && P_RIGHTMOST(lpageop) &&
				!P_IGNORE(lpageop) &&
				(PageGetFreeSpace(page) 
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PostgreSQL 中的 SP-GiST 是一种通用的空间数据结构,它可以用于实现各种数据类型的索引,例如文本、图像等非空间数据类型。SP-GiST 索引相对于 B-tree 索引来说,具有更好的可扩展性和更高的查询效率,特别是在处理大规模数据集时,表现更为优异。 下面是在 PostgreSQL使用 SP-GiST 索引的一些步骤: 1. 创建扩展 在使用 SP-GiST 索引之前,需要先创建 SP-GiST 扩展。可以使用如下 SQL 语句创建 SP-GiST 扩展: ``` CREATE EXTENSION IF NOT EXISTS "spgist"; ``` 2. 创建索引 在创建 SP-GiST 索引时,需要指定 SP-GiST 算法的名称和需要索引的列。例如,下面的 SQL 语句创建了一个 SP-GiST 索引,用于对表中的 jsonb 类型的列 data 进行索引: ``` CREATE INDEX idx_data_spgist ON tablename USING spgist(data); ``` 3. 查询优化 在使用 SP-GiST 索引时,需要根据具体的业务需求进行查询优化。通常情况下,可以使用 SP-GiST 索引提供的查询算子来实现高效的查询。例如,对于 jsonb 类型的列 data,可以使用 SP-GiST 索引提供的 @> 查询算子来进行查询: ``` SELECT * FROM tablename WHERE data @> '{"key": "value"}'; ``` 这样可以快速地查询出符合条件的记录。 总的来说,SP-GiST 索引可以用于优化各种非空间数据类型的查询,例如文本、图像、JSON 等。在使用 SP-GiST 索引时,需要根据具体的业务需求进行查询优化,以实现最佳的查询效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值