我有这样的疑问。
WITH all_products AS (
SELECT
gtin,
category,
product_name,
product_image,
brand,
manufacturer
FROM `products`
),
client_products as (
SELECT *
FROM all_products
WHERE
client_id = "usdemoaccount" and is_client_product = true
),
competitor_products as (
SELECT *
FROM all_products
WHERE
client_id = "usdemoaccount" and is_client_product = false
);
这里
all_products
的计算发生了两次,因为它在下面的代码中被引用了两次。但如果重复使用上述结果,我们不需要重复两次并节省计算量。
BQ 文档中提到的原因是,非递归 CTE 并未实现。
BigQuery 仅具体化递归 CTE 的结果,但不会具体化 WITH 子句内的非递归 CTE 的结果。如果在查询中的多个位置引用非递归 CTE,则每次引用都会执行一次 CTE。
我正在探索解决此问题的替代方案。虽然我知道使用临时表是一种选择,但我担心潜在的缺点,例如存储成本增加和并发问题,特别是当具有不同参数的多个用户使用相同的 API 时。
优化 BigQuery 中 CTE 性能的有效策略或最佳实践有哪些?具体来说,我对能够帮助实现非递归 CTE 或提高查询性能而无需诉诸临时表的方法感兴趣。
即使有临时表,如果有一个选项可以自动清理这些表以避免存储成本并开箱即用地进行并发处理,那也应该是更好的选择。
在 BigQuery 中降低成本的一个重要因素是始终明确指定要从中选择的列,而不是使用
SELECT *
。
此外,对于运行时,将数据限制为尽可能少的行,例如按日期和/或其他一些
WHERE
条件进行限制,因此任何后续查询或 CTE 仅适用于所需的最小数量或行。
成本与运行时间
在提供的查询中,没有任何额外费用,因为什么都没有实现。仅来自
products
的原始查询仅运行一次,因此即使您稍后引用第一个 CTE 两次,也仅会产生一组费用,因此这不是成本或存储问题,而只是运行时问题。
减少运行时间
为了减少运行时间,您可以在第一个(也是唯一的)CTE 中为客户或竞争对手设置标志,然后根据需要使用派生字段
client_competitor_product
调用它。这取代了计算您要使用哪个 CTE - client_product
或 competitor_product
。
减少解析的数据
此外,如果两个子句中的条件相同 (
client_id = "usdemoaccount"
),请将其移至 WHERE
子句,以便在评估 CASE
语句之前限制正在使用的数据集。
OP 原始查询的注释
在第二个和第三个 CTE 中,all_products 中不存在 2x 引用字段,因此它们会失败 -
client_id
和 is_client_product
不存在于 all_products
中。
CTE 没有输出
SELECT
,那么可以参考哪个 CTE?有时是client_products
,有时是competitor_products
。如果您 UNION ALL
它们,您仍然无法分辨哪个产品属于哪个来源,没有附加字段,例如来源,以区分它们。
限制选择的字段、评估的数据并导出所需的字段
WITH all_products AS (
SELECT
gtin,
category,
product_name,
product_image,
brand,
manufacturer,
CASE
WHEN is_client_product = true THEN "client"
WHEN is_client_product = false THEN "competitor"
END AS client_competitor_product
FROM `products`
WHERE client_id = "usdemoaccount"
)
SELECT <limit fields>
FROM all_products
WHERE <some condition>;