Spark SQL 使用基于成本的优化器(CBO)来选择高效的查询计划。 CBO使用表格和列统计数据,如表格大小和数据分布,估算备选计划的成本,并选择估算成本最低的计划。 这对多连接查询尤为重要,因为糟糕的计划可能比好的计划慢好几个数量级。
CBO默认是启用的,但这取决于统计数据。 如果统计数据缺失或过时,CBO可能会选择效率较低的连接顺序或连接策略。 收集表和列的统计数据并保持其最新状态。 参见 收集统计数据。
最佳做法
为了帮助CBO选择高效的查询计划,请遵循以下做法:
- 收集统计数据,用于多连接查询的表。 如果你在 Unity Catalog 管理的表上使用预测优化,统计数据会被自动收集。 参见 收集统计数据。
- 当多重连接查询比预期慢时,检查查询计划。 缺失或不准确的统计数据是常见原因。 参见 “验证查询计划”。
- 只需删除统计信息或禁用CBO,以缓解统计信息引发的特定规划问题。 参见 禁用基于成本的优化器。
收集统计信息
为了充分利用 CBO,重要的是要同时收集列统计信息和表统计信息。 可以使用 ANALYZE TABLE 该命令手动收集统计信息。
提示
若要使统计信息保持最新,请在将内容写入表后运行 ANALYZE TABLE。
使用 ANALYZE
预测优化会自动运行 ANALYZE 命令,以收集 Unity Catalog 托管表的统计信息。 Databricks 建议为所有 Unity Catalog 托管表启用预测优化,以简化数据维护并降低存储成本。 请参阅 ANALYZE TABLE ...计算统计信息。
可以删除优化器统计信息,以便优化器不再依赖这些统计信息,例如,缓解统计信息导致的规划问题。 请参阅 ANALYZE TABLE … DROP STATISTICS。
验证查询计划
可通过多种方式来验证查询计划。
EXPLAIN 命令
若要检查计划是否使用统计信息,请使用 SQL 命令 EXPLAIN。
如果缺少统计信息,则查询计划可能不是最佳计划。
== Optimized Logical Plan ==
Aggregate [s_store_sk], [s_store_sk, count(1) AS count(1)L], Statistics(sizeInBytes=20.0 B, rowCount=1, hints=none)
+- Project [s_store_sk], Statistics(sizeInBytes=18.5 MB, rowCount=1.62E+6, hints=none)
+- Join Inner, (d_date_sk = ss_sold_date_sk), Statistics(sizeInBytes=30.8 MB, rowCount=1.62E+6, hints=none)
:- Project [ss_sold_date_sk, s_store_sk], Statistics(sizeInBytes=39.1 GB, rowCount=2.63E+9, hints=none)
: +- Join Inner, (s_store_sk = ss_store_sk), Statistics(sizeInBytes=48.9 GB, rowCount=2.63E+9, hints=none)
: :- Project [ss_store_sk, ss_sold_date_sk], Statistics(sizeInBytes=39.1 GB, rowCount=2.63E+9, hints=none)
: : +- Filter (isnotnull(ss_store_sk) && isnotnull(ss_sold_date_sk)), Statistics(sizeInBytes=39.1 GB, rowCount=2.63E+9, hints=none)
: : +- Relation[ss_store_sk,ss_sold_date_sk] parquet, Statistics(sizeInBytes=134.6 GB, rowCount=2.88E+9, hints=none)
: +- Project [s_store_sk], Statistics(sizeInBytes=11.7 KB, rowCount=1.00E+3, hints=none)
: +- Filter isnotnull(s_store_sk), Statistics(sizeInBytes=11.7 KB, rowCount=1.00E+3, hints=none)
: +- Relation[s_store_sk] parquet, Statistics(sizeInBytes=88.0 KB, rowCount=1.00E+3, hints=none)
+- Project [d_date_sk], Statistics(sizeInBytes=12.0 B, rowCount=1, hints=none)
+- Filter ((((isnotnull(d_year) && isnotnull(d_date)) && (d_year = 2000)) && (d_date = 2000-12-31)) && isnotnull(d_date_sk)), Statistics(sizeInBytes=38.0 B, rowCount=1, hints=none)
+- Relation[d_date_sk,d_date,d_year] parquet, Statistics(sizeInBytes=1786.7 KB, rowCount=7.30E+4, hints=none)
重要
rowCount 统计信息对于具有多个联接的查询尤其重要。 如果缺少 rowCount,则意味着没有足够的信息来对其进行计算(也就是说,某些必需列没有统计信息)。
在Databricks Runtime 16.0及以上版本中,命令输出 EXPLAIN 列出了包含缺失、部分和完整统计的引用表,例如:
== Optimizer Statistics (table names per statistics state) ==
missing = date_dim, store
partial =
full = store_sales
Corrective actions: consider running the following command on all tables with missing or partial statistics
ANALYZE TABLE <table-name> COMPUTE STATISTICS FOR ALL COLUMNS
Spark SQL UI
使用 Spark SQL UI 页可以查看已执行的计划以及统计信息的准确性。
诸如 rows output: 2,451,005 est: N/A 之类的行表示此运算符大约生成 2 百万个行,但没有可用的统计信息。
诸如 rows output: 2,451,005 est: 1616404 (1X) 之类的行表示此运算符大约生成 2 百万个行,而估算的行约为 160 万个,估算误差系数为 1。
诸如 rows output: 2,451,005 est: 2626656323 之类的行表示此算符大约生成 200 万行,而估计则为 20 亿行,因此估算误差系数为 1000。
禁用基于成本的优化器
默认情况下,CBO 已启用。 可以通过更改 spark.sql.cbo.enabled 标志来禁用 CBO。
spark.conf.set("spark.sql.cbo.enabled", false)