一、直连BigQuery后常见的性能痛点

很多用Tableau或Looker做数据可视化的开发者,应该都碰过这种情况:明明数据都存在BigQuery里,直连模式下点个筛选、刷个仪表板,等半分钟甚至更久才出结果,有时候还直接加载失败。这种延迟不仅影响自己的开发效率,给业务方展示的时候也特别掉价。其实直连BigQuery的慢,大多不是工具本身的问题,而是没有针对BigQuery的特性做调优。接下来就从数据预处理、工具配置、查询优化三个核心维度,一步步讲怎么把延迟降下来。

二、数据预处理阶段的调优(从源头减少压力)

BigQuery是列式存储的大数据仓库,它的查询速度和数据本身的结构、分区、索引密切相关,很多时候仪表板慢,根源是数据准备得不够好。

2.1 按时间分区存储数据

如果你的数据是按时间更新的(比如日活、订单、日志),一定要给BigQuery表做时间分区,不然查询的时候会扫描全表,速度慢还费钱。举个例子,假设你要做日活用户的仪表板,原来的表是没有分区的,查询近7天的数据会扫全量数据,做了分区之后就只扫7天的分区,速度能快几十倍。 技术栈:BigQuery SQL

-- 创建按日期分区的表,分区字段为dt(日期格式的字符串,格式为YYYY-MM-DD)
CREATE OR REPLACE TABLE `your-project.your-dataset.daily_active_users` (
  user_id INT64, -- 用户ID
  activity_date DATE, -- 活动日期,和分区字段一致
  device_type STRING -- 设备类型
)
PARTITION BY DATE(dt) -- 按dt字段的日期值分区
CLUSTER BY user_id, device_type; -- 后续要做聚合或筛选的字段可以做聚类,进一步加速

注意事项:分区字段一定要是DATE或TIMESTAMP类型,要是用字符串类型的日期,需要先转成DATE类型再做分区,不然分区会失效。另外,分区表的查询一定要带上分区字段的筛选条件,比如WHERE dt >= '2024-01-01',不然还是会扫全表。

2.2 提前做聚合计算,减少仪表板查询压力

很多仪表板展示的都是统计类数据,比如日活总数、各地区订单金额,要是直连的时候每次都实时计算这些统计值,会特别慢。可以提前把这些聚合好的数据存在一个单独的汇总表,每天定时更新,仪表板直接连这个汇总表就行。 举个例子,原来的明细订单表有几百万条数据,仪表板要展示每天的订单总数、总金额,提前做一个汇总表: 技术栈:BigQuery SQL

-- 创建每日订单汇总表,提前计算好统计值
CREATE OR REPLACE TABLE `your-project.your-dataset.daily_order_summary` (
  order_date DATE, -- 订单日期
  total_orders INT64, -- 当日总订单数
  total_amount FLOAT64, -- 当日总订单金额
  region STRING -- 地区
)
PARTITION BY DATE(order_date) -- 按订单日期分区
CLUSTER BY region; -- 按地区聚类,方便按地区筛选

-- 每天定时更新汇总表,这里用MERGE语句实现增量更新
MERGE `your-project.your-dataset.daily_order_summary` T
USING (
  -- 从明细订单表按日期、地区聚合
  SELECT 
    DATE(order_time) AS order_date,
    COUNT(order_id) AS total_orders,
    SUM(amount) AS total_amount,
    region
  FROM `your-project.your-dataset.order_detail` -- 明细订单表
  WHERE order_time >= '2024-01-01' -- 只处理新数据,避免全量更新
  GROUP BY order_date, region
) S
ON T.order_date = S.order_date AND T.region = S.region
WHEN MATCHED THEN UPDATE SET 
  T.total_orders = S.total_orders,
  T.total_amount = S.total_amount
WHEN NOT MATCHED THEN INSERT ROW;

优缺点:这种方法的优点是仪表板查询速度极快,因为只扫少量的汇总数据;缺点是需要额外维护汇总表的更新任务,要是更新不及时,仪表板的数据会有延迟。适合对实时性要求不高的业务场景,比如日报、周报类的仪表板。

三、Tableau直连BigQuery的配置与查询调优

Tableau直连BigQuery的时候,默认配置往往不是最优的,调整一些连接属性和查询写法,能大幅提升响应速度。

3.1 优化Tableau的连接属性

Tableau连接BigQuery的时候,有几个关键属性一定要改: 第一个是“使用查询缓存”,默认是开启的,但很多人不知道,Tableau直连的时候会默认带一个会话ID的参数,导致每次查询的缓存都不命中。可以在连接的时候加一个参数,让不同会话的查询能共享缓存: 技术栈:Tableau连接字符串(在自定义连接里输入)

project=your-project-id;dataset=your-dataset-id;useLegacySql=false;cacheTtl=3600;useQueryCache=true

注释:cacheTtl是缓存的有效期,单位是秒,这里设为3600秒(1小时),useQueryCache开启后,相同的查询会复用BigQuery的缓存结果,不用重新计算。 第二个是“限制查询结果的行数”,要是仪表板只需要展示前1000条数据,不要让Tableau拉全量数据,可以在数据源的“筛选器”里加一个行数限制,或者在自定义SQL里加LIMIT。

3.2 优化Tableau的自定义SQL查询

很多人在Tableau里写自定义SQL的时候,会直接把明细数据拉过来再做聚合,其实可以把聚合放在BigQuery端,减少传输的数据量。举个例子,要做一个按设备类型的日活仪表板,自定义SQL应该这么写: 技术栈:Tableau自定义SQL(BigQuery方言)

-- 只拉取需要的字段和聚合结果,减少数据传输
SELECT 
  DATE(activity_date) AS activity_date, -- 日期字段,用于按时间筛选
  device_type, -- 设备类型,用于分组
  COUNT(DISTINCT user_id) AS dau -- 日活用户数,提前聚合
FROM `your-project.your-dataset.daily_active_users`
WHERE activity_date >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY) -- 只拉取近30天的数据,减少扫描范围
GROUP BY activity_date, device_type
ORDER BY activity_date DESC;

注意事项:不要在自定义SQL里用SELECT *,只选需要的字段;尽量把筛选条件(WHERE)放在聚合(GROUP BY)前面,减少需要聚合的数据量;如果要做日期筛选,尽量用DATE_SUB、DATE_ADD这类函数,不要用动态的CURRENT_DATE()之外的变量,不然会影响缓存命中。

3.3 禁用不必要的功能

Tableau里有一些功能会增加查询压力,比如“自动更新仪表板”,要是仪表板有很多筛选器,每次改筛选器都触发查询,会很慢。可以把自动更新改成手动更新,或者加一个“应用”按钮,等用户选完所有筛选条件再触发查询。另外,不要在仪表板里加太多的“实时刷新”组件,除非业务真的需要实时数据。

四、Looker直连BigQuery的配置与模型调优

Looker是基于模型的可视化工具,它的调优更多是围绕LookML模型的配置,合理配置模型能让查询更高效。

4.1 配置LookML模型的连接属性

Looker连接BigQuery的时候,需要在连接配置里开启BigQuery的缓存,并且设置合适的缓存有效期。另外,要开启“并行查询”,让Looker可以同时发送多个查询,提升仪表板的加载速度。 技术栈:Looker连接配置(在Admin > Connections里设置)

{
  "name": "bigquery_connection",
  "database": "bigquery",
  "host": "bigquery.googleapis.com",
  "project": "your-project-id",
  "dataset": "your-dataset-id",
  "cache": true,
  "cache_ttl": 3600,
  "parallel_queries": true,
  "use_legacy_sql": false
}

注释:cache设为true开启缓存,cache_ttl设为3600秒(1小时),parallel_queries设为true开启并行查询,适合仪表板有多个图表同时加载的场景。

4.2 优化LookML模型的字段配置

LookML模型里的字段配置直接影响查询的效率,比如要给经常做筛选的字段加“filter”属性,给经常做聚合的字段加“type”属性,并且尽量把聚合逻辑放在模型里,不要在仪表板里做临时聚合。 举个例子,配置一个日活用户的LookML模型: 技术栈:LookML

view: daily_active_users {
  sql_table_name: `your-project.your-dataset.daily_active_users` ;; -- 关联BigQuery表
  dimension: activity_date { -- 日期维度,用于筛选和分组
    type: date
    sql: ${TABLE}.activity_date ;;
  }
  dimension: device_type { -- 设备类型维度,用于分组
    type: string
    sql: ${TABLE}.device_type ;;
  }
  measure: dau { -- 日活用户数,提前定义聚合逻辑
    type: count_distinct
    sql: ${TABLE}.user_id ;;
  }
  filter: activity_date_filter { -- 预定义筛选器,方便仪表板使用
    type: date
    sql: ${TABLE}.activity_date ;;
  }
}

注意事项:不要在模型里定义太多的临时字段,只保留仪表板需要的字段;如果字段是枚举类型(比如设备类型有手机、平板、电脑),可以给字段加“case”属性,统一显示值,减少查询时的转换时间。

4.3 配置预聚合模型(Aggregate Tables)

Looker的预聚合模型是专门用来提升查询速度的,它可以把常用的聚合结果提前计算好,存在一个单独的表中,仪表板查询的时候优先用预聚合表,不用再扫明细数据。 举个例子,配置一个日活用户的预聚合模型: 技术栈:LookML

aggregate_table: daily_dau { -- 预聚合表名称
  materialization: {
    sql: `your-project.your-dataset.daily_dau_agg` ;; -- 预聚合表的位置
    schedule: "0 0 * * *" -- 每天凌晨更新
  }
  measure: dau { -- 预聚合的指标
    type: count_distinct
    sql: ${TABLE}.user_id ;;
  }
  dimension: activity_date { -- 预聚合的维度
    type: date
    sql: ${TABLE}.activity_date ;;
  }
  dimension: device_type { -- 预聚合的维度
    type: string
    sql: ${TABLE}.device_type ;;
  }
}

优缺点:预聚合模型的优点是查询速度极快,能大幅降低BigQuery的费用;缺点是需要额外的存储和更新时间,适合对实时性要求不高的场景。要是业务需要实时数据,就不能用预聚合模型。

五、通用调优技巧与注意事项

除了上面针对两个工具的调优,还有一些通用的技巧,能进一步减少延迟。

5.1 合理使用BigQuery的缓存

BigQuery的缓存是免费的,只要查询的结果在缓存有效期内,就不会重新计算,也不会产生费用。要让缓存命中,需要满足几个条件:查询的SQL完全一致(包括空格、大小写)、查询的表没有被修改、缓存没有过期。所以在写查询的时候,尽量用固定的写法,不要用动态的参数,比如不要用CURRENT_TIMESTAMP(),尽量用DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)这类相对固定的写法。

5.2 控制仪表板的查询数量

一个仪表板里不要放太多的图表,每个图表对应一个查询,要是有10个图表,就会同时发送10个查询,不仅慢,还会占用BigQuery的查询配额。可以把相关的图表合并,或者用参数来控制图表的显示,减少同时查询的数量。

5.3 监控BigQuery的查询性能

BigQuery的控制台里有“查询历史”,可以看到每个查询的执行时间、扫描的数据量、缓存命中情况。要是仪表板慢,可以先看查询历史,找到慢的查询,分析是扫描的数据太多,还是没有命中缓存,再针对性优化。 应用场景:这些调优技巧适合所有用Tableau或Looker直连BigQuery做数据可视化的场景,比如电商的运营仪表板、互联网的用户行为仪表板、企业的财务报表等。 技术优缺点:整体调优的优点是能大幅降低仪表板的响应延迟,提升用户体验,同时减少BigQuery的费用;缺点是需要额外的开发和维护成本,比如维护汇总表、预聚合模型、更新任务等,对开发人员的BigQuery和工具的掌握程度有一定要求。 注意事项:调优的时候要优先优化数据预处理阶段,因为从源头减少数据量是最有效的;其次是工具的配置,最后才是查询的优化;不要为了速度牺牲数据的准确性,比如汇总表的更新频率要和业务需求匹配,要是业务需要实时数据,就不能用预聚合模型。

六、文章总结

Tableau和Looker直连BigQuery的性能调优,核心是围绕“减少BigQuery的扫描数据量”和“提升缓存命中率”两个点。从数据预处理阶段的分区、聚类、提前聚合,到工具配置的连接属性、缓存设置、预聚合模型,再到通用的查询优化、监控,每一步都能带来不同程度的速度提升。调优的时候要结合业务的实际需求,比如对实时性要求高的业务,就不要用预聚合模型,对速度要求高的业务,就尽量提前做聚合。只要按照这些方法一步步调整,就能把仪表板的响应延迟降到可以接受的范围,提升整个数据可视化流程的效率。