2021SC@SDUSC SQLite源码分析(九)————SQLite Rtree结构

2021SC@SDUSC SQLite源码分析(九)————SQLite Rtree结构


前言

在这里插入图片描述
Rtree位于sqlite源码的ext文件夹下,之前并未接触过此概念。
查阅资料后写下此篇博客作为记录。


一、Rtree是什么?

Rtree的概念源于Toni Guttman:
Rtree:A Dynamic Index structure for spatial Searching,Proc.1984 ACM SIGMOD International Conference on Management of Data

在SQLite中细化并实现了Guttman的算法,也就是Norbert Beckmann, Hans-Peter Kriegel,Ralf Schneider,Bernhard Seeger:The R-Tree:An Efficient and Robust Access Method for Points and Rectangles.SIGMOD Conference 1990:322-331中描述的R*tree。

一个关于R树算法的博文

Rtree是为行查询所设计的一种特殊索引。Rtree一般是用在地理信息系统中查询最小或最大xy坐标的矩形框。给出一个查询矩形,Rtree能快速找到所有包含在矩形中或者与矩形重叠的条目。
Rtree在 时域查询 中也有涉及。比如,如何查询数据库中开始时间和结束时间中的大量记录,Rtree可以迅速的找到在给定时间段内的所有活跃事务,或者在特殊时间段内开始的所有事务,或者所有在特殊时间段内开始并结束的所有事务,等等。

二、Rtree使用

SQLite Rtree模块是用虚表实现的。每个Rtree索引都是一个3-11奇数列的虚表。第一列一般为64bit有符号整型主键。其他列各自组成一对,每对代表一维,包含该维的最大或最小值。因此,一维索引有三列,二维有5列,三维有7列……五维Rtree有11列。SQLite最多支持5维Rtree索引。

Rtree 模块包含在源码中,但默认是不编译的(不在src在ext文件夹)。为了启用R*tree模块,编译时设置SQLITE_ENABLE_RTREE即可。对于大多数编译器,只需在命令行增加“-DSQLITE_ENABLE_RTREE=1”

默认虚表(rtree)用单精度浮点数(4byte)来存放坐标值。如果需要用整型来存放,定义表时需要设置“rtree_i32”

CREATE VIRTUAL TABLE intrtree
USING  rtree_i32(id,x0,x1,y0,y1,z0,z1);

三、Rtree结构

rtree.c中的结构定义:

/* 
** An rtree virtual-table object.
*/
struct Rtree {
  sqlite3_vtab base;          /* Base class.  Must be first */
  sqlite3 *db;                /* Host database connection */
  int iNodeSize;              /* Size in bytes of each node in the node table */
  u8 nDim;                    /* Number of dimensions */
  u8 nDim2;                   /* Twice the number of dimensions */
  u8 eCoordType;              /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */
  u8 nBytesPerCell;           /* Bytes consumed per cell */
  u8 inWrTrans;               /* True if inside write transaction */
  u8 nAux;                    /* # of auxiliary columns in %_rowid */
  u8 nAuxNotNull;             /* Number of initial not-null aux columns */
#ifdef SQLITE_DEBUG
  u8 bCorrupt;                /* Shadow table corruption detected */
#endif
  int iDepth;                 /* Current depth of the r-tree structure */
  char *zDb;                  /* Name of database containing r-tree table */
  char *zName;                /* Name of r-tree table */ 
  u32 nBusy;                  /* Current number of users of this structure */
  i64 nRowEst;                /* Estimated number of rows in this table */
  u32 nCursor;                /* Number of open cursors */
  u32 nNodeRef;               /* Number RtreeNodes with positive nRef */
  char *zReadAuxSql;          /* SQL for statement to read aux data */

  /* List of nodes removed during a CondenseTree operation. List is
  ** linked together via the pointer normally used for hash chains -
  ** RtreeNode.pNext. RtreeNode.iNode stores the depth of the sub-tree 
  ** headed by the node (leaf nodes have RtreeNode.iNode==0).
  */
  RtreeNode *pDeleted;
  int iReinsertHeight;        /* Height of sub-trees Reinsert() has run on */

  /* Blob I/O on xxx_node */
  sqlite3_blob *pNodeBlob;

  /* Statements to read/write/delete a record from xxx_node */
  sqlite3_stmt *pWriteNode;
  sqlite3_stmt *pDeleteNode;

  /* Statements to read/write/delete a record from xxx_rowid */
  sqlite3_stmt *pReadRowid;
  sqlite3_stmt *pWriteRowid;
  sqlite3_stmt *pDeleteRowid;

  /* Statements to read/write/delete a record from xxx_parent */
  sqlite3_stmt *pReadParent;
  sqlite3_stmt *pWriteParent;
  sqlite3_stmt *pDeleteParent;

  /* Statement for writing to the "aux:" fields, if there are any */
  sqlite3_stmt *pWriteAux;

  RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */ 
};

节点结构

/* 
** An rtree structure node.
*/
struct RtreeNode {
  RtreeNode *pParent;         /* Parent node */
  i64 iNode;                  /* The node number */
  int nRef;                   /* Number of references to this node */
  int isDirty;                /* True if the node needs to be written to disk */
  u8 *zData;                  /* Content of the node, as should be on disk */
  RtreeNode *pNext;           /* Next node in this hash collision chain */
};

其中,nRef是该结点的引用次数,用来衡量是否需要将该结点从hash链中删除,isDirty是用来确认该结点是否已被修改.将该结点从hash链删除前如果isDirty=1,则需要将结点数据写入到数据库中.
zData保存了结点相关信息.如果该结点为根结点,则zData前2byte保存了树的高度信息,如果该结点非根节点,则前2byte未使用.zData[2-3]保存了该结点的单元数

节点单元结构

/* 
** A single cell from a node, deserialized
*/
struct RtreeCell {
  i64 iRowid;                                 /* Node or entry ID */
  RtreeCoord aCoord[RTREE_MAX_DIMENSIONS*2];  /* Bounding box coordinates */
};

其中,如果该单元所在结点为叶结点,则iRowid保存对应的rowid.如果该单元所在结点为非叶结点,则iRowid保存了该单元对应的孩子结点号.
aCoord数组保存了该单元对应的维坐标数据。对于每一维数据都会记录一个最大值和最小值,故维坐标数据的数量=最大维度数*2.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值