是否有任何更快、更少资源消耗的查询用于相同目的?
Posted
技术标签:
【中文标题】是否有任何更快、更少资源消耗的查询用于相同目的?【英文标题】:Is there any faster and less resource hungry query for same purpose? 【发布时间】:2019-01-11 18:03:42 【问题描述】:我有一个包含 50+ 百万条记录的表,具有这种结构:
sku STRING,
sale_net STRING,
sold_amount FLOAT64,
dt DATE,
is_promo BOOL
我需要从中选择包含sku
和sale_nets
且至少有一次is_promo = true
的记录。
例如,如果表只有 3 条记录:
sku1 sn1 123 01.01.2018 false
sku1 sn1 456 02.01.2018 true
sku2 sn1 321 01.01.2018 false //this sku-sale_net pair don't have is_promo = true records at other dates
我的查询应该只选择前两个。
我写了这个查询:
select *
from src_tbl tbl1
where (select count(*)
from src_tbl tbl2
where tbl1.sku = tbl2.sku
and tbl1.sale_net = tbl2.sale_net
and is_promo = true) > 0;
但由于资源过度使用,它无法在更大的数据库上执行:
Resources exceeded during query execution: The query could not be executed in the allotted memory. Peak usage: 105% of limit. Top memory consumer(s): aggregate functions and GROUP BY clauses: 93% other/unattributed: 7%
是否可以优化我的查询以及如何优化?
【问题讨论】:
你的表中有什么索引? @JuanCarlosOropeza - 抱歉,我不是 SQL 专家,可能无法正确回答您。如果您询问每条记录的唯一 GUID,则没有。如果你问别的事情,那我不知道。这不是我的数据库,但我需要查询,不能更改。 数据库中的index 的作用类似于书中的索引。让您搜索东西比扫描整本书要快得多。但是您需要能够修改表以创建新索引。如果没有索引,您可能需要适当的组合索引,您的查询不会提高性能。 我刚刚读到 bigquery 不需要像往常一样使用索引 db。所以也许我的评论对你不起作用***.com/questions/28600228/indexes-on-bigquery-table 这个问题有 40 次浏览和 5 个回答。干得好! 【参考方案1】:使用窗口函数怎么样?
select *
from (select t.*,
countif(ispromo) over (partition by sku, sale_net) as num_promos
from t
) t
where num_promos > 0;
【讨论】:
【参考方案2】:一般来说,对于这种类型的查询,exists 子句比使用 count() 更好,因为这意味着数据库知道它可以在找到一条匹配记录后停止工作,这样的事情可能会起作用:
select *
from src_tbl tbl1
where exists (select 1
from src_tbl tbl2
where tbl1.sku = tbl2.sku
and tbl1.sale_net = tbl2.sale_net
and tbl2.is_promo = true);
如果这仍然不起作用,您可以尝试完全避免使用相关子查询,例如:
select *
from src_tbl tbl1
where tbl1.sku in( (select tbl2.sku
from src_tbl tbl2
where tbl2.is_promo = true
group by tbl2.sku ) );
【讨论】:
谢谢。可悲的是,我仍然在资源使用方面遇到同样的错误。如果可能的话,看起来我需要一些完全不同的东西。 您可以将数据移动到集群表中吗? @TamirKlein - 可能没有。这不是我的数据库,我能做的就是查询它。【参考方案3】:以下是 BigQuery 标准 SQL
#standardSQL
SELECT *
FROM `project.dataset.src_tbl`
WHERE (sku, sale_net) IN (
SELECT DISTINCT AS STRUCT sku, sale_net
FROM `project.dataset.src_tbl`
WHERE is_promo
)
【讨论】:
谢谢,但这也会导致资源超出限制使用错误。 提供的答案是否真的为您解决了资源问题 - 很高兴知道 :o) 我现在尝试使用window
事物查询来测试它是否有效。然后将尝试 Juan Carlos Oropeza 解决方案。到目前为止,我一直在测试最简单的查询。
没有一个答案解决了资源使用问题,但每个答案都比我的好。但是您向我展示了如何进行多列IN
检查,这对我将来非常有用。
很高兴,它至少在某种程度上有所帮助!【参考方案4】:
select * from src_tbl tbl1
where exists (select * from src_tbl tbl2
where tbl1.sku = tbl2.sku and
tbl1.sale_net = tbl2.sale_net and
tbl2.is_promo = true);
【讨论】:
【参考方案5】:我不确定这是否适合您,因为我意识到 bigquery 的工作方式与常规数据库不同。但无论如何我都会给出我的建议。
首先尝试查找哪些 sku 有促销。
select sku
from src_tbl
group by sku
having COUNT( case when is_promo then 1 end) > 0
如果该工作尝试使用部分结果或将其保存为临时表
SELECT *
FROM src_tbl
WHERE sku IN ( select sku
from src_tbl
group by sku
having COUNT( case when is_promo then 1 end) > 0
)
不同之处在于,您只需在全表扫描中查找所有带有促销的 sku,然后再进行一次全表扫描以返回匹配 sku 的行。而不是对每一行进行全面扫描以查找该行是否有促销。
【讨论】:
谢谢,我会想办法解决这个问题的。 测试一下。如果您可以让第一个查询工作,您将获得部分解决方案,第二个查询会更容易。 第一个查询有效。我得到了这个逻辑背后的基本思想并现在构建新的查询。我希望它会起作用。【参考方案6】:加入应该可以工作,它比WHERE IN
type 查询更有效:
WITH promo_sku AS (
SELECT DISTINCT sku, sale_net
FROM `project.dataset.src_tbl`
WHERE is_promo = true
)
SELECT *
FROM src_tbl tbl1
JOIN promo_sku ON promo_sku.sku = tbl1.sku AND promo_sku.sale_net = tbl1.sale_net
【讨论】:
以上是关于是否有任何更快、更少资源消耗的查询用于相同目的?的主要内容,如果未能解决你的问题,请参考以下文章