📜  关系代数中的查询优化

📅  最后修改于: 2021-09-10 02:11:48             🧑  作者: Mango

查询:查询是对数据库信息的请求。

查询计划:查询计划(或查询执行计划)是一组有序的步骤,用于访问 SQL 关系数据库管理系统中的数据。

查询优化:单个查询可以通过不同的算法执行或以不同的形式和结构重写。因此,查询优化的问题就出现了——这些形式或途径中哪一种是最优化的?查询优化器尝试通过考虑可能的查询计划来确定执行给定查询的最有效方式。

重要性:查询优化的目标是减少完成查询所需的系统资源,最终更快地为用户提供正确的结果集。

  • 首先,它为用户提供更快的结果,这使得应用程序在用户看来更快。
  • 其次,它允许系统在相同的时间内为更多的查询提供服务,因为每个请求比未优化的查询花费的时间更少。
  • 第三,查询优化最终会减少硬件(例如磁盘驱动器)的磨损量,并允许服务器更有效地运行(例如更低的功耗、更少的内存使用)。

有两种方法可以优化查询:

  1. 分析和转换等效的关系表达式:尝试最小化中间和最终查询过程的元组和列数(此处讨论)。
  2. 对每个操作使用不同的算法:这些底层算法确定如何从存储元组的数据结构、索引、散列、数据检索中访问元组,从而影响磁盘和块访问的数量(在查询处理中讨论)。

分析和转换等效的关系表达式。
在这里,我们将讨论生成最小等效表达式。为了分析等价表达式,列出了一组等价规则。这些为用关系代数编写的查询生成等效表达式。为了优化查询,只要满足等价规则,我们就必须将查询转换为其等价形式。

  1. 连接选择操作可以写成一系列单独的选择。这称为 sigma-cascade。

    \sigma_{\theta_{1}\Lambda\theta_{2} }(E)=\sigma_{\theta_{1}}(\sigma_{\theta_{2}}(E))

    说明:申请条件\theta_{1}  路口\theta_{2}  价格昂贵。相反,过滤掉满足条件的元组\theta_{2}  (内部选择)然后应用条件\theta_{1}  (外部选择)到然后产生更少的元组。这让我们第二次处理的元组更少。这可以扩展为两个或多个交叉选择。由于我们将单个条件分解为一系列选择或级联,因此称为“级联”。

  2. 选择是可交换的。
    \sigma_{\theta_{1}}(\sigma_{\theta_{2}}(E))=\sigma_{\theta_{2}}(\sigma_{\theta_{1}}(E))

    解释: \sigma  条件本质上是可交换的。这意味着,我们是否申请并不重要\sigma_{1}  首先或\sigma_{2}  第一的。在实践中,最好先应用该选择,从而产生较少数量的元组。这节省了我们外部选择的时间。

  3. 后面所有的投影都可以省略,只需要第一个投影。这称为 pi 级联。
    \pi_{L_{1}}(\pi_{L_{2}}(...(\pi_{L_{n}}(E))...)) = \pi_{L_{1}}(E)

    解释:级联或一系列投影是没有意义的。这是因为最后,我们只选择在最后或最外层投影中指定的那些列。因此,最好将所有投影折叠成一个,即最外面的投影。

  4. 笛卡尔积的选择可以重写为 Theta Joins。
    • 等价 1
      \sigma_{\theta}(E_{1} \times E_{2}) = E_{1} \bowtie_{\theta} E_{2}

      说明:众所周知,叉积操作非常昂贵。这是因为它将 E1 的每个元组(总共 m 个元组)与 E2 的每个元组(总共 n 个元组)匹配。这会产生 m*n 个条目。如果我们在此之后应用选择操作,我们将不得不扫描 m*n 个条目以找到满足条件的合适元组\theta  .与其执行所有这些操作,不如使用 Theta Join,这是一种专门设计用于仅选择叉积中满足 Theta 条件的条目的联接,而无需先评估整个叉积。

    • 等价 2
      \sigma_{\theta_{1}}(E_{1} \bowtie_{\theta_{2}} E_{2}) = E_{1} \bowtie_{\theta_{1} \Lambda \theta_{2}} E_{2}

      说明: Theta Join 从根本上减少了结果元组的数量,所以如果我们应用两个连接条件的交集,即\theta_{1}  \theta_{2}  进入 Theta Join 本身,我们需要做的扫描更少。另一方面,一个\sigma_{1}  外部条件不必要地增加了要扫描的元组。

  5. Theta Join 是可交换的。
    E_{1} \bowtie_{\theta} E_{2} = E_{2} \bowtie_{\theta} E_{1}

    说明: Theta Joins是可交换的,查询处理时间在某种程度上取决于join过程中哪个表用作外循环,哪个表用作内循环(基于索引结构和块)。

  6. 联接操作是关联的。
    • 自然连接
      (E_{1} \bowtie E_{2}) \bowtie E_{3} = E_{1} \bowtie (E_{2} \bowtie E_{3})

      说明:联接都是可交换的和关联的,因此必须先联接产生较少条目数的两个表,然后再应用另一个联接。

    • 西塔连接
      (E_{1} \bowtie_{\theta_{1}} E_{2}) \bowtie_{\theta_{2} \Lambda \theta_{3}} E_{3} = E_{1} \bowtie_{\theta_{1} \Lambda \theta_{3}} (E_{2} \bowtie_{\theta_{2}} E_{3})

      说明: Theta Joins 以上述方式关联,其中\theta_{2}  仅涉及来自 E2 和 E3 的属性。

  7. 选择操作可以是分布式的。
    • 等价 1
      \sigma_{\theta_{1}\Lambda\theta_{2}}(E_{1}\bowtie_{\theta}E_{2})=(\sigma_{\theta_{1}}(E_{1}))\bowtie_{\theta}(\sigma_{\theta_{2}}(E_{2}))

      说明:在执行 Theta Join 后应用选择会导致 Theta Join 返回的所有元组在 join 后受到监控。如果此选择仅包含来自 E1 的属性,则最好将此选择应用于 E1(因此导致较少数量的元组),然后将其与 E2 连接。

    • 等价 2
      \sigma_{\theta_{0}}(E_{1}\bowtie_{\theta}E_{2})=(\sigma_{\theta_{0}}(E_{1}))\bowtie_{\theta}E_{2}

      说明:这可以扩展到两个选择条件, \theta_{1}  \theta_{2}  ,其中 Theta1 只包含 E1 的属性,并且\theta_{2}  仅包含 E2 的属性。因此,我们可以在加入之前单独应用选择标准,以大幅减少加入的元组数量。

  8. 投影分布在 Theta Join 上。
    • 等价 1
      \pi_{L_{1}\cup L_{2}}(E_{1}\bowtie_{\theta}E_{2})=(\pi_{L_{1}}(E_{1}))\bowtie_{\theta}(\pi_{L_{2}}(E_{2}))

      说明:为选择而讨论的想法也可用于投影。这里,如果 L1 是一个只涉及 E1 列的投影,而 L2 是另一个只涉及 E2 列的投影,那么最好在连接之前分别对两个表应用投影。这让我们在每一侧都有更少的列,因此有助于更容易地连接。

    • 等价 2
      \pi_{L_{1}\cup L_{2}}(E_{1}\bowtie_{\theta}E_{2})=\pi_{L_{1}\cup L_{2}}((\pi_{L_{1}\cup L_{3}}))\bowtie_{\theta}(\pi_{L_{2}\cup L_{4}}(E_{2})))

      说明:这里,当在连接上应用投影 L1 和 L2 时,其中 L1 仅包含 E1 的列,L2 仅包含 E2 的列,我们可以引入另一列 E3(这两个表之间是通用的)。然后,我们可以分别在 E1 和 E2 上应用投影 L1 和 L2,以及添加的列 L3。 L3 使我们能够进行连接。

  9. Union 和 Intersection 是可交换的。
    E_{1}\ \cup E_{2}\ =\ E_{2}\ \cup\ E_{1}
    E_{1}\ \cap E_{2}\ =\ E_{2}\ \cap\ E_{1}

    解释:并和交都是分布的;我们可以根据需要和易于访问将任何表格括在括号中。

  10. Union 和 Intersection 是关联的。
    (E_{1}\ \cup E_{2})\ \cup\ E_{3}=E_{1}\ \cup\ (E_{2}\ \cup\ E_{3})
    (E_{1}\ \cap E_{2})\ \cap\ E_{3}=E_{1}\ \cap\ (E_{2}\ \cap\ E_{3})

    解释:并和交都是分布的;我们可以根据需要和易于访问将任何表格括在括号中。

  11. 选择操作分布在并、交和差操作上。
    \sigma_{P}(E_{1}\ -\ E_{2})=\sigma_{P}(E_{1})\ -\ \sigma_{P}(E_{2})

    说明:在集合差异中,我们知道只显示属于表 E1 而不属于表 E2 的那些元组。因此,对整个集差应用选择条件等同于对单个表应用选择条件,然后应用集差。这将减少设置差异步骤中的比较次数。

  12. 投影操作分布在联合操作上。
    \pi_{L}(E_{1}\ \cup\ E_{2})=(\pi_{L}(E_{1}))\ \cup\ (\pi_{L}(E_{2}))

    说明:在计算 E1 和 E2 的并集之前应用单个投影比左表达式更优化,即在并集步骤之后应用投影。

极简——
如果不能从其他规则的任何组合中导出规则,则称一组等价规则是最小的。一个查询在最小时被认为是最优的。

例子 –
假设有以下表格:

instructor(ID, name, dept_name, salary)
teaches(ID, course_id, sec_id, semester, year)
course(course_id, title, dept_name, credits)

查询 1:查找音乐系所有教师的姓名,以及他们教授的课程名称

$\pi_{name, title}(\sigma_{dept\_name=``Music"}(instructor \bowtie (teaches \bowtie \pi_{course\_id, title}(course))))$

此处,dept_name 仅是教师表的一个字段。因此,我们可以在加入表之前选择音乐教师,从而减少查询时间。

优化查询:
使用规则 7a 并尽可能早地执行选择可以减小要连接的关系的大小。
$\pi_{name, title}((\sigma_{dept\_name=``Music"(instructor)}\bowtie(teaches\bowtie\pi_{course\_id, title}(course)))$

查询 2:查找 CSE 部门所有在 2009 年教过课程的教师的姓名,以及他们教过的课程的名称

$\sigma_{dept\_name=``CSE"}(\sigma_{year=2009}(instructor\bowtie teaches))$

优化查询:
我们可以执行“早期选择”,因此优化后的查询变为:
$\sigma_{dept\_name=``CSE"}(instructor)\bowtie \sigma_{year=2009}(teaches)$