磁盘导向的数据库管理系统(DBMS)设计考虑到了数据不完全存储在内存中的情况,这包括了表格数据和查询结果。为了应对这种情况,磁盘导向的DBMS依赖于缓冲池(buffer pool)来管理内存和磁盘之间的数据交换。这意味着当数据无法全部装入内存时,DBMS需要使用特定算法将部分数据暂时存储到磁盘上。
此外,这类DBMS倾向于采用那些能最大化顺序I/O(输入/输出)操作的算法。顺序I/O比随机I/O在速度上更有优势,因为磁盘读写顺序数据时的效率远高于读写散乱数据。尤其是在处理大量数据时,通过优化I/O操作,磁盘导向的DBMS能够显著提高数据处理的效率。
一、外部排序(External Merge Sort)
(略)见数据结构
二、聚集(Aggregations)
在磁盘导向的数据库管理系统中,聚集(Aggregation)是一种常见的操作,它将来自多个元组的单一属性值汇总成一个标量值。实现聚集操作主要有两种方式:排序(Sorting)和哈希(Hashing)。
- 排序(Sorting): 通过将数据按照某个或某些属性进行排序,使具有相同聚集键的元组相邻,然后进行遍历,对这些相邻的元组进行聚集计算。排序优势在于能够有效地进行范围查询和顺序访问,但排序操作本身可能较为耗时,特别是对于大量数据。
- 哈希(Hashing): 使用哈希表将具有相同聚集键的元组分组在一起。对每个唯一的聚集键,都创建一个哈希桶,并将对应键的元组加入到相应的桶中,然后对每个桶中的元组进行聚集计算。哈希方法对于等值查询非常高效,但可能不如排序那样适合范围查询。
选择哪种实现方式取决于具体的应用场景、数据的特性以及查询的类型。排序方法在处理有序数据或者需要输出有序结果时更为优越,而哈希方法在处理等值连接或者需要高效处理大量散列数据时更为有效。在磁盘导向的DBMS中,考虑到磁盘I/O的成本,选择最适合当前数据和查询需求的聚集实现方式尤为重要。
排序聚集
数据库通过排序来执行聚集操作的查询通常包括以下几个详细步骤:
- 查询解析(Query Parsing): 数据库首先解析SQL查询指令,理解其结构和需求,如需选择哪些列,过滤条件是什么,以及需要哪种类型的聚集。
- 筛选数据(Filter): 根据查询条件,数据库引擎搜索存储在磁盘上的表,找出满足条件的记录。例如,在图中展示的查询中,数据库会查找所有成绩为'B'或'C'的记录。
- 投影(Projection): 数据库将筛选出的记录中不需要的列移除,只保留对完成查询必要的列,也就是移除列(Remove Columns)。在这个案例中,它会移除sid和grade列,仅保留cid列。
- 排序(Sorting): 然后,数据库将剩下的记录按照聚集操作的键(这里是cid)进行排序。排序是为了将所有相同的cid值放置在一起,从而便于后续的聚集操作。
- 聚集处理(Aggregating): 排序后,数据库可以容易地通过遍历记录来合并或计算重复的cid值。在这个例子中,因为SQL查询使用了SELECT DISTINCT关键字,聚集操作将会消除消除重复项(Eliminate Dupes)。
- 生成结果集(Generating Result Set): 最后,数据库将聚集的结果集返回给用户。在这个查询中,最终结果是一个包含了不重复cid值的列表,按照cid排序。
在整个过程中,数据库可能会使用内部优化,例如索引,以加速排序和过滤步骤。如果数据集很大,不能完全放入内存中,数据库可能会使用外部排序算法,该算法涉及将数据分割成块,分别排序,然后合并。这样的聚集查询对磁盘I/O效率有高要求,因此数据库设计时会尽可能减少对磁盘的随机访问,倾向于使用顺序访问以提高查询效率。
哈希聚集(Hashing)
在数据库查询处理中,排序操作经常被用于GROUP BY聚集和DISTINCT去重等操作。然而,当数据不需要有序排列时,哈希(Hashing)提供了一个更高效的替代方案。
不需要排序的场景
- GROUP BY聚集:当仅需要将数据分组而不需要对结果进行排序时,哈希聚集可以直接将相同的键值分组,进行聚集计算,无需事先排序。
- DISTINCT去重:在去除重复数据时,与其对数据进行排序以识别重复项,不如使用哈希表来高效地识别和去除重复项。
哈希聚集(Hashing Aggregate)
特点
哈希聚集通过在数据库管理系统(DBMS)扫描表时填充一个临时哈希表来实现。对于每条记录,DBMS检查哈希表中是否已经存在相应的条目:
- DISTINCT:如果发现重复的条目,则丢弃,仅保留唯一项。
- GROUP BY:如果存在相同键值的条目,则对这些条目执行聚集计算。
内存与磁盘数据管理
- 内存中操作:如果整个数据集和哈希表可以完全适配于内存,则哈希聚集操作相对简单直接。
- 溢出到磁盘:当数据集太大,无法完全放入内存时,DBMS需要采取更智能的策略来管理内存和磁盘之间的数据溢出。这可能包括使用分区哈希(Partitioned Hashing)等技术,将数据集分割成小块,分别进行处理。
哈希的优势
- 性能:在不需要数据排序的场景下,哈希聚集可以提供比排序更高的性能,尤其是对于大数据集的处理。
- 计算成本:哈希操作的计算成本通常低于排序,特别是当数据集很大且仅需去重或聚集计算时。
外部哈希聚集(External Hashing Aggregate)
在数据库系统中处理大规模数据聚集和去重任务时,外部哈希聚集(External Hashing Aggregate)提供了一种有效的方法。这种方法特别适用于无法将全部数据装入内存的情况。外部哈希聚集通常包含两个阶段:分区(Partition)和重新哈希(ReHash)。
使用哈希函数 h 将元组分割成磁盘上的分区的过程涉及以下几个步骤:
- 哈希函数的应用:哈希函数 h 被用来处理每个元组的键值,根据这个键值的哈希结果将元组分配到不同的分区中。每个分区可以包含一个或多个页面,这些页面存储了具有相同哈希值的键集合。
- 分区与缓冲区:当元组被哈希函数处理并分配到相应的分区后,这些分区会通过输出缓冲区“溢出”到磁盘上。假设我们有 B 个缓冲区,我们将使用 B-1 个缓冲区来存储这些分区,而另外 1 个缓冲区用于输入数据的处理。
外部哈希聚集的优势:
- 适应大数据集:当数据集过大而无法完全放入内存时,外部哈希聚集允许数据库系统有效地处理这些数据,通过分区和重新哈希来分散内存需求。
- 减少I/O操作:通过优化分区策略和内存管理,此方法旨在最小化对磁盘的I/O操作,从而提高查询性能。
通过这种方式,数据库管理系统可以高效地组织和存储大量数据。哈希函数确保数据均匀分布在各个分区中,这有助于优化查询性能,这种方法特别适用于处理大型数据集,因为它可以更快地定位到包含特定键的分区,能够减少对磁盘的访问次数,提高数据处理的效率。
第一阶段:分区(Partition)
- 基于哈希键分桶:根据哈希函数h,将元组(tuples)根据哈希键值分配到不同的桶(buckets)中。
- 磁盘写出:当一个桶满了之后,将这些数据写出到磁盘。每个桶会形成一个或多个包含具有相同哈希值键的数据集的分区。数据落盘前可以提前distinct。
- 使用缓冲区管理:假设有B个缓冲区,其中B-1个用于存储各个分区的数据,剩下一个用于输入数据。
第二阶段:重新哈希(ReHash)
原因:
- 磁盘中哈希表太大,distinct未全部完成
- 单个哈希函数容易发生碰撞
- 为每个分区构建内存哈希表:对于磁盘上的每个分区,读取其数据到内存中,并基于第二个哈希函数h2构建一个内存哈希表。
- 聚集计算:遍历这个哈希表的每个桶,将匹配的元组汇总在一起进行聚集计算。
- 内存要求:这个阶段假设每个分区的数据量足够小,能够完全适配于内存。
第三阶段:哈希汇总
- 插入新元组:当我们想要向哈希表中插入一个新的元组时,会发生以下两种情况之一:
- 如果找到一个匹配的 GroupKey,只需要适当地更新 RunningVal。
- 如果没有找到匹配的 GroupKey,则插入一个新的 GroupKey->RunningVal 键值对。
在这个过程中,数据库有效地对数据进行汇总。GroupKey 代表了需要进行分组的键,而 RunningVal 是对应于该 GroupKey 的累计值,是一个中间结果。此过程类似于mapreduce。通过这种方式,数据库可以高效地对大量数据进行分组和汇总处理,对于需要进行快速数据聚合查询的应用场景尤为重要。
在数据库操作中,哈希汇总(Hashing Summarization)是一种处理聚集查询的技术,特别是在处理分组(GROUP BY)和聚集函数(如SUM、COUNT等)时。这种技术使用哈希表来高效地计算每个分组的聚集值。在聚集过程中的一个关键步骤是重新哈希(ReHash)阶段,其操作如下:
- 创建哈希表:首先,创建一个哈希表,用于存储键值对,其中键(GroupKey)是根据聚集查询中的分组条件确定的,值(RunningVal)是当前分组的聚集值。
- 处理新元组:当新的数据元组(行)进入系统时,会根据分组条件计算它的GroupKey。
- 在哈希表中查找GroupKey:
-
- 如果哈希表中已存在该GroupKey,这意味着之前已有元组被归入了这个分组。此时,只需根据聚集函数更新RunningVal。例如,如果聚集函数是SUM,那么就将新元组的相应值加到RunningVal上。
- 如果哈希表中不存在该GroupKey,这意味着这是这个分组的第一个元组。此时,需要在哈希表中插入一个新的键值对,键是GroupKey,值是这个元组的聚集值(对于SUM,就是这个元组的值;对于COUNT,初始值可能是1等)。
- 重复处理直至完成:对所有数据元组重复以上步骤,直至所有数据都被处理完毕。
- 从哈希表中提取结果:最终,哈希表中的每个键值对代表一个分组及其聚集值。这些键值对就是聚集查询的结果。
使用哈希汇总的优点包括:
- 高效性:哈希表提供了非常快速的查找和更新操作,这使得处理大量分组时能保持较高的效率。
- 灵活性:这种方法适用于多种聚集函数,如SUM、COUNT、AVG等。
- 适用性:即使是在数据量非常大的情况下,哈希汇总也能有效地工作,尤其是在内存足够容纳哈希表的情况下。
然而,这种方法也有其局限性,特别是当内存不足以容纳全部的GroupKey时,可能需要额外的策略来处理内存溢出,比如使用外部排序或将哈希表分割成多个部分(分区)。
总结来说,在数据库操作中,尤其是涉及到聚集计算和去重时,如果不需要数据有序,哈希聚集提供了一种计算成本较低且执行速度更快的替代方案。通过有效利用内存和磁盘资源,哈希聚集能够高效地处理大规模数据集,优化数据库查询性能。
三、总结
排序与聚集的选择依据
- 数据量和内存限制:对于内存足够容纳全部数据的情况,内存哈希通常提供更好的性能。对于大数据集,外部哈希和排序都是可行的选择,但具体优劣取决于具体的查询需求和数据特性。
- 查询需求:如果查询需要有序数据,排序是必须的。如果查询仅涉及分组和去重,哈希会是更优的选择。
- 数据访问模式:顺序访问模式更适合排序,而随机访问模式可能更倾向于使用哈希,因为哈希表对于键值查找非常高效。