是否有用于相同目的的更快,更少资源占用的查询?

时间:2019-01-11 18:03:42

标签: sql google-bigquery

我有一个表,其中有50多个记录具有以下结构:

sku STRING,
sale_net STRING,
sold_amount FLOAT64,
dt DATE,
is_promo BOOL

我需要从中选择包含sku至少一次的sale_netsis_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%

是否可以优化我的查询?如何优化?

6 个答案:

答案 0 :(得分:2)

通常,对于这种类型的查询,存在子句比使用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 ) );

答案 1 :(得分:2)

如何使用窗口功能?

select * 
from (select t.*,
             countif(ispromo) over (partition by sku, sale_net) as num_promos
      from t
     ) t
where num_promos > 0;

答案 2 :(得分:1)

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);

答案 3 :(得分:1)

我不确定这是否对您有用,因为我意识到bigquery的工作与常规db不同。但是我还是会提出我的建议。

首先尝试查找哪个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的行。而不是对每一行进行全面扫描以查找该行是否有促销。

答案 4 :(得分:1)

以下是用于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
)

答案 5 :(得分:1)

加入应该有效,它比WHERE IN类型查询更有效地实现:

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