预测 SQL 降级

 SQL  语言明显是非过程化的语言:您只需指定想要的数据,而不必关心如何获取数据。数据库优化器将决定获取所需数据的最佳方式。然而,优化器并不是完美的,开发人员或  DBA  经常需要对欠佳的优化器决策进行更正。并且优化器不能对数据库设计或实施缺陷(例如缺少索引)加以弥补。

这样,SQL 调整便成了数据库优化中最重要的因素之一。调整 SQL  的传统流程是,先通过基准测试或生产监控来识别需要调整的  SQL  语句。然后使用各种工具来诊断根本原因(可能是缺少索引或  SQL  语法反模式)。最后对生产部署解决方案。在 Quest,我们将这一流程称为“检测-诊断-解决”(DDR) 工作流。

虽然 DDR 永远是必要的活动,但我们在改进 DDR 工作流的同时实际上是在减少投资回报。主要原因是,对 SQL 优化器的改进减少了“琐碎”SQL       问题的数量。在不能说话的优化器时代,编写不佳的  SQL  语句可能会因无法利用索引(例如)而导致大幅降级。现今的优化器由于采用了适应性强的脱机优化策略,因此很少发生这些问题。剩余问题则需要特殊的解决方案,例如在生产中新建索引、分区或反规范化。生产系统需要足够的提前期来部署这些性能解决方案,并且实施这些解决方案所需的停机时间也会随底层数据量的增长而增长。因此,我们需要将重心从提高反应性地调整 SQL 的能力转移到更有效地预测 SQL  问题并在问题发生前将其修正上来。

典型 SQL 性能模式

SQL 语句的执行分为多个步骤,其中每个步骤通常都遵循数据容量与执行时间之间的清晰关系。有时用“大  O ”表示法 1 来表示这些关系。对于数据库操作,我们通常会使用以下表示法:

     *  O(1):常量。无论所涉及的底层数据量是多少,操作所需的时间相同。良好构造的哈希索引使用的就是此关系。

     *  O(n):线性。随着数据量的增加,执行时间也相应地增加。完全表扫描和非唯一索引扫描使用的就是此模式。

     *  O(log n):对数。执行时间随数据量增加,但增加速度越来越低。基本上,基于索引的唯一值查找使用的就是此模式。

     *  O(nx):指数。执行时间随数据量增加,且增加速度越来越快。嵌套扫描使用的就是此模式(对于集合 A  中 的每一列,都会扫描集合 B 中的所有列以查找匹配)。

查看大图

图 2. 各种“大 O”表示法的性能特性。

现实的 SQL 方案表示多个执行步骤间的交互,其中每个步骤可能都遵循一种“大 O”表示法。然而在高水平上,某个模式通常会占主导地位。例如,在与  B-树索引查找相配的嵌套表扫描中,嵌套表扫描的指数特性将超过索引查找的对数特性,从而占据主导地位。

数据量与执行速率的相互作用

随着供应商对其 SQL  查询优化层进行改进以及采用更加有效率的访问算法,指数 SQL  性能模式越来越少见。虽然指数模式仍然存有一席之地,但如今它们经常与欠佳的索引决策(而不是欠佳的优化代码)联系在一起。

然而,当数据量和执行速率同时增长时,对底层数据显示出线性执行模式的 SQL 仍显示出指数级的资源消耗,并且在增长应用程序中,这两个因素都很常见。