如何优化这个以减少执行时间

how to optimize this one to reduce execution time

Use ReportingDb
select hd.company_name as CompanyName,
        COALESCE((select sum(case datepart(dw, hrd.created_datetime)
             when 1 then 1 else 0
        end) from dbo.HdSurvey_Result_Details hrd where hd.company_id = hrd.company_id and (hrd.created_datetime between '2019-10-10 10:46:19' AND '2020-10-10 10:46:19')),0) as Monday,
       COALESCE((select sum(case datepart(dw,hrd.created_datetime)
             when 2 then 1 else 0
        end)from dbo.HdSurvey_Result_Details hrd where hd.company_id = hrd.company_id and (hrd.created_datetime between '2019-10-10 10:46:19' AND '2020-10-10 10:46:19')),0) as Tuesday,
         COALESCE((select sum(case datepart(dw,hrd.created_datetime)
             when 3 then 1 else 0
        end)from dbo.HdSurvey_Result_Details hrd where hd.company_id = hrd.company_id and (hrd.created_datetime between '2019-10-10 10:46:19' AND '2020-10-10 10:46:19')),0) as Wednesday,
         COALESCE((select sum(case datepart(dw,hrd.created_datetime)
             when 4 then 1 else 0
        end)from dbo.HdSurvey_Result_Details hrd where hd.company_id = hrd.company_id and (hrd.created_datetime between '2019-10-10 10:46:19' AND '2020-10-10 10:46:19')),0) as Thursday,
         COALESCE((select sum(case datepart(dw,hrd.created_datetime)
             when 5 then 1 else 0
        end)from dbo.HdSurvey_Result_Details hrd where hd.company_id = hrd.company_id and(hrd.created_datetime between '2019-10-10 10:46:19' AND '2020-10-10 10:46:19')),0) as Friday,
         COALESCE((select sum(case datepart(dw,hrd.created_datetime)
             when 6 then 1 else 0
        end)from dbo.HdSurvey_Result_Details hrd where hd.company_id = hrd.company_id and (hrd.created_datetime between '2019-10-10 10:46:19' AND '2020-10-10 10:46:19')),0) as Saturday,
         COALESCE((select sum(case datepart(dw,hrd.created_datetime)
             when 7 then 1 else 0
        end)from dbo.HdSurvey_Result_Details hrd where hd.company_id = hrd.company_id and (hrd.created_datetime between '2019-10-10 10:46:19' AND '2020-10-10 10:46:19')),0) as Sunday,
        COALESCE((select COUNT_BIG(*) from dbo.HdSurvey_Result_Details hrd where hd.company_id = hrd.company_id and(hrd.created_datetime between '2019-10-10 10:46:19' AND '2020-10-10 10:46:19')),0) as TotalResults
from HdSurvey_Result_Details as hd
group by hd.company_name,hd.company_id

我认为就时间而言,最初的问题是所有 sub-queries(例如,SELECT SUM(CASE ... 语句)的 amount/approach 可能无法通过查询得到很好的优化优化器。

如果可能,您确实需要尝试简化该方法。这是可能的。理想情况下,您可以将 'SELECT' 组件作为简单的 SUM(CASE ... 语句来执行,而无需完整 sub-queries。这使查询优化器有机会(比如说)决定只读取 table 一次而不是 10 次。

首先,我总是检查分组:每一行应该是什么?在这种情况下,每一行都是一个公司名称。你已经设置好了。

下一步是优化聚合组件。这是您的问题的一个例子(大多数似乎是这样)。为了帮助我,我对其进行了一些不同的格式化。

COALESCE(
    (select  sum(case datepart(dw, hrd.created_datetime)
               when 1 then 1 else 0
               end) 
       from  dbo.HdSurvey_Result_Details hrd 
       where hd.company_id = hrd.company_id and (hrd.created_datetime between '2019-10-10 10:46:19' AND '2020-10-10 10:46:19')
    ), 
    0) as Monday,

据我所知,这是 a) 按 hrd.created_datetime 过滤,以及 b) 计算周一范围内的行数。

相反,这可以通过将过滤放在 CASE 中来简化 -(消除对完整 sub-query 的需要)例如,

SUM(CASE WHEN datepart(dw, hd.created_datetime) = 1 AND (hd.created_datetime between '2019-10-10 10:46:19' AND '2020-10-10 10:46:19') THEN 1 ELSE 0 END) AS Monday

已按公司分组,无需加入it/etc公司。这是由底部的 GROUP BY 处理的。

此外,这是 total_results 值

的一种方法
SUM(CASE WHEN (hd.created_datetime between '2019-10-10 10:46:19' AND '2020-10-10 10:46:19') THEN 1 ELSE 0 END) as TotalResults

如果你对所有的聚合值都这样做,我相信你会得到很好的改进。

不过,我们可以更进一步。

您似乎在按相同的日期范围过滤每个 count/sum 值。不要将它包含在 SUM(CASE) 语句中,只需使用 WHERE 子句过滤原始数据,例如

select  hd.company_name as [CompanyName],
        SUM(CASE WHEN datepart(dw, hd.created_datetime) = 1 THEN 1 ELSE 0 END) AS [Monday],
        -- add similar rows for Tuesday to Sunday
        -- Total results no longer needs the SUM(CASE) as all rows match
        COUNT_BIG(*) as [TotalResults]
from  HdSurvey_Result_Details as hd
WHERE (hd.created_datetime between '2019-10-10 10:46:19' AND '2020-10-10 10:46:19')
group by hd.company_name, hd.company_id

这意味着不是读取整个 table,然后在整个 table 中计算每个聚合(例如,很多行在您的 SUM 中为 0),您可以改为只读取 table 的一小部分(希望如此),并且只对这个小得多的数据集进行聚合计算。

编辑:拼写错误 - 我在解决方案中留下了一些 hrd table 参考而不是 hd。这些已更改为高清。


更新以下评论 - 包括所有公司名称

要获取所有公司名称,如果不存在则为 0,请将以上内容用作 LEFT JOIN 的一部分(其中左侧 table 是公司名称)。

这是一个示例 - 假设公司存储在 'Company' table 中并具有 CTE。你也可以做一个 sub-query.

; WITH A AS
    (select hd.company_Id,   -- Note - changed this to company_id rather than company_name       
            SUM(CASE WHEN datepart(dw, hd.created_datetime) = 1 THEN 1 ELSE 0 END) AS [Monday],
            -- add similar rows for Tuesday to Sunday
            -- Total results no longer needs the SUM(CASE) as all rows match
            COUNT_BIG(*) as [TotalResults]
    from  HdSurvey_Result_Details as hd
    WHERE (hd.created_datetime between '2019-10-10 10:46:19' AND '2020-10-10 
    10:46:19')
    group by hd.company_id      -- Also changed this to company_id
    )
SELECT c.company_name,
       COALESCE(A.[Monday],0) AS Monday,
       --- other days
       COALESCE(A.[TotalResults],0) AS TotalResults
FROM   companies AS c
       LEFT OUTER JOIN A on c.company_id = A.company_id