【数据库原理】(22)查询优化方法

发布时间:2024年01月11日

一.代数优化

代数优化是查询优化的关键环节之一,涉及到基于关系代数表达式的转换和改进。这些表达式通常在查询处理过程中,由查询分析和检查步骤生成。通过应用一系列代数规则和启发式方法,代数优化的目标是找到一个成本最低的执行计划。

1.关系代数表达式变换规则

以下是一些关系代数表达式变换的基本规则,它们是代数优化过程中常用的工具:

  1. 交换律(Commutativity):连接和笛卡儿积操作满足交换律,即改变操作顺序不会影响结果。

    • 笛卡儿积交换律: E 1 × E 2 = E 2 × E 1 E_1 \times E_2 = E_2 \times E_1 E1?×E2?=E2?×E1?
    • 自然连接交换律: E 1 ? E 2 = E 2 ? E 1 E_1 \bowtie E_2 = E_2 \bowtie E_1 E1??E2?=E2??E1?
    • 自然连接交换律: E 1 ? F E 2 = E 2 ? F E 1 E_1 \bowtie_F E_2 = E_2 \bowtie_F E_1 E1??F?E2?=E2??F?E1?
  2. 结合律(Associativity):连接和笛卡儿积还满足结合律,允许我们在不改变结果的情况下,重新组织操作的结合方式。

    • 笛卡儿积结合律: ( E 1 × E 2 ) × E 3 = E 1 × ( E 2 × E 3 ) (E_1 \times E_2) \times E_3 = E_1 \times (E_2 \times E_3) (E1?×E2?)×E3?=E1?×(E2?×E3?)
    • 自然连接结合律: ( E 1 ? E 2 ) ? E 3 = E 1 ? ( E 2 ? E 3 ) (E_1 \bowtie E_2) \bowtie E_3 = E_1 \bowtie (E_2 \bowtie E_3) (E1??E2?)?E3?=E1??(E2??E3?)
    • 条件连接结合律: ( E 1 ? F 1 E 2 ) ? F 2 E 3 = E 1 ? F 1 ( E 2 ? F 2 E 3 ) (E_1 \bowtie_{{F}_1} E_2) \bowtie_{{F}_2} E_3 = E_1 \bowtie_{{F}_1} (E_2 \bowtie_{{F}_2} E_3) (E1??F1??E2?)?F2??E3?=E1??F1??(E2??F2??E3?)
  3. 选择操作串接定律(Cascading of Selection):选择操作可以串接执行,且可以按任何顺序进行。合取条件(AND连接的条件)可以分解为多个选择操作。

    • 选择运算顺序交换定律: σ F 1 ( σ F 2 ( E ) ) = σ F 2 ( σ F 1 ( E ) ) \sigma_{F1}(\sigma_{F2}(E)) = \sigma_{F2}(\sigma_{F1}(E)) σF1?(σF2?(E))=σF2?(σF1?(E))
    • 合取条件分解定律: σ F 1 ∧ F 2 ( E ) = σ F 1 ( E ) ∩ σ F 2 ( E ) \sigma_{F1 \land F2}(E) = \sigma_{F1}(E) \cap \sigma_{F2}(E) σF1F2?(E)=σF1?(E)σF2?(E)
  4. 投影操作串接定律:如果投影的属性集是另一个投影属性集的子集,那么这两个投影操作可以合并为一个。

    • π A 1 , A 2 , . . . , A n ( π B 1 , B 2 , . . . , B m ( E ) ) = π A 1 , A 2 , . . . , A n ( E ) , 当 ( A i ? B j ) \pi_{A1, A2, ..., An}(\pi_{B1, B2, ..., Bm}(E)) = \pi_{A1, A2, ..., An}(E) ,当 (A_i \subseteq B_j) πA1,A2,...,An?(πB1,B2,...,Bm?(E))=πA1,A2,...,An?(E),(Ai??Bj?)
  5. 选择与其他操作的交换律(Commutation with Other Operations):在某些情况下,选择操作可以与笛卡儿积、投影和连接操作交换,使得可以先对小的数据集进行筛选,减少后续操作的数据量。

    • 选择与笛卡儿积: σ F ( E 1 × E 2 ) = ( σ F ( E 1 ) ) × E 2 \sigma_{F}(E_1 \times E_2) = (\sigma_{F}(E_1)) \times E_2 σF?(E1?×E2?)=(σF?(E1?))×E2? 如果 (F) 中涉及的属性都是 ( E 1 E_1 E1?) 中的属性

    • 选择与投影: σ F ( π A ( E ) ) = π A ( σ F ( E ) ) \sigma_{F}(\pi_{A}(E)) = \pi_{A}(\sigma_{F}(E)) σF?(πA?(E))=πA?(σF?(E)) 如果 (F) 只涉及 (A) 的属性

  6. 分配律(Distributivity):选择操作对于并集和自然连接操作具有分配性质,而投影操作对于笛卡儿积和并操作具有分配性质。

    • 选择与并运算: σ F ( E 1 ∪ E 2 ) = σ F ( E 1 ) ∪ σ F ( E 2 ) \sigma_{F}(E_1 \cup E_2) = \sigma_{F}(E_1) \cup \sigma_{F}(E_2) σF?(E1?E2?)=σF?(E1?)σF?(E2?)
    • 选择与差运算: σ F ( E 1 ? E 2 ) = σ F ( E 1 ) ? σ F ( E 2 ) \sigma_{F}(E_1 - E_2) = \sigma_{F}(E_1) - \sigma_{F}(E_2) σF?(E1??E2?)=σF?(E1?)?σF?(E2?)
    • 选择与自然连接: σ F ( E 1 ? E 2 ) = ( σ F ( E 1 ) ) ? ( σ F ( E 2 ) ) \sigma_{F}(E_1 \bowtie E_2) = (\sigma_{F}(E_1)) \bowtie (\sigma_{F}(E_2)) σF?(E1??E2?)=(σF?(E1?))?(σF?(E2?)) 如果 (F) 只涉及共同属性

这些变换规则的应用使得我们能够将复杂的查询表达式转换为一系列更高效的操作步骤。例如,将大型表的连接操作推迟,先对小型表执行选择和投影操作,可以大幅降低查询成本。

代数优化的目标

代数优化的最终目标是减少查询过程中的磁盘I/O操作,因为磁盘访问通常是数据库操作中最耗时的部分。此外,优化器还试图减少中间结果的大小,以及减少CPU计算的复杂性。

在实际的DBMS中,代数优化通常是自动进行的。优化器会根据数据库的统计信息,如表的大小、索引的存在与否以及数据的分布特征等,来选择最佳的执行计划。然而,数据库管理员和有经验的用户可以通过查询重写或者使用特定的查询提示,来辅助或指导优化器的选择。

总的来说,代数优化是查询优化不可或缺的一环,它确保了数据库系统可以以最高效的方式执行用户的查询请求。

2.查询树的启发式规则

启发式规则

  1. 选择操作优先原则:这一规则的基础在于,早期过滤掉不相关的数据可以显著减少后续操作处理的数据量。通过在查询的早期应用选择(过滤)条件,可以避免对不需要的数据进行复杂的运算。

  2. 投影操作优先原则:与选择操作类似,投影(确定需要哪些列)操作也应尽早进行,以减少处理数据的宽度,特别是在进行连接操作之前。

  3. 笛卡儿积合并规则:笛卡儿积(Cartesian product)会生成大量的中间结果,往往是不必要的。因此,应该尽量将笛卡儿积与其他操作如选择和投影合并,减少中间结果的生成。

  4. 提取公共表达式规则:如果某个计算在多个地方重复进行,而这个计算的结果集较小,那么应该计算一次并将结果缓存起来,供后续操作使用。

应用示例

假设我们要从数据库中检索所有选修了编号为’02’的课程的学生姓名。SQL查询语句可能如下所示:

SELECT S.Sname FROM S, SC WHERE S.Sno = SC.Sno AND SC.Cno = '02';

在未优化的情况下,数据库可能会先执行笛卡儿积,然后再应用选择条件,这种方法效率极低。应用启发式规则后,我们可以优化查询执行计划,如下所示:

  1. 选择操作优先:首先,我们应用选择条件SC.Cno = '02'来过滤SC表,这样可以减少后续操作的数据集大小。

  2. 投影操作优先:其次,我们只选择S.SnameS.Sno,以及满足条件的SC.Sno,进一步减少数据的宽度。

  3. 合并笛卡儿积:我们在选择操作之后立即执行连接操作,这避免了不必要的大量中间数据的生成。

  4. 提取公共表达式:如果SC.Cno = '02'是一个常见的查询条件,我们可以将其结果缓存以供后续查询快速使用。

优化后的查询执行计划如下:

SELECT S.Sname FROM S JOIN SC ON S.Sno = SC.Sno WHERE SC.Cno = '02';

在这个优化的查询计划中,我们首先对SC表应用了选择条件,然后只在这个过滤后的结果集上执行连接操作。这种策略将极大地提高查询的效率。

通过这些例子,我们可以看出,合理的查询优化能够在数据库系统中带来巨大的性能提升。这一过程通常是自动完成的,用户不必担心底层的执行细节,但是了解这些优化原理有助于写出更高效的查询语句。

二.物理优化

物理优化是查询优化中的一个重要环节,它涉及到底层的数据存取方法和执行算法的选择。目的是通过选择最有效的存取路径和操作算法,以减少查询执行时的资源消耗和提高查询速度。物理优化通常包括基于启发式规则的优化和基于代价估计的优化。

1.基于启发式规则的存取路径选择优化

在物理优化中,启发式规则提供了一组经验法则,它们可以在没有详细统计信息时快速指导存取路径的选择。

  1. 选择操作的启发式规则

    • 对于小关系的查询,全表扫描往往是最快的,即使存在索引。
    • 对于主键等值查询,通常使用主键索引,因为结果最多只有一个元组。
    • 对于非主属性的等值查询,若存在索引并且预期返回的元组数量较少(小于总数的10%),应考虑使用索引扫描;否则,使用全表扫描可能更高效。
    • 对于非等值或范围查询,如果结果集很小并且有索引,同样应优先考虑索引扫描。
    • 对于有 AND 连接的多条件查询,如果有涉及多个条件的复合索引,优先使用该复合索引。
    • 对于 OR 连接的查询,通常使用全表扫描。
  2. 连接操作的启发式规则

    • 如果两个表都已经按连接属性排序,应使用排序-合并连接。
    • 如果其中一个表在连接属性上有索引,则索引连接通常是首选。
    • 如果两个表都很大并且没有索引优势,可以考虑使用哈希连接(Hash Join)。
    • 如果上述规则都不适用,考虑使用嵌套循环连接(Nested Loop Join),尤其是当一个表远小于另一个表时。

2.基于代价估计的优化

假设我们有一个简单的查询:从Employees表中检索所有部门为“Sales”的员工记录。我们的数据库包含以下统计信息:

  • Employees 表共有B个数据块。
  • 每个数据块可以包含R条记录。
  • 部门列有一个非聚簇索引。

信息统计

基于代价的优化方法要计算每种操作算法的执行代价,这就需要知道数据库的状态,包括:

  • 表的元组总数( N )。
  • 表的元组平均长度( L )。
  • 表占用的数据块数( B )。
  • 每个字段不同值的个数( m )。
  • 字段选择率( s )。
  • 索引的层数( L )。
  • 索引的选择基数( S )。

估算代价

在上述信息的基础上,查询优化器可以采用以下算法来估计执行查询的代价:

  1. 全表扫描算法代价的估算:

    • 代价 ( cost = B )
    • 如果选择条件是“主码=值”,则平均搜索代价 ( c o s t = B 2 cost = \frac{B}{2} cost=2B? )。
  2. 索引扫描算法代价的估算:

    • 如果选择条件是“码=值”,则采用该表的主索引,若为B+树,层数为L,那么代价 ( cost = L + 1 )。
  3. 嵌套循环连接算法代价的估算:

    • 对于两个表的嵌套循环连接,如果其中一个表较小,则可以将较小的表放在内循环中,代价 ( c o s t = B r + B r × B s K ? 1 cost = B_{r} + \frac{B_{r} \times B_{s}}{K - 1} cost=Br?+K?1Br?×Bs?? )。
  4. 排序-合并连接算法代价的估算:

    • 如果连接的表已经按照连接属性排好序,则代价 ( c o s t = B r + B s + F r s × N r × N s M r s cost = B_{r} + B_{s} + \frac{F_{rs} \times N_{r} \times N_{s}}{M_{rs}} cost=Br?+Bs?+Mrs?Frs?×Nr?×Ns?? )。

其中:

  • ( B r B_{r} Br? ) 和 ( B s B_{s} Bs? ) 分别是两个连接表占用的数据块数。
  • ( K ) 是内存中可用于存储数据块的数量。
  • ( F r s F_{rs} Frs? ) 是连接选择性,代表连接结果元组数的比例。
  • ( M r s M_{rs} Mrs? ) 是存放连接结果的块因子,表示每块中可以存放的结果元组数目。

示例:代价估计的实际应用

假设Employees表有1000个数据块,部门列的非聚簇索引有3层,我们想用这个索引来快速定位“Sales”部门的员工。

  1. 全表扫描的代价估计:

    • 代价 ( c o s t f u l l _ s c a n = 1000 cost_{full\_scan} = 1000 costfull_scan?=1000 )
  2. 索引扫描的代价估计:

    • 代价 ( c o s t i n d e x _ s c a n = 3 + 1 = 4 cost_{index\_scan} = 3 + 1 = 4 costindex_scan?=3+1=4 ) (假设索引扫描直接定位到所需的记录)

如果选择“Sales”部门的员工比例小于10%,索引扫描会是更有效的方法,因此选择它作为我们的查询策略。在更复杂的查询中,会有更多的因素需要考虑,例如连接操作、并行执行等。

文章来源:https://blog.csdn.net/qq_40951951/article/details/135531908
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。