1 概述
一个 R树 是特别的 用于执行范围查询的索引。 R-树是最常见的 用于地理空间系统中,其中每个条目都是一个带有最小值和 最大X和Y坐标。 给定一个查询矩形,R-Tree可以 快速查找查询矩形中包含的所有条目 或与查询矩形重叠。 这个想法很容易推广到 CAD系统中使用的三维。 R-Trees也可用于时域 范围查找。 例如,假设一个数据库记录启动和 大量事件的结束时间。 R-Tree能够快速 查找给定时间内任何时间处于活动状态的所有事件 时间间隔,或在特定时间间隔内开始的所有事件, 或在给定时间间隔内开始和结束的所有事件。 等等。
R-Tree概念起源于 托尼·古特曼 : R树:一种用于空间搜索的动态索引结构 , 程序。 1984年ACM SIGMOD国际数据管理会议, 第47-57页。 SQLite中的实现是Guttman原始版本的改进 这个想法通常被称为“R*Trees”,由 诺伯特·贝克曼(Norbert Beckmann)、汉斯·佩特·克里格尔(Hans-Peter Kriegel)、拉尔夫·施奈德(Ralf Schneider)、伯恩哈德·西格(Bernhard Seeger): R*-树:一种高效、稳健的点访问方法 和矩形。 SIGMOD会议1990:322-331。
2 编译R*树模块
SQLite R*Tree模块的源代码包含在其中 的 合并 。但是,取决于配置选项 以及您正在使用的SQLite的特定版本,它可能会也可能不会 默认情况下启用。 为了确保启用R*Tree模块, 只需使用 SQLITE_ENABLE_RTREE数据库 C预处理器宏已定义。 通过许多编译器,这是可以实现的 通过将选项“-DSQLITE_ENABLE_RTREE=1”添加到编译器 命令行。
三。 使用R*树模块
SQLite R*Tree模块实现为 虚拟表 每个R*树索引是一个 奇数列数在3到11之间的虚拟表。 第一列始终是64位有符号整数主键。 其他列是对,每个维度一对,包含 该尺寸的最小值和最大值。 因此,一维R*树具有3列。 二维R*树有5列。 三维R*树有7列。 四维R*Tree有9列。 5维R*Tree有11列。 SQLite R*Tree实现 不支持宽度超过5维的R*树。
SQLite R*树的第一列类似于整数主目录 普通SQLite表的键列。 它只能存储64位签名 整数值。 在该列中插入NULL值会导致SQLite 自动生成新的唯一主键值。 如果尝试 将任何其他非整数值插入此列, r-tree模块在写入之前将其静默地转换为整数 到数据库中。
最小/最大值对列存储为的32位浮点值 “rtree”虚拟表或“rtree_i32”虚拟中的32位有符号整数 桌子。 与常规SQLite表不同,后者可以将数据存储在各种 数据类型和格式,R*Tree严格执行这些存储类型。 如果在这样的列中插入任何其他类型的值,则r-树 模块在写入 数据库中的新记录。
3.1. 创建R*树索引
创建一个新的R*Tree索引,如下所示:
这个 <名称> 是应用程序为 R*树索引和 <列名> 是以逗号分隔的列表 3至11列之间。 虚拟<name>表创建三个 阴影表 到实际上 存储其内容。 这些影子表的名称为:
影子表是普通的SQLite数据表。 您可以查询它们 如果你愿意,可以直接说,尽管这不太可能透露任何特别的信息 非常有用。 你可以 更新 , 删除 , 插入 甚至是 下降 影子表,尽管这样做会破坏你的R*树索引。 因此,最好忽略影子表。 认识到他们 保留你的R*Tree索引信息,然后就这样放了。
例如,考虑创建一个二维R*Tree索引,用于 空间查询:
使用rtree创建虚拟表demo_index( id,--整数主键 minX,maxX,--最小和最大X坐标 minY,maxY——最小和最大Y坐标 );
3.1.1. 列命名详细信息
在CREATE VIRTUAL TABLE语句中“rtree”的参数中 列的名称取自每个参数的第一个标记。 每个参数中的所有后续标记都将被默认忽略。 这意味着,例如,如果您尝试将 类型亲和力 或将约束(如UNIQUE、NOT NULL或DEFAULT)添加到 列中,这些额外的标记被视为有效,但不会更改 rtree的行为。 在RTREE虚拟表中,第一列始终具有 类型亲和力 INTEGER和所有其他数据列的 类型亲和力 真实的。 在RTREE_I32虚拟表中,所有列的类型关联都为INTEGER。
建议的做法是在rtree规范中省略任何额外的标记。 让“rtree”的每个参数都是一个普通标签,它是 相应的列,并省略参数列表中的所有其他标记。
3.2. 填充R*树索引
像往常一样 插入 , 更新 、和 删除 命令在R*树上工作 索引就像在常规表上一样。 所以要在我们的示例中插入一些数据 R*树索引,我们可以这样做:
插入demo_index值 (28215, -80.781227, -80.604706, 35.208813, 35.297367), (28216, -80.957283, -80.840599, 35.235920, 35.367825), (28217, -80.960869, -80.869431, 35.133682, 35.208233), (28226、-80.878983、-80.778275、35.060287、35.154446), (28227, -80.745544, -80.555382, 35.130215, 35.236916), (28244、-80.844208、-80.841988、35.223728、35.225471), (28262, -80.809074, -80.682938, 35.276207, 35.377747), (28269, -80.851471, -80.735718, 35.272560, 35.407925), (28270, -80.794983, -80.728966, 35.059872, 35.161823), (28273, -80.994766, -80.875259, 35.074734, 35.172836), (28277, -80.876793, -80.767586, 35.001709, 35.101063), (28278, -81.058029, -80.956375, 35.044701, 35.223812), (28280, -80.844208, -80.841972, 35.225468, 35.227203), (28282, -80.846382, -80.844193, 35.223972, 35.225655);
上面的条目是14的边界框(经度和纬度) 北卡罗来纳州夏洛特附近的邮政编码。一个真正的数据库会有数千个, 数百万或数十亿条这样的条目,但这个14行的小样本将 足以说明这些想法。
3.3. 查询R*树索引
任何有效的查询都将针对R*Tree索引。 R*树 实现只是使一些类型的查询特别 高效。 对主键的查询是高效的:
从demo_index中选择*,其中id=28269;
当然,一个普通的SQLite表也会对它的 integer主键有效,所以前面的并不重要。 使用R*Tree的主要原因是 您可以有效地根据坐标进行范围查询 范围。 例如,SQLite项目的主要办公室是 位于35.37785,80.77470。 要找到可能为该办公室服务的邮政编码,可以更正:
从demo_index选择id 其中,minX<=-80.77470,maxX>=-80.774 70 最小值<=35.37785,最大值>=35.3778;
上面的查询将快速查找包含以下内容的所有邮政编码 SQLite主办公室位于其边界框中,即使 R*树包含许多条目。 前面是一个示例 “contained-in-within”查询。 R*树还支持“重叠” 查询。 例如,查找所有重叠的邮政编码边界框 邮政编码为28269:
从demo_index AS A和demo_ndex AS B中选择A.id 其中A.maxX>=B.minX和A.minX<=B.maxX 和A.maxY>=B.minY和A.minY<=B.maxY 和B.id=28269;
第二个查询将找到28269个条目(因为每个边界框 与自身重叠)以及其他足够接近的邮政编码 28269个边界框重叠。
注意,R*Tree索引中的所有坐标都不需要 约束以使索引搜索高效。 例如,可能需要查询与重叠的所有对象 第35平行线:
从demo_index选择id 其中,最大值>=35.0,最小值<=35.0;
但是,一般来说,R*Tree模块的约束更多 必须使用,并且边界框越小 结果会回来的。
3.4. 舍入误差
默认情况下,坐标使用32位浮点存储在R*树中 点值。 当坐标不能由 32位浮点数,下限坐标向下舍入 上界坐标向上舍入。 因此,边界框可能 略大于指定值,但永远不会小于指定值。 这个 正是执行更常见的“重叠”查询所需要的 应用程序希望查找R*树中重叠的每个条目的位置 查询边界框。 向外舍入条目边界框可能会导致 如果 条目边界框对应于查询边界框的边缘。 但是 重叠查询永远不会丢失有效的表条目。
然而,对于“contained-in-within”样式的查询,舍入边界 向外的框可能会导致从结果集中排除某些条目 如果条目边界框的边缘对应于查询的边缘 边界框。 为了防止这种情况,应用程序应该扩展其 通过将 在每个维度中,降低坐标并向上舍入顶部坐标。
3.5. 阅读和写作同时进行
Guttman R-Tree算法的本质是任何写操作都可能 从根本上重新构造树,并在此过程中更改扫描顺序 节点的。 因此,通常不可能修改 R-Tree查询中间的R-Tree。 尝试这样做 将失败,并返回 SQLITE_锁定 “数据库表被锁定”错误。
例如,假设应用程序对R-Tree运行一个查询 这个:
从demo_index选择id 其中,最大值>=35.0,最小值<=35.0;
然后,假设应用程序为返回的每个“id”值创建一个 如下所示的UPDATE语句并绑定返回的“id”值 “?1”参数:
更新demo_index集合maxY=maxY+0.5,其中id=? 1;
那么UPDATE可能会失败,并出现SQLITE_LOCKED错误。 原因是 初始查询尚未运行完成。 它正在记住它的位置 在R树扫描的中间。 因此,更新R-Tree不能 可以容忍,因为这会破坏扫描。
这只是R-Tree扩展的一个限制。 中的普通表 SQLite能够同时读写。 其他虚拟表 可能(也可能不)具有该功能。 R-Tree可以显示为 并在某些情况下同时写作,如果它能想出如何 在开始更新之前可靠地运行查询直至完成。 但是 你不应该在每次查询中都指望它。 一般来说 最好避免在同一个R-Tree上运行查询和更新 时间。
如果您真的需要基于针对 相同的R-Tree,最好先运行复杂的查询并存储 临时表中的结果,然后根据这些值更新R-Tree 存储在临时表中。
4 有效使用R*树
对于3.24.0(2018-06-04)之前的SQLite版本, R*Tree索引存储的关于对象的唯一信息是 其整数ID和边界框。 需要更多信息 存储在单独的表中,并使用 主键。 对于上面的示例,可以创建一个辅助 下表:
创建表格demo_data( id整数主键,--主键 objname TEXT,--对象的名称 对象类型TEXT,--对象类型 boundary BLOB——对象的详细边界 );
在本例中,demo_data.boundary字段用于保存一些 对象精确边界的二进制表示。 R*树索引仅为 对象。 R*树边界只是真实对象的近似值 边界。 所以通常情况下,R*Tree索引用于 将搜索范围缩小到候选对象列表,然后进行更详细的搜索 并对每个候选人进行昂贵的计算,以确定 候选人确实符合搜索条件。
关键点: R*Tree索引通常不会提供准确的答案,而只是 将潜在答案从数百万个减少到几十个。
假设demo_data.boundary字段包含一些专有数据描述 zipcode的复杂二维边界,并假设 应用程序已使用 sqlite3_create_function() 接口到 创建了应用程序定义的函数“contained-in(boundary,lat,long)” 它接受demodata.boundary对象和纬度和经度 如果lat/long包含在 边界。 可以假设“contained_in()”是一个相对较慢的 我们不想频繁调用的函数。 然后是查找主 SQLite办公室将运行如下查询:
从demo_data、demo_index中选择对象名 WHERE demo_data.id=demo_index.id AND contained_in(演示数据边界,35.37785,-80.77470) 和最小X<=-80.77470和最大X>=-80.774 70 最小值<=35.37785,最大值>=35.3778;
注意上面的查询是如何工作的:R*Tree索引在外部运行 循环查找包含SQLite主办公室的条目 边界框。 对于找到的每一行,SQLite都会进行查找 demodata表中的相应条目。 然后使用边界 demo_data表中的字段作为contained_in()的参数 函数,如果该函数返回true,那么我们就知道寻找的 坐标位于该邮政编码边界内。
如果不使用R*Tree索引,就会得到相同的答案 使用以下更简单的查询:
从demo_data选择对象名 包含在何处(demo_data.boundary,35.37785,-80.77470);
后一个查询的问题是它必须应用 contained_in()函数添加到demo_data表中的所有条目。 倒数第二个查询中使用R*树可以减少 调用contained_in()函数到整个表的一个子集。 R*Tree索引本身并没有找到确切的答案,它只是 限制了搜索空间。
4.1. 辅助立柱
从SQLite版本3.24.0(2018-06-04)开始,r-tree表 可以有存储任意数据的辅助列。 可以使用辅助柱代替 辅助表,如“demo_data”。
辅助列在列名之前用“+”符号标记。 辅助列必须位于所有坐标边界列之后。 一个RTREE表的列总数不能超过100列。 换句话说, 包括整数主键列的列的计数, 坐标边界列和所有辅助列必须小于等于100。 以下示例显示了一个带有辅助列的r树表 相当于上面的两个表“demo_index”和“demo_data”:
使用rtree创建虚拟表demo_index2( id,--整数主键 minX,maxX,--最小和最大X坐标 minY,maxY,--最小和最大Y坐标 +objname TEXT,--对象的名称 +对象类型TEXT,--对象类型 +boundary BLOB——对象的详细边界 );
通过将位置数据和相关信息组合到同一个 表,辅助列可以提供更清晰的模型 并减少连接的需要。 例如,较早的 demo_index和demo_data之间的连接 现在可以了 写为一个简单的查询,如下所示:
从demo_index2选择对象名 其中包含_ in(边界,35.37785,-80.77470) 和最小X<=-80.77470和最大X>=-80.774 70 最小值<=35.37785,最大值>=35.3778;
4.1.1. 限制
对于辅助列,只有列的名称才重要。 这个 类型亲和力 被忽略。 约束,如NOT NULL、UNIQUE、REFERENCES或CHECK 也会被忽略。 然而,未来版本 SQLite的可能会开始注意类型关联和 约束,因此建议辅助列的用户离开 都是空白的,以避免将来的兼容性问题。
5 整值R-树
默认的虚拟表(“rtree”)将坐标存储为 单精度(4字节)浮点数。 如果是整数坐标 如果需要,则使用“rtree_i32”声明表:
使用rtree_i32(id,x0,x1,y0,y1,z0,z1)创建虚拟表intrtree;
rtree_i32将坐标存储为32位有符号整数。 尽管它使用整数存储值,但rtree_i32虚拟 表仍然在内部使用浮点计算作为 r树算法。
6 自定义R-Tree查询
通过在SELECT查询的WHERE子句中使用标准SQL表达式, 程序员可以查询所有R*Tree条目 与特定的bounding-box相交或包含在其中。 自定义R*Tree查询,使用MATCH 运算符,允许程序员查询 与任意区域或形状相交的R*Tree项集,而不是 只是一个盒子。 例如,在计算 R*树中从定位的摄影机可见的对象子集 在三维空间中。
自定义R*Tree查询的区域由R*Tree-geometry回调定义 由应用程序实现并通过调用SQLite注册 以下两个API中的一个:
int sqlite3_rtree_query_callback( sqlite3*db, const char*zQueryFunc, int(*xQueryFunc)(sqlite3_rtree_query_info*), 无效*pContext, void(*x析构函数)(void*) ); int sqlite3_rtree_geometry回调( sqlite3*db, 常量字符*zGeom, int(*xGeom)(sqlite3_rtree_geometry*,int nCoord,double*aCoord,int*pRes), 无效*pContext );
sqlite3_rtree_query_callback()可用于SQLite 版本3.8.5 (2014-06-04),是首选接口。 sqlite3_rtree_geometry_callback()是一个较旧且不太灵活的 支持向后兼容性的接口。
对上述API之一的调用会创建一个新的SQL函数,该函数由 第二个参数(zQueryFunc或zGeom)。 当该SQL函数出现时 在MATCH运算符的右侧和 MATCH运算符是R*Tree虚拟表中的任何列,然后是回调 调用由第三个参数(xQueryFunc或xGeom)定义的 如果特定对象或子树与所需区域重叠。
例如,可以使用以下查询来查找 R*与以45.3,22.9为中心的圆圈重叠的树条目 半径5.0:
从demo_index中选择id,其中id匹配圆(45.3、22.9、5.0)
无论哪种情况,自定义查询的SQL语法都是相同的 接口,sqlite3_rtree_geometry_callback()或sqlite3_ rtree_query_callback(), 用于注册SQL函数。 然而,更新的查询样式 回调使应用程序能够更好地控制查询的进行方式。
6.1. Legacy xGeom回调
使用四个参数调用遗留xGeom回调。 第一个 参数是指向sqlite3rtree_geometry结构的指针,该结构提供 有关如何调用SQL函数的信息。 第二个参数 是每个r树条目中的坐标数,并且始终相同 对于任何给定的R*树。 一维R*树的坐标数为2, 4表示二维R*树,6表示三维R*树等。 第三个参数aCoord[]是一个nCoord坐标数组,用于定义 待测试的边界框。 最后一个参数是指向的指针 应该写入回调结果。 结果为零 如果由aCoord[]定义的bounding-box完全位于外部 xGeom回调定义的区域,如果 bounding-box位于xGeom区域内部或与该区域重叠。 xGeom系列 回调通常应返回SQLITE_OK。如果xGeom返回任何其他 则r树查询将中止并返回错误。
sqlite3_rtree_geometry结构 xGeom回调指向具有如下所示的结构。 完全一样 sqlite3_rtree_geometry 结构用于相同中相同MATCH运算符的每个回调 查询。 sqlite3_rtree_geometry的内容 结构由SQLite初始化,但 未随后修改。 回调可以自由更改 pUser和xDelUser元素(如果需要)。
typedef struct sqlite3_rtree_geometry sqlite3_tree_geametry; 结构sqlite3_rtree_geometry{ void*pContext;/* 传递给s_r_g_c()的pContext副本*/ int nParam;/* 数组aParam的大小*/ 双精度*aParam;/* 传递给SQL geom函数的参数*/ void*p用户;/* 回调实现用户数据*/ void(*xDelUser)(void*);/* SQLite调用以清理pUser*/ };
sqlite3_rtree_geometry的pContext成员 结构始终设置为pContext的副本 参数传递给sqlite3_rtree_geometry_callback()时 已注册回调。 aParam[]数组(大小nParam)包含参数 传递给MATCH运算符右侧的SQL函数的值。 在上面的示例“circle”查询中,nParam将设置为3,aParam[] 数组将包含三个值45.3、22.9和5.0。
sqlite3_rtree_geometry结构的pUser和xDelUser成员包括 初始设置为NULL。 pUser变量可以由回调设置 实现任何可能对后续操作有用的任意值 在同一查询中调用回调(例如 指向用于测试区域相交的复杂数据结构的指针)。 如果xDelUser变量设置为非NULL值,则在 查询已完成运行SQLite,并使用 pUser变量的值作为唯一参数。 换句话说,xDelUser 可以设置为pUser值的析构函数。
xGeom回调总是对r-tree进行深度优先搜索。
6.2. 新的xQueryFunc回调
较新的xQueryFunc回调从r树接收更多信息 查询引擎,并将更多信息发送回查询引擎 在它返回之前。 为了帮助保持接口的可管理性,xQueryFunc回调发送和接收 中作为字段的查询引擎信息 sqlite3_rtree_query_info结构:
结构sqlite3_rtree_query_info{ void*pContext;/* pContext从函数注册时开始*/ int nParam;/* 功能参数数量*/ sqlite3_rtree_dbl*a参数;/* 函数参数值*/ void*p用户;/* 如果需要,回调可以使用这个*/ void(*xDelUser)(void*);/* 释放pUser的函数*/ sqlite3_rtree_dbl*a坐标;/* 要检查的节点或入口坐标*/ 无符号int*anQueue;/* 队列中挂起的条目数*/ int nCoord;/* 坐标数*/ int iLevel;/* 当前节点或条目的级别*/ int mxLevel;/* 树中最大的iLevel值*/ sqlite3_int64 iRowid;/* 当前条目的行ID*/ sqlite3_rtree_dbl rParentScore;/* 父节点得分*/ int eParentWith;/* 父节点的可见性*/ int eWithin;/*内 OUT:可视性*/ sqlite3_rtree_dbl rScore;/* OUT:在这里写分数*/ /*以下字段仅在3.8.11及更高版本中可用*/ sqlite3_value**apSqlParam;/* 参数的原始SQL值*/ };
sqlite3_rtree_query_info结构的前五个字段是相同的 到sqlite3_rtree_geometry结构,并且具有完全相同的含义。 sqlite3_rtree_query_info结构还包含nCoord和aCoord字段 与xGeom回调中同名参数的含义相同。
xQueryFunc必须将sqlite3_rtree_query_info的eWithin字段设置为 NOT_WITHIN、PARTLY_WITHIN或FULLY_WINTHIN值之一,具体取决于 或者,由aCoord[]定义的边界框是否完全位于区域之外, 与区域重叠,或完全位于区域内。 在 此外,xQueryFunc必须将rScore字段设置为非负值 指示应分析查询的子树和条目的顺序 然后回来了。 先处理较小的分数。
顾名思义,R*Tree被组织为树。 的每个节点 树是一个边界框。 树的根是一个封装了 树的所有元素。 根目录下有许多子树(通常是 20或更多)每个具有自己的较小边界框,每个包含一些 R*Tree条目的子集。 子树可能有子树,依此类推 直到最后一个人到达真正的R*树的叶子 条目。
通过将根节点作为唯一条目来初始化R*Tree查询 在按rScore排序的优先级队列中。 查询通过从具有 得分最低。 如果该条目是叶(表示它是实际的 R*树条目而不是子树),然后是该条目 作为查询结果的一行返回。 如果提取的优先级队列条目是节点(子树), 然后将该节点的下一个子节点传递给xQueryFunc回调。 如果节点有更多子节点,则会将其返回到优先级队列。 否则将被丢弃。 xQueryFunc 回调集eWithin添加到PARTLY_WITHIN或FULLY_VITHIN 使用回调提供的分数进行优先级队列。 子元素 return NOT_WITHIN被丢弃。 查询一直运行到优先级队列 为空。
R*Tree中的每个叶条目和节点(子树)都有一个整数“level”。 叶子的级别为0。 叶子的第一个包含子树有 1级。 R*树的根具有最大的级别值。 这个 sqlite3_rtree_query_info结构中的mxLevel条目是的级别值 R*树的根。 sqlite3_rtree_query_info中的iLevel条目提供了 被询问对象的级别。
大多数R*Tree查询使用深度优先搜索。 这是通过设置 rScore等于iLevel。 通常首选深度优先搜索,因为 最小化优先级队列中的元素数量,从而减少内存 并加快处理速度。 然而,某些应用程序可能更喜欢 宽度优先搜索,可以通过将rScore设置为mxLevel-iLevel来完成。 通过为rScore创建更复杂的公式,应用程序可以练习 对子树和叶的搜索顺序进行详细控制 返回R*树条目。 例如,在具有多个 数以百万计的R*Tree条目,rScore可以被安排为 首先返回最大或最重要的条目,允许 应用程序快速显示最重要的信息,以及 在可用时填写较小且不太重要的细节。
sqlite3_rtree_query_info结构的其他信息字段包括 如果需要,可供xQueryFunc回调使用。 iRowid字段 是元素的rowid(R*Tree中3到11列中的第一列) 正在考虑中。 iRowid仅对叶有效。 eParentWith和 rParentScore值是来自 包含当前行的子树。 anQueue字段是一个数组 mxLevel+1个无符号整数,表示中的当前元素数 每个级别的优先级队列。
6.3. 自定义查询的其他注意事项
自定义R*Tree查询函数的MATCH运算符必须是顶级的 WHERE子句的AND连接项,否则它将不可用 通过R*Tree查询优化器,查询将无法运行。 如果MATCH运算符连接到WHERE子句的其他项 例如,通过OR运算符,查询将失败并返回错误。
同一WHERE子句中允许两个或多个MATCH运算符,只要 因为它们由AND运算符连接。 然而, R*Tree查询引擎只包含一个优先级队列。 优先级 分配给搜索中每个节点的优先级是 MATCH运算符。
7 实施详细信息
以下部分描述了R*Tree实现的一些底层细节, 这可能对故障排除或性能分析有用。
7.1. 阴影表
R*Tree索引的内容实际上存储在三个普通的 名称源自R*Tree名称的SQLite表。 这些 三张表被称为“ 影子表格 “。这是他们的架构:
创建表格%_node(节点整数主键,数据) CREATE TABLE%_parent(nodeno INTEGER主键,parentnode) 创建表格%_rowid(rowid整数主键,nodeno)
每个影子表名称中的“%”将替换为 R*Tree虚拟表。 因此,如果R*Tree表的名称是“xyz”,那么 这三个影子表分别是“xyznode”、“xyzparent”和“xyzrowid”。
%_node表中每个R*树节点都有一个条目。 一个 R*Tree节点由一个或多个彼此接近的条目组成。 树的R*树的节点。 除根节点之外的所有节点都具有 %_parent阴影表中标识父节点的条目。 R*树中的每个条目都有一个rowid。 %_rowid阴影表映射条目 rowid指向包含该条目的节点。
附加到%_rowid表的额外列包含 的内容 辅助立柱 .这些额外的名称 %_rowid列可能与 实际辅助列名。
7.2. 使用rtreecheck()SQL函数进行完整性检查
标量SQL函数rtrecheck(R)或rtreecheck(S,R)运行 对数据库S中包含的名为R的rtree表进行完整性检查。 该函数返回所发现问题的人机语言描述, 如果一切正常,则为字符串“ok”。在R*Tree上运行rtreecheck() 虚拟表类似于运行 PRAGMA完整性检查 在上 数据库。
示例:验证名为“demo_index”的R*树是否格式良好 并且内部一致,运行:
选择rtreecheck('demo_index');
rtreecheck()函数执行以下检查:
对于r-树结构(%_node表)中的每个单元格:
对于每个维度,(坐标1<=坐标2)。
除非单元格位于根节点上,否则该单元格是有界的 由父节点上的父单元执行。
对于叶节点,%_rowid中有一个条目 与单元格的rowid值相对应的表 指向正确的节点。
对于非叶节点上的单元格,在 %_从单元格的子节点到 它所在的节点。
%_rowid表中的条目数相同 因为r树结构中有叶细胞 是一个叶单元,对应于%_rowid表中的每个条目。
%_parent表中的条目数相同 因为r树结构中有非叶细胞 有一个非叶单元格对应于 %_父表。
此页面上次修改时间 2023-02-20 00:00:42 联合技术公司