【连载】关系型数据库是如何工作的?(19) - 查询管理器之贪婪算法

来源:互联网 发布:怎么用vs2013写c语言 编辑:程序博客网 时间:2024/04/27 21:19

贪婪算法

对于非常大的查询或者对速度要求很高的查询,还有一种贪婪算法可以应用。

其思想就是应用一个规则(试探或者启发式)来一步步增量的构建执行计划。用这个规则贪婪算法会在有限时间内找到最好的算法(译者注:不是实际意义上最好的,只是说在要求的时间内最好的)。这个算法总是以一个join开始,然后在每一步总是应用相同的规则增加一个join。

我们举一个简单的例子:5张表(A, B, C, D, E)的4次join。为了简化问题,我们采用nested join。我们的规则是:保证join成本最低。

  • 首先我们任意选择一张表开始,假设是A表。
  • 我们计算A表和其他每张表的JOIN成本(A可能是内关系也可能是外关系)。
  • 我们发现A JOIN B成本最低。
  • 然后我计算A JOIN B的结果和剩余每张表的JOIN成本(A JOIN B可能是内关系也可能是外关系)。
  • 我们发现(A JOIN B) JOIN C的成本最低。
  • 然后我们计算(A JOIN B) JOIN C的结果和剩余表JOIN的成本。
  • 最后我们得到了执行计划:(((A JOIN B) JOIN C) JOIN D) JOIN E)。

既然我们可以任意的选择A表开始,那么自然也可能任意的选择B、C、D、E表开始,但我们仍然使用相同的规则。

这个算法有个学名:Nearest neighbor algorithm。

我不会继续深入去讲,但只要采用一个好的建模和排序,这个问题会很容易解决,并且其时间复杂度是O(N*log(N))。这个算法的成本是O(N*log(N))而完全动态计算算法是O(3N),这意味着当你有20个join的时候,成本会从3 486 784 401降为26,差异巨大。

这个算法的一个问题是,如果我们在一个join上增加一个join,我们始终假定找到2张表之间最优的join就会带给我们最低的成本。但是:

  • 即使A JOIN B是A JOIN B and A JOIN C之间成本更低的,
  • 也不能保证(A JOIN B) JOIN C成本比(A JOIN C) JOIN B更低。

为了得到更好的结果,我们可以运行采用不同规则的贪婪算法,择优取之。

其他算法

找寻组好的执行计划对于很多研究人员来说是一个很有诱惑的研究主题。对于特定类型或模式的问题,他们通常会尝试找到更好的算法那。比如:

  • 如果一个查询是星型join(一种特殊的多连接查询),一些数据库会采用特殊的算法。
  • 如果一个查询是并行查询,一些数据库会采用特殊的算法。

有很多其他算法可以在大查询时替换动态编程。贪婪算法归属于启发式算法(试探法)这个大家族。贪婪算法在它在当前找到的结果上不断追加,最终找到结果。一些算法在每一步都遵循一个规则,但它们可能并不保证是当前最好的解决方案,它们就称为启发式算法。

举个例子,贪婪算法遵循一个规则,但在最后一步的最好选择通常不是:

  • 一个方案就能表示一个可能的完整查询计划;
  • 一个方案而是在每一步可能都有P个相同成本的选择方案:
  • 0) P个查询计划是被随机创建的
  • 1) 只有成本最低的那些被保留下来(译者注:所有分支计划一起比较,不仅仅是比较本子分支内的计划
  • 2) 这些成本最低的被继续追加join就会产生P个新的执行计划(译者注:相当于在某次join由于有多个成本相同的选择,所以出现了分支
  • 3) 这P个执行计划后续追加join可能还会继续被拆分,随机变化
  • 4) 所以可能会循环1、2、3步T次
  • 5) 那么最后你会从最后一步的计划中得到最好的那个

循环的次数越多(译者注:其实就是比较的次数),得到的计划越好。这不是一个魔术而是一个简单的自然法则:适者生存。

贪婪算法在PostgreSQL被实现了,但是我不太确定其是否是默认的算法。

还有很多其他被用于数据库的启发式算法,比如:Simulated Annealing, Iterative Improvement, Two-Phase Optimization…但是我不太确定它们是否在企业中是否应用了,还是只是在研究室中。

如果想了解更多的算法,可以参考研究论文:Review of Algorithms for the Join Ordering Problem in Database Query Optimization。

1 0
原创粉丝点击