多个相关子查询正在查杀SQL Server。怎么避免这个?

问题描述 投票:1回答:3

我有两个表,我需要从他们生成报告。我编写了这个查询来解决我在较小数据库中的任务,但是如果记录数量超过5-6百万,那么查询的性能就会变差

insert into Reconcile ([Account], [Beginning balance], [Turnover TB], [Turnover JE], [Diff], [Ending balance], [Ending balance client]) 
select 
    [GL Account Number ], 
    [Functional Beginning Balance], 
    (case when  (select COUNT([DMBTR]) from JE where [SHKZG]='S' and je.[HKONT]=[GL Account Number ]) = 0 
        then 0 
    else (select SUM([DMBTR]) from JE where [SHKZG]='S' and je.[HKONT]=[GL Account Number ]) end 
    + case when (select COUNT([DMBTR]) from JE where [SHKZG]='H' and je.[HKONT]=[GL Account Number ]) = 0 
        then 0 
    else (select SUM([DMBTR]) from JE where [SHKZG]='H' and je.[HKONT]=[GL Account Number ]) end), 
    [Turnover], 
    ((case when (select COUNT([DMBTR]) from JE where [SHKZG]='S' and je.[HKONT]=[GL Account Number ]) = 0 
        then 0 
    else (select SUM([DMBTR]) from JE where [SHKZG]='S' and je.[HKONT]=[GL Account Number ]) end 
    + case when (select COUNT([DMBTR]) from JE where [SHKZG]='H' and je.[HKONT]=[GL Account Number ]) = 0 
        then 0 
    else (select SUM([DMBTR]) from JE where [SHKZG]='H' and je.[HKONT]=[GL Account Number ]) end) - ([Turnover])), 
    ([Functional Beginning Balance] + 
    (case when (select COUNT([DMBTR]) from JE where [SHKZG]='S' and je.[HKONT]=[GL Account Number ]) = 0 
        then 0 
    else (select SUM([DMBTR]) from JE where [SHKZG]='S' and je.[HKONT]=[GL Account Number ]) end 
    + case when (select COUNT([DMBTR]) from JE where [SHKZG]='H' and je.[HKONT]=[GL Account Number ]) = 0 
        then 0 
    else (select SUM([DMBTR]) from JE where [SHKZG]='H' and je.[HKONT]=[GL Account Number ]) end)), 
    [Functional Ending Balance] 
from TB LEFT JOIN JE je 
ON TB.[GL Account Number ]=[HKONT]
group by [GL Account Number ], [Functional Beginning Balance], [Turnover], [Functional Ending Balance], [HKONT]

我知道问题出现在多个重复的子查询中,但我对tsql很新,我不知道如何为数据集中的每个记录运行一次子查询,然后只使用它在其他出现的返回值,使用该子查询

(case when  (select COUNT([DMBTR]) from JE where [SHKZG]='S' and je.[HKONT]=[GL Account Number ]) = 0 
        then 0 
    else (select SUM([DMBTR]) from JE where [SHKZG]='S' and je.[HKONT]=[GL Account Number ]) end 
    + case when (select COUNT([DMBTR]) from JE where [SHKZG]='H' and je.[HKONT]=[GL Account Number ]) = 0 
        then 0 
    else (select SUM([DMBTR]) from JE where [SHKZG]='H' and je.[HKONT]=[GL Account Number ]) end)

如何优化此查询?

sql-server tsql
3个回答
1
投票

如何优化此查询?

那么试试以下:

  • 避免任何子查询。
  • 尽可能用派生表替换子查询。
  • 有效地使用分组。
  • 避免重复代码。

话虽如此,

尝试以下查询。

INSERT INTO Reconcile ([Account], [Beginning balance], [Turnover TB], [Turnover JE], [Diff], [Ending balance], [Ending balance client]) 
SELECT 
    [GL Account Number ], 

    [Functional Beginning Balance], 

    (CASE WHEN  ISNULL(JE_S.DMBTR_COUNT, 0) = 0 THEN 0 ELSE ISNULL(JE_S.DMBTR_SUM, 0) END 
    + CASE WHEN ISNULL(JE_H.DMBTR_COUNT, 0) = 0 THEN 0 ELSE ISNULL(JE_H.DMBTR_SUM, 0) END), 

    [Turnover], 

    ((CASE WHEN ISNULL(JE_S.DMBTR_COUNT, 0) = 0 THEN 0 ELSE ISNULL(JE_S.DMBTR_SUM, 0) END 
    + CASE WHEN ISNULL(JE_H.DMBTR_COUNT, 0) = 0 THEN 0 ELSE ISNULL(JE_H.DMBTR_SUM, 0) END) 
    - ([Turnover])), 

    ([Functional Beginning Balance] 
    + (CASE WHEN ISNULL(JE_S.DMBTR_COUNT, 0) = 0 THEN 0 ELSE ISNULL(JE_S.DMBTR_SUM, 0) END 
    + CASE WHEN ISNULL(JE_H.DMBTR_COUNT, 0) = 0 THEN 0 ELSE ISNULL(JE_H.DMBTR_SUM, 0) END)), 

    [Functional Ending Balance] 

FROM TB LEFT JOIN JE je 
ON TB.[GL Account Number ]=[HKONT]
LEFT OUTER JOIN (SELECT [HKONT], COUNT([DMBTR]) DMBTR_COUNT, SUM([DMBTR]) DMBTR_SUM  FROM JE WHERE [SHKZG]='S' GROUP BY [HKONT]) JE_S
ON [GL Account Number ] = JE_S.[HKONT]
LEFT OUTER JOIN (SELECT [HKONT], COUNT([DMBTR]) DMBTR_COUNT, SUM([DMBTR]) DMBTR_SUM  FROM JE WHERE [SHKZG]='H' GROUP BY [HKONT]) JE_H
ON [GL Account Number ] = JE_S.[HKONT]
GROUP BY [GL Account Number ], [Functional Beginning Balance], [Turnover], [Functional Ending Balance], [HKONT]

我刚尝试快速查找并替换您的查询。请让我知道这对你有没有用。

这可以肯定进一步优化。虽然,我会留给你探索。

尝试谷歌或检查有关该主题的一些微软technet详细信息,以便进一步学习。

以下是一些示例文章:

  1. Query Performance Tuning guide - Microsot Technet
  2. Difference between subqueries and derived tables

0
投票

我试图匹配你在每个select语句中运行的4个子查询,然后在APPLY语句中使用它们(这对我的经验中的子查询非常有效)。

SELECT 
    [GL Account Number ] AS [Account], 
    [Functional Beginning Balance] AS [Beginning balance], 
    (CASE       WHEN q1.[Count] = 0 THEN 0      ELSE q2.[Sum] END +     CASE        WHEN q4.[Count] = 0 THEN 0          ELSE q3.[Sum] END) as [Turnover TB],    [Turnover] AS [Turnover JE], 
    (   (CASE       WHEN q1.[Count] = 0 THEN 0          ELSE q2.[Sum] END +     CASE        WHEN q4.[Count] = 0 THEN 0          ELSE q3.[Sum] END) - ([Turnover])) AS [Diff], 
    ([Functional Beginning Balance] + 
    (   CASE        WHEN q1.[Count] = 0 THEN 0          ELSE q2.[Sum] END +     CASE        WHEN q4.[Count] = 0 THEN 0          ELSE q3.[Sum] END)) AS [Ending balance], 
    [Functional Ending Balance] AS [Ending balance client]
FROM TB LEFT JOIN JE je ON TB.[GL Account Number ]=[HKONT]
    OUTER APPLY (SELECT COUNT([DMBTR]) AS [Count]   FROM JE where [SHKZG]='S' AND je.[HKONT]=[GL Account Number ]) AS q1
    OUTER APPLY (SELECT SUM([DMBTR]) AS [Sum]       FROM JE where [SHKZG]='S' AND je.[HKONT]=[GL Account Number ]) AS q2
    OUTER APPLY (SELECT SUM([DMBTR]) AS [Sum]       FROM JE where [SHKZG]='H' AND je.[HKONT]=[GL Account Number ]) AS q3
    OUTER APPLY (SELECT COUNT([DMBTR]) AS [Count]   FROM JE where [SHKZG]='H' AND je.[HKONT]=[GL Account Number ]) AS q4
GROUP BY [GL Account Number ], [Functional Beginning Balance], [Turnover], [Functional Ending Balance], [HKONT]

你可能需要添加一个COALESCEIS NOT NULL> 0的组合,以实现你想要的。

另外,为什么你在LEFT OUTER JOINFROM的原始TB声明中完成了JE?每个子查询都在查看左外连接右侧表格的字段。


0
投票

获得一次总结,然后加入它

declare @JEsum table (SHKZG varchar(20), GLAccountNumber varchar(20), cnt int
                      , primary key (SHKZG, GLAccountNumber));
insert into @JEsum (SHKZG, GLAccountNumber, cnt) 
select [SHKZG], [GL Account Number ], count([DMBTR]) as cnt 
from TB LEFT JOIN JE 
ON TB.[GL Account Number ]=[HKONT] 
where [SHKZG] in ('s', 'h')
group by [SHKZG], [GL Account Number ] 

您的查询很难阅读。始终在列中包含表名,以便人们知道它来自何处。使用没有别名的JE多个点是令人困惑的。

© www.soinside.com 2019 - 2024. All rights reserved.