数据仓库慢查询怎么办?Redshift、BigQuery、Snowflake性能调优实战
本内容发表于:2026-05-25 12:02:41
浏览量
1008

数据仓库慢查询怎么办?Redshift、BigQuery、Snowflake性能调优实战

微信图片_2026-05-25_115146_713.png

去年一个客户,数据仓库换成了Redshift,觉得“云数仓肯定比自建快”。结果跑了两个月,业务方反馈报表越跑越慢,季度汇总从10分钟变成40分钟。他们又准备扩容。

我说:“先别扩,我看一眼查询。”

慢查询日志里有一条:扫描了全表,过滤条件在where里,但没有用排序键。表按日期排序,但查询按用户ID过滤。每次都要扫全表——数据量大了当然慢。

加了排序键后,同样的查询从40分钟缩到6分钟。没扩一个节点。

这是数仓优化最常见的误区:觉得慢就是资源不够,其实往往是用法不对。

今天聊聊Redshift、BigQuery、Snowflake的性能调优。不是那种“数仓很快”的入门课,而是帮你理清楚:不同数仓的优化重点在哪里?什么情况下扩仓是最后手段?

01 数仓优化三板斧:存储、查询、资源

数仓慢,逃不出这三个方面的问题。

维度核心问题优化方向
存储数据怎么放排序键、分区、压缩、分布风格
查询SQL怎么写过滤下推、聚合前置、Join顺序
资源并发怎么管队列、超时、资源隔离

那家客户的慢查询,存储层问题。表按日期排序,查询按用户ID过滤,全表扫描。加了一个按用户ID的排序键后,查询只扫相关数据块。

02 存储优化:数据怎么放

数仓和OLTP数据库不一样,没有传统意义上的索引。性能靠数据组织。

Redshift:排序键和分布风格

  • 排序键:决定数据在磁盘上的物理顺序。查询经常用作过滤条件的列,设为排序键。一张表最多设一个排序键(复合排序键也是按顺序存储)。

  • 分布风格:决定数据在节点间的分布。键分布(按某列hash)适合该列经常被Join;全分布(所有节点全量复制)适合维度表;自动分布适合小表。

那家客户的表,分布风格是自动,数据随机分布。查询Join时大量数据跨节点传输。改成按用户ID键分布后,Join时数据已在本地,传输量大降。

BigQuery:分区和聚簇

  • 分区:按时间分区,查询只扫描相关分区。必须指定分区列。

  • 聚簇:按某几列自动组织数据存储顺序。适合高基数列(如用户ID)。

Snowflake:自动优化为主

Snowflake自动管理微分区和统计信息,用户干预少。主要优化查询写法。

03 查询优化:SQL怎么写

存储层优化完了,看查询怎么写。

避免全表扫描:能用分区键过滤的,一定用。能用排序键过滤的,一定用。

过滤下推:把过滤条件尽早执行,减少数据传输量。Redshift的WHERE条件会在扫描时应用;BigQuery的WHERE会下推到存储层。

聚合前置:子查询里先聚合,再Join。减少Join的数据量。

Join顺序:小表在左,大表在右(取决于优化器)。但大多数现代数仓优化器会自动重排,不用过分纠结。关键是避免笛卡尔积

避免SELECT *:只取需要的列。列存数据库读取列越多,IO越大。

那家客户有一条查询,先Join再聚合,扫描了全表。改成先聚合再Join,数据量从10亿行降到几万行,查询时间从15分钟降到2分钟。

04 资源管理:并发不是越高越好

数仓是共享资源池。并发太高,大家都慢。

Redshift:查询队列(WLM)

  • 按查询类型分队列:短查询、长查询、ETL分开

  • 设并发上限:一个队列最多5个并发,超过排队

  • 设超时:超过时间自动取消

BigQuery:槽位(Slot)

  • 按项目分配槽位

  • 按需模式:公共槽池共享

  • 固定模式:购买专用槽位

Snowflake:虚拟仓库

  • 一个仓库一套资源。不同业务用不同仓库,资源隔离

  • 按查询负载决定仓库大小(Small到XXLarge)

  • 多仓库并发,互不影响

那家客户把所有查询放一个队列,长查询占满资源,短查询排队等。后来把BI查询和ETL分开队列,BI查询不再被ETL阻塞。

05 物化视图:预聚合加速

对于固定模式的聚合查询(如每日报表),可以建物化视图。

  • Redshift:支持物化视图,自动增量刷新

  • BigQuery:支持物化视图,自动查询重写

  • Snowflake:支持物化视图,需要手动刷新

那家客户有张日报表,每天跑一次,全量聚合。建了物化视图按天预聚合,查询直接读物化视图,从10分钟降到几秒。

06 一个真实案例:从40分钟到6分钟

一个客户,季度汇总报表从10分钟涨到40分钟。我们做了几件事:

  • 加排序键:表原按日期排序,但查询按用户ID过滤。在用户ID上建排序键(复合排序键:用户ID在前,日期在后)。扫描数据量大降。

  • 改分布风格:从随机分布改成按用户ID键分布。Join时数据本地化。

  • 改查询写法:子查询先聚合,再Join主表。

  • 拆分长查询:一个巨复杂的SQL拆成3个临时表,分段执行。

不扩一个节点,查询从40分钟缩到6分钟。运维负责人说:“以前以为数仓慢就是资源不够,现在知道,先查数据怎么放的,再查SQL怎么写的,最后才考虑扩仓。”

写在最后

数仓慢,第一反应不是“加钱扩仓”。先看存储:数据怎么放的?排序键对吗?分布风格对吗?再看SQL:过滤下推了吗?聚合前置了吗?最后才看资源:队列堵了吗?并发超了吗?

那家客户的运维负责人后来总结了一个口诀:“存储先看排序键,过滤下推少扫描;聚合前置减数据,队列隔离防堵塞;扩仓是最后手段,别当第一板斧。”

你的数仓慢,是资源不够,还是用法不对?