Postgresql内核源码分析-索引如何加速查询

 

  • 专栏内容:postgresql内核源码分析
  • 个人主页:senllang的主页
  • 座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物.

文章目录

前言

加速查询的方式

索引记录的内容

索引与数据如何对应

索引与数据创建顺序

结尾



前言

本文是基于postgresql 15的代码进行分析解读,演示是在centos8系统上进行。


加速查询的方式

大的方面来说,主要是减少检索的数据量,那如何减少呢?

一方面是优化执行计划,逻辑层面减少处理的数据量,另一方面,每个tuple还要从表文件中查找位置,如何能更精确找到位置,而不是遍历整个文件。

索引主是解决第二种情况,同时索引中不会记录真实的数据,所以它的大小非常小,可以很快加载到内存进行查询,这样大大减少了查询过程中的磁盘IO;

下面我们来看索引是如何做到的?


索引记录的内容

不同索引记录的内容不一致,下面以btree索引为例:

看一下insert操作代码:

/* insert the tuple normally */
table_tuple_insert(resultRelationDesc, slot,

                     estate->es_output_cid,

                      0, NULL);

/* insert index entries for tuple */

if (resultRelInfo->ri_NumIndices > 0)

recheckIndexes = ExecInsertIndexTuples(resultRelInfo,

                                    slot, estate, false,

                                    false, NULL, NIL);

在数据insert到block后,heapam_tuple_insert中,会将tuple的tid记录到slot中,也就是tuple的位置信息;


 

   /* Perform the insertion, and copy the resulting ItemPointer */

    heap_insert(relation, tuple, cid, options, bistate);

    ItemPointerCopy(&tuple->t_self, &slot->tts_tid);

在ExecInsertIndexTuples中,会将slot->tts_tid再传到索引里面,形成索引记录

ItemPointer tupleid = &slot->tts_tid;

然后下面开始索引记录的插入操作       

satisfiesConstraint =

            index_insert(indexRelation, /* index relation */

                         values,    /* array of index Datums */

                         isnull,    /* null flags */

                         tupleid,   /* tid of heap tuple */

                         heapRelation,  /* heap relation */

                         checkUnique,   /* type of uniqueness check to do */

                         indexUnchanged,    /* UPDATE without logical change? */

                         indexInfo);    /* index AM may need this */

生成indextuple, 使用以下结构,有两部分:一是heaptuple tid, 二是flag和长度;

typedef struct IndexTupleData

{

    ItemPointerData t_tid;      /* reference TID to heap tuple */

    /* ---------------

     * t_info is laid out in the following fashion:

     *

     * 15th (high) bit: has nulls

     * 14th bit: has var-width attributes

     * 13th bit: AM-defined meaning

     * 12-0 bit: size of tuple

     * ---------------

     */

    unsigned short t_info;      /* various info about tuple */

} IndexTupleData;               /* MORE DATA FOLLOWS AT END OF STRUCT */

typedef IndexTupleData *IndexTuple;


索引与数据如何对应

  • 首先是HOT, heap only tuple。

理论上每个数据tuple都对应一条索引,postgresql在此处做了优化,对于update, 如果新老版本不跨page的话,索引不会新增,通过索引找到老版本,再通过版本链找到最新tuple,这类tuple就是heap only tuple。

  • 对于新老版本跨page存储的,就会新增一条索引,这就会造成索引的膨胀。


索引与数据创建顺序

从代码来看,先将数据插入数据块,在table_tuple_insert操作完成后,拿到tuple的位置信息后,再进行索引操作。         

  /* insert the tuple normally */

  table_tuple_insert(resultRelationDesc, slot,

                      estate->es_output_cid,

                       0, NULL);

   /* insert index entries for tuple */

   if (resultRelInfo->ri_NumIndices > 0)

         recheckIndexes = ExecInsertIndexTuples(resultRelInfo,

                                                slot, estate, false,

                                                 false, NULL, NIL);


结尾

作者邮箱:[email protected]
如有错误或者疏漏欢迎指出,互相学习。

注:未经同意,不得转载!

猜你喜欢

转载自blog.csdn.net/senllang/article/details/129077636