索引可以加快查询处理速度,但为每个属性以及每个属性组合(这些属性是潜在的搜索键)创建索引通常不是一个好主意。解释为什么。 答:每个额外的索引都需要额外的存储空间;每个索引都需要在插入和删除时额外的CPU时间和磁盘I/O开销;如果有 n n n 个属性,那么需要 2 n 2^n 2n 个索引,这是指数级的。
假设有一个包含 n r n_r nr 个元组的关系 r r r,要在该关系上构建辅助 B+树。 a. 给出一次插入一条记录来构建 B+ 树索引的成本的公式。假设每个块平均保存 f f f 个条目,并且叶子上方的树的所有级别都在内存中。 b. 假设随机磁盘访问需要 10 毫秒,那么针对 1000 万条记录的关系构建索引的成本是多少? c. 编写伪代码以自下而上构建 B+ 树。可以假设有一个可以对大文件进行有效排序的函数。 答: a. C = n r ⋅ ( 1 + log f n r ) / f ∗ t C=n_r\cdot (1+\log_fn_r)/f*t C=nr⋅(1+logfnr)/f∗t b. C = 1000000 ⋅ ( 1 + l o g f 1000000 ) / f ⋅ 0.01 C=1000000\cdot (1 + log_f1000000)/f\cdot0.01 C=1000000⋅(1+logf1000000)/f⋅0.01 c.
B+树文件组织的叶节点在一系列插入后可能会丢失顺序。 a. 解释为什么顺序可能会丢失。 b. 为了最大限度地减少顺序扫描中的查找次数,对于某些相当大的 n n n,许多数据库在 n n n 个块的范围内分配叶页。当分配 B+ 树的第一个叶子时,仅使用 n n n 块单元中的一个块,其余页是空闲的。如果页面分裂,并且其 n n n 块单元有一个空闲页面,则该空间将用于新页面。如果 n n n 块单元已满,则分配另一个 n n n 块单元,并且前 n ∕ 2 n∕2 n∕2 叶页放置在一个 n n n 块单元中,剩余的放置在第二个 n n n 块单元中。为简单起见,假设没有删除操作。 i. 假设第一个 n n n 块单元已满后,最坏情况下分配空间的占用情况是多少? ii. 是否有可能分配给一个 n n n 节点块单元的叶子节点不是连续的,即是否有可能两个叶子节点分配给一个 n n n 节点块,但两者之间的另一个叶子节点分配给不同的 n n n 节点块? iii. 在缓冲区空间足以存储 n n n 页块的合理假设下,在最坏的情况下,B+ 树的叶级扫描需要多少次查找?如果一次分配一个叶页块,将此数字与最坏情况进行比较。 iv. 当与前面的叶块分配方案一起使用时,将值重新分配给兄弟节点以提高空间利用率的技术可能会更有效。解释为什么。 答:a. 叶子节点的顺序性可能会丢失的原因是,当插入一个新的数据条目时,可能会导致叶子节点分裂。分裂后,原来的叶子节点和新的叶子节点之间的指针可能会指向不连续的物理块,从而破坏了顺序性。 b. i. 最坏情况占用率是 50 % 50\% 50%。这是因为当第一个 n n n 块单元满了之后,需要分配一个新的单元,并将前 n / 2 n/2 n/2 个叶子页面移到新的单元中。这样,原来的单元就只剩下 n / 2 n/2 n/2 个叶子页面,而新的单元也只有 n / 2 n/2 n/2 个叶子页面。所以,两个单元中一共有 n n n 个叶子页面,占用了 2 n 2n 2n 个块,占用率是 50 % 50\% 50%。 ii. 不可能。这是因为当一个页面分裂时,它会优先使用它所在的单元中的空闲页面。只有当这个单元已经满了时,才会分配一个新的单元,并将 n / 2 n/2 n/2 个叶子页面移到新的单元中。这样,每个单元中的叶子节点都是连续的,并且按照键值排序。 iii. 在最坏情况下,需要 ⌈ N n ⌉ ⌈\frac{N}{n}⌉ ⌈nN⌉ 次寻道来进行B+树的叶级扫描,其中 N N N 是B+树中数据条目的总数。这是因为每次寻道可以读取一个 n n n 页块,并且每个 n n n 页块都至少有 ⌈ n 2 ⌉ ⌈\frac{n}{2}⌉ ⌈2n⌉ 个数据条目。所以,总共需要 ⌈ N ⌈ n 2 ⌉ ⌉ = ⌈ N n ⌈\frac{N}{⌈\frac{n}{2}⌉}⌉=⌈\frac{N}{n} ⌈⌈2n⌉N⌉=⌈nN⌉次寻道。与每次分配一个块的叶页面相比,这个数字要小得多。如果每次分配一个块的叶页面,那么在最坏情况下,需要 N N N 次寻道来进行B+树的叶级扫描,因为每次寻道只能读取一个数据条目。所以,使用 n n n 块单元的分配方法可以显著减少寻道次数。 iv. 这是因为当使用前面描述的分配叶块的方法时,每个单元中的叶节点都是连续的,并且按照键值排序。这样,当一个叶节点的数据条目过少时,可以从它相邻的兄弟节点中借用一些数据条目,而不需要改变它们所在的单元。这样就可以避免分裂和合并操作,从而提高空间利用率和性能。
假设一个关系存储在一个B+树文件组织中。假设二级索引存储记录标识符,它们是指向磁盘上记录的指针。 a. 如果在文件组织中发生了节点分裂,会对二级索引有什么影响? b. 更新二级索引中所有受影响的记录的代价是多少? c. 如何使用文件组织的搜索键作为逻辑记录标识符来解决这个问题? d. 使用这样的逻辑记录标识符会带来额外的成本吗? 答: a. 如果在文件组织中发生了节点分裂,会导致辅助索引中的一些记录标识符失效,因为它们指向的记录可能已经被移动到新的节点中。这就需要更新二级索引中所有包含失效指针的数据项。 b. 更新二级索引中所有受影响的记录的代价取决于分裂节点中有多少记录被移动,以及二级索引中有多少数据项引用了这些记录。如果分裂节点中有 n n n 个记录被移动,而每个记录在二级索引中有 m m m 个数据项引用它,那么总共需要更新 n m nm nm 个数据项。每个数据项的更新代价包括查找、删除和插入操作。如果二级索引也是B+树结构,那么每个操作的平均代价是 O ( log B N ) O(\log_BN) O(logBN),其中 B B B 是B+树的分支数, N N N 是B+树的数据项数。因此,总的更新代价是 O ( n m log B N ) O(nm\log_BN) O(nmlogBN)。 c. 使用文件组织的搜索键作为逻辑记录标识符可以解决这个问题,因为这样就不需要存储指向磁盘上记录的物理指针,而是存储能够唯一标识记录的搜索键值。这样,即使文件组织中发生了节点分裂,也不会影响二级索引中的数据项,因为它们仍然可以通过搜索键找到对应的记录。 d. 使用这样的逻辑记录标识符会带来额外的成本,因为它们通常比物理指针占用更多的空间,从而增加了二级索引的大小和存储需求。此外,使用逻辑记录标识符还需要在文件组织中进行额外的查找操作,以便根据搜索键找到对应的记录。这可能会增加查询性能的开销。
文章评论