是否有任何更快、更少资源消耗的查询用于相同目的?

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

我需要从中选择包含skusale_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 INtype 查询更有效:

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

【讨论】:

以上是关于是否有任何更快、更少资源消耗的查询用于相同目的?的主要内容,如果未能解决你的问题,请参考以下文章

是否有任何 jar 可用于在 java 中更快地执行 sql 查询? [关闭]

更快的哈希和更少的冲突?

网页的缓存Cache与控制

选择更少的 SQL 列是不是会使请求更快? [复制]

gozero和gin性能对比

减少查询中的资源使用