避免重复与慢子查询

Posted

技术标签:

【中文标题】避免重复与慢子查询【英文标题】:Avoiding duplicates vs slow sub-query 【发布时间】:2016-08-09 08:11:48 【问题描述】:

我有一个 MS SQL 查询,它使用 TransactionID 链接到如下表(12m 行)。我需要对成本求和,但仅当 AnalysisGroupID 在给定列表中时,例如。 (56, 62)

+---------------+-----------------+-------+
| TransactionID | AnalysisGroupID | Cost  |
+---------------+-----------------+-------+
| 1118850       | 57              | 5.00  |
+---------------+-----------------+-------+
| 1118850       | 56              | 10.00 |
+---------------+-----------------+-------+
| 1118850       | 57              | 4.00  |
+---------------+-----------------+-------+
| 1118850       | 56              | 7.00  |
+---------------+-----------------+-------+
| 1132443       | 57              | 3.00  |
+---------------+-----------------+-------+
| 1132443       | 56              | 8.00  |
+---------------+-----------------+-------+
| 1132443       | 57              | 9.00  |
+---------------+-----------------+-------+
| 1145784       | 62              | 10.00 |
+---------------+-----------------+-------+
| 1145784       | 63              | 5.00  |
+---------------+-----------------+-------+
| 1145784       | 62              | 4.00  |
+---------------+-----------------+-------+
| 1145784       | 63              | 7.00  |
+---------------+-----------------+-------+
| 1145786       | 62              | 9.00  |
+---------------+-----------------+-------+
| 1145786       | 63              | 8.00  |
+---------------+-----------------+-------+
| 1145786       | 42              | 3.00  |
+---------------+-----------------+-------+

问题是,如果我只是对 TransactionID 进行直接连接,我会得到重复项,因为一个 TransactionID 可以针对多个 AnalysisGroupID 产生成本。

但是,如果我尝试使用子查询或事先创建视图,如下所示:

create view SorDeliveryTransactionAnalysisCarriage

as

select
    sdta.transactionid,
    sum(sdta.Cost) as Cost
from
        SorDeliveryTransactionAnalysis sdta         
where
        sdta.AnalysisGroupID in (56, 62)
    and 
        sdta.Cost > 0
group by
    sdta.transactionid

...性能大大降低,我猜是因为在这种情况下我可以加入 TransactionID 之前需要对表的所有 12m 行求和?

有没有我可以做我的加入来避免重复但不必事先处理表中的每一行?

编辑: 我应该提到一些关于我的情况的具体点,这有助于我找到解决方案:

我需要运行这个查询数百次,将来自其他表的不同 ID 插入查询的其他部分,但重要的是,我只需要定期执行整个过程,即每周或每两周一次。

【问题讨论】:

【参考方案1】:

尝试使用过滤索引来限制行

Select 
Transactionid,
sum(Case when analysisgroupid in (56,62) then cost else 0.00 end) as 'summ'
from
Yourtable
group by 
Transactionid

当你有一个 group by 时,SQL 将尝试获取 group by 中列的不同值并做剩下的事情

在你的情况下,由于 transactionid 上的重复,Unqiue idnex 是不可能的,所以在 transactionid 上创建一个过滤索引来限制分析组,如下所示..

create index nci_test
on dbo.yourtable(transactinid)
include(cost)
where analysusgroupid in(56,62)

【讨论】:

谢谢,我是否将“创建索引..”部分作为命令运行,然后将“选择...”部分设置为视图,然后链接到事务 ID 上的该视图? 创建索引并尝试运行选择部分,看看性能差异 您好,这将我的查询时间从 67 秒略微增加到 60 秒,因此感谢您的建议。实际上,我设法找到了一个在我的情况下非常有效的解决方案,但这只是因为我没有在我的问题中解释我的问题的全部性质,所以这是我的错。我将发布我找到的答案。【参考方案2】:

因为只需要每周或每两周进行一次,并且不需要不断更新实时数据,因此最有效的方法是:

    创建问题中指定的视图。 从视图中创建一个静态表,如下所示:

Select * into MyTable from MyView

    在主查询中引用表而不是视图。

这个解决方案意味着对 12m 行求和的主要工作只完成一次。之后我们可以通过链接 TransactionID 来引用静态表

【讨论】:

以上是关于避免重复与慢子查询的主要内容,如果未能解决你的问题,请参考以下文章

索引与慢查询优化

避免用于派生选择中的列的多个重复子查询

索引原理与慢查询优化

mysql数据库之索引与慢查询优化

如何避免重复冗长的相关子查询?

如何在子查询中实现多列过滤