查询优化器

什么是查询优化器?

Cloud Spanner SQL 查询优化器会将描述查询所需数据的声明式 SQL 语句转换为命令式执行计划,以描述一种精确获取数据的方式。将声明式语句转换为查询执行计划的过程涉及对用于表示查询的树结构执行转换。在生成执行计划的过程中,优化器会保留原始 SQL 查询的逻辑含义,以便返回正确的行。

优化器的另一个重要作用是生成高效的执行计划。

Cloud Spanner 优化器如何生成高效的执行计划?

Cloud Spanner 的优化器结合使用成熟的启发式算法和基于成本的优化来生成高效的计划。一些启发法非常复杂,例如“在远程机器上执行过滤器,而不是将数据拉取到本地机器”。其他启发法更为复杂,但仍具有移动逻辑的原则,使得数据量更接近数据。在将数据分开存放在多台机器中的系统中,该原则尤其重要。

并非所有执行决策都可以通过这样的固定规则来高效做出,因此 Cloud Spanner 的优化器也会根据替代方案的估算成本做出决策。此类成本估算是根据查询的结构、数据库的架构以及由查询片段产生的数据卷估算得出的。例如,Cloud Spanner 会估算 Songs 表中有多少行满足过滤条件 SongGenre = "Country"(如果该过滤条件出现在查询中)。为帮助计算此类估算值,Cloud Spanner 会定期收集有关用户数据的统计信息。

如需详细了解查询执行计划以及 Cloud Spanner 如何使用它们在分布式环境中执行查询,请参阅查询执行计划

查询优化器版本控制

随着时间的推移,查询优化器会不断发展,扩大了查询执行计划中的选项集,并提高了传达这些选择的估算值的准确性,从而产生更高效的查询执行计划。

Cloud Spanner 将以新查询优化器版本的形式发布优化器更新。默认情况下,每个数据库在该版本发布后的 30 天内开始使用最新版本的优化器。

为了让您有更多的控制权,我们推出了用于管理您所用查询的查询优化器版本的功能。在提交到最新版本之前,您可以比较旧版本与最新版本之间的性能配置文件。如需了解详情,请参阅管理查询优化器

查询优化器版本记录

下面总结了在每个版本中对查询优化器进行的更新。

版本 3:2021 年 8 月 1 日(最新和默认)

  • 添加了一种新的联接算法——合并联接(通过使用新的 JOIN METHOD 查询提示值来启用)。

    语句提示:SQL @{join_method=merge_join} SELECT ...

    联接提示:SQL SELECT ... FROM (...) JOIN@{join_method=merge_join} (...)

  • 添加了一种新的联接算法——推送广播哈希联接(通过使用新的 JOIN METHOD 查询提示值来启用)。

    联接提示:SQL SELECT ... FROM (...) JOIN@{join_method=push_broadcast_hash_join} (...)

  • 引入分布式合并联合,适用时,它默认处于启用状态。

  • 当 SELECT 列表中没有 MAX 或 MIN 聚合(或 HAVING MAX/MAX)时,GROUP BY 下的扫描性能有小幅改进。在此更改之前,Spanner 也会加载额外的非分组列,即使查询不需要该列也不例外。

    例如:

    请参考下表:

    CREATE TABLE myTable(
      a INT64,
      b INT64,
      c INT64,
      d INT64)
    PRIMARY KEY (a, b, c);
    

    在此更改之前,以下查询将加载 c 列,即使查询不需要该列也不例外。

    SELECT a, b
    FROM myTable
    GROUP BY a, b
    
  • 当存在联接引入的 CrossApply 运算符且查询要求使用 LIMIT 对结果进行排序时,使用 LIMIT 提高可某些查询的性能。完成此更改后,优化器首先会应用针对 CrossApply 输入端施加限制的排序。

    例如:

    SELECT a2.*
    FROM Albums@{FORCE_INDEX=_BASE_TABLE} a1
    JOIN Albums@{FORCE_INDEX=_BASE_TABLE} a2 USING(SingerId)
    ORDER BY a1.AlbumId
    LIMIT 2;
    
  • 通过 JOIN 推送更多计算来改进查询性能。

    推送更多计算,其中可能包括通过联接进行的子查询或结构体构造。这样一来,可以通过以下几种方式提高查询性能:例如,可以采用分布式方式完成更多计算,而且可以减少依赖于推送的计算的运算。例如,查询具有限制,并且排序顺序取决于这些计算,则也可以通过联接推送该限制。

    例如:

    SELECT
      t.ConcertDate,
      (
        SELECT COUNT(*) FROM UNNEST(t.TicketPrices) p WHERE p > 10
      ) AS expensive_tickets,
      u.VenueName
    FROM Concerts t
    JOIN Venues u ON t.VenueId = u.VenueId
    ORDER BY expensive_tickets
    LIMIT 2;
    

版本 2:2020 年 3 月 1 日

  • 在索引选择中添加优化。
  • 改进了某些情况下 REGEXP_CONTAINSLIKE 谓词的性能。
  • 改进了某些情况下 GROUP BY 下的扫描性能。

版本 1:2019 年 6 月 18 日

  • 包括许多基于规则的优化,例如谓词下推、限制下推、冗余联接和冗余表达式移除等。

  • 使用有关用户数据的统计信息来选择要用于访问每个表的索引。

查询优化器统计信息软件包

Cloud Spanner 会维护表列数据分布的统计信息,以帮助估算查询将生成的行数。查询优化器使用这些估算值来帮助选择最佳查询执行计划。Cloud Spanner 会定期更新这些统计信息。由于统计信息用于选择查询执行计划,因此在更新统计信息时,Cloud Spanner 可能会更改其用于查询的查询计划。

默认情况下,数据库会自动使用最新生成的统计信息软件包。您可以将数据库固定到较早的统计信息软件包版本。您还可以选择使用并非最新的统计信息软件包来运行个别查询。

统计信息软件包的垃圾回收

Cloud Spanner 每 3 天更新一次统计信息软件包。较旧的软件包在创建后会保留 30 天,之后会被垃圾回收。

Cloud Spanner 内置的 INFORMATION_SCHEMA.SPANNER_STATISTICS 表包含可用统计信息软件包的列表。此表中的每一行按名称列出一个统计信息软件包,且名称包含给定软件包的创建时间戳。每个条目还包含一个名为 ALLOW_GC 的字段,用于定义是否可以对软件包进行垃圾回收。

您可以将整个数据库固定到该表中列出的任何一个软件包。固定的统计信息软件包不会被垃圾回收,并且只要将数据库固定到此软件包,ALLOW_GC 的值就会被忽略。如需将特定统计信息软件包用于个别查询,该软件包必须通过 ALLOW_GC=FALSE 列出或已固定。这可防止在统计信息软件包被垃圾回收后失败查询。可以使用 ALTER STATISTICS DDL 语句更改 ALLOW_GC 的值。

软件包保留和个人身份信息

根据标准行业做法,统计信息软件包包含列数据的直方图。这有助于查询优化器选择最佳查询计划。直方图是使用值的小样本构建的。这个小数据集可能包含个人身份信息。

Cloud Spanner 会定期创建新的统计信息软件包,并且默认保留 30 天。因此,从数据库中删除的值的小样本可能会在统计信息直方图中额外保留 30 天。使用 optimizer_statistics_package 数据库选项固定的统计信息软件包或使用 ALLOW_GC=FALSE 选项固定的软件包不会被垃圾回收。这些软件包中的直方图可能包含从数据库中删除了较长时间的值。此外,统计信息软件包的内容包含在数据库备份中。

优化器统计信息在存储时会采用与用户数据相同的加密方式。

这些软件包所需的总存储空间量通常小于 100 MB,并且会计入您的总存储费用。

后续步骤

  • 如需根据您的情况管理优化器版本和统计信息软件包,请参阅管理查询优化器