替换 Union All 加入以提高性能

Posted

技术标签:

【中文标题】替换 Union All 加入以提高性能【英文标题】:Replace Union All to join to improve performance 【发布时间】:2018-04-03 08:08:29 【问题描述】:

我有一个工作查询需要 20 分钟才能返回数据。我想优化它。 我有桌子

激励措施:

Transaction_ID | Incentive_On_A  | Incentive_On_B  | Incentive_On_C
--------------+-----------------+-----------------+---------------
1             | 0               | 0               | 10
2             | 30              | 0               | 0
3             | 0               | 20              | 0
4             | 40              | 0               | 0

所需输出:

Transaction_ID| Product_Category | Incentive_Amt
 ----------   + -----------------+--------------
  1           | A                | 30
  2           | B                | 20
  3           | C                | 10
  4           | A                | 40

我正在使用这个查询:

   select Transaction_ID, 'A' as Product_Category,
       Incentive_On_A from Incentives
Union all
   select Transaction_ID, 'B' as Product_Category,
       Incentive_On_B from Incentives
Union all
   select Transaction_ID, 'C' as Product_Category,
       Incentive_On_C from Incentives

有什么方法可以通过使用 join 删除 union all 来优化此查询? 非常感谢您的帮助。

已编辑** 1.在两个表中增加了一行。 注意:- 基本上我们只是对数据进行转置 - 将列 - 'Incentive_on_A'、'Incentive_on_B'、'Incentive_on_C' 转换为具有上述 3 列值的列 - 'Category'。

【问题讨论】:

这是一个奇怪的数据模型。那么一个产品可以有衬衫价格、牛仔裤价格和短裤价格?那会是一个什么样的产品?奇怪的。乍一看,我会说更改此数据模型;这似乎没有任何意义。 顺便说一下,20 分钟的简单联合所有查询也很奇怪。你是说秒吗? UNION ALL 相当快,您的查询没有什么复杂的。表中有多少条记录? 那么,对于市场上的每一种最新时尚,您要在您的 Clothes 表中添加一个新列吗? 您好,Thorsten,感谢您抽出宝贵时间。实际上在我的项目中,我有类似的场景,不同的表和数据。我以产品为例来简化问题。我使用 union all 7 次来访问同一张表,并将不同列中存在的产品价格与布料类型的硬编码值一起提取到一列中。 虽然 NOMB ,但我很高兴知道你们提供的其他 4 种类型? 【参考方案1】:

这里不需要JOIN,只需要取消透视数据:

SELECT transaction_id, REGEXP_SUBSTR(incentive_col, '[^_]*$') AS product_category
     , incentive_amt
  FROM (
    SELECT transaction_id, incentive_a, incentive_b, incentive_c
      FROM incentives
) UNPIVOT (
    incentive_amt 
      FOR incentive_col IN (incentive_a, incentive_b, incentive_c )
) WHERE incentive_amt > 0;

这是否真的会提高你的表现,我不能说。我的猜测是,使用 UNION ALL 版本的查询,您实际上是在进行 3 次全表扫描。

【讨论】:

【参考方案2】:

首先:这是一个糟糕的数据模型。如果每条记录只能有一个值,则只需存储一个值,就像您想要的输出中显示的那样。

按原样,您可以添加所有值并使用CASE WHEN 查看哪个值大于零:

select
  transaction_id,
  case when incentive_on_a > 0 then 'A'
       when incentive_on_b > 0 then 'B'
       when incentive_on_c > 0 then 'C'
  end as product_category,
  incentive_on_a + incentive_on_b + incentive_on_c as incentive_amt
from incentives
order by transaction_id;

(但是,我仍然看不出像您展示的那样简单的查询如何运行二十分钟。)

【讨论】:

COALESCE() 不会在这里做你想做的事,有 0 的非空值是 OP 似乎不想要的。 @David Faber:谢谢。我有空值,但它是零。我已经更正了我的答案。

以上是关于替换 Union All 加入以提高性能的主要内容,如果未能解决你的问题,请参考以下文章

sql server with as 能提高性能吗

Oracle数据库如何提高访问性能

Orale数据库提高访问性能

我正在尝试提高查找两个表之间差异的 Oracle SQL 的性能

提高 PostgresSQL 聚合查询性能

Android提高UI性能技巧