2017-04-21 80 views
0

我有以下sql查询并尝试使用执行计划对其进行优化。在执行计划中,它表示估计的子树成本是36.89。有几个表轴(Eager Spool)。任何人都可以帮助我优化这个查询。提前致谢。优化SQL Server中的表假脱机执行计划

SELECT 
    COUNT(DISTINCT bp.P_ID) AS total, 
    COUNT(DISTINCT CASE WHEN bc.Description != 'S' THEN bp.P_ID END) AS m_count, 
    COUNT(DISTINCT CASE WHEN bc.Description = 'S' THEN bp.P_ID END) AS s_count, 
    COUNT(DISTINCT CASE WHEN bc.Description IS NULL THEN bp.P_ID END) AS n_count 
FROM 
    progress_tbl AS progress 
INNER JOIN Person_tbl AS bp ON bp.P_ID = progress.person_id 
LEFT OUTER JOIN Status_tbl AS bm ON bm.MS_ID = bp.MembershipStatusID   
LEFT OUTER JOIN Membership_tbl AS m ON m.M_ID = bp.CurrentMembershipID 
LEFT OUTER JOIN Category_tbl AS bc ON bc.MC_ID = m.MembershipCategoryID 
WHERE 
    logged_when BETWEEN '2017-01-01' AND '2017-01-31' 

enter image description here

+2

我没有看到'b'别名。我没有看到在SELECT部分​​中使用了'b_p'别名。发布的查询错误 – StanislavL

+0

我在发布之前编辑了查询。我将相应地更改 –

+0

由于您现在提供了一个正在运行的查询,请参阅我的编辑 –

回答

0

前面已经指出的那样,似乎与你查询的一些错字/复制粘贴问题。这使我们很难弄清楚发生了什么事情。

表轴可能是CASE WHEN b.description etc...结构中正在发生的事情。 MSSQL首先创建一个包含所有结果值的(内存)表,然后通过COUNT(DISTINCT ...)运算符对其进行排序和流式处理。由于工作需要在某个地方完成,我不认为你可以做些什么。

无论如何,一些言论和乱撞:

  • 我猜logged_whenprogress_tbl表?
  • 如果是这样,你真的需要LEFT OUTER JOIN所有其他表吗?从我能告诉他们没有被使用?
  • 您正在尝试计算与条件匹配的P_ID s的数量,并且您希望将这个数字拆分为具有b.Description'S',其他值或NULL的值。
    • 为此,您可以将总数计算为m_count,s_count和n_count之和。这样可以节省您的操作,不确定它在更大的图片中有很大的帮助,但所有的位都帮助我猜测。

事情是这样的:

;WITH counts AS (

        SELECT 
         COUNT(DISTINCT CASE WHEN b.Description != 'S' THEN b_p.P_ID END) AS m_count, 
         COUNT(DISTINCT CASE WHEN b.Description = 'S' THEN b_p.P_ID END) AS s_count, 
         COUNT(DISTINCT CASE WHEN b.Description IS NULL THEN b_p.P_ID END) AS n_count 
        FROM 
         progress_tbl AS progress 
        INNER JOIN Person_tbl AS bp ON bp.P_ID = progress.person_id 
        LEFT OUTER JOIN Status_tbl AS bm ON bm.MS_ID = bp.MembershipStatusID  -- really needed? 
        LEFT OUTER JOIN Membership_tbl AS m ON m.M_ID = bp.CurrentMembershipID -- really needed? 
        LEFT OUTER JOIN Category_tbl AS bc ON bc.MC_ID = m.MembershipCategoryID -- really needed? 
        WHERE 
         logged_when BETWEEN '2017-01-01' AND '2017-01-31' -- what table does logged_when column come from???? 

    ) 

SELECT total = m_count + s_count + n_count, 
     * 
    FROM counts 

UPDATE

请注意:使用马丁·史密斯的答案/例子代码,我才明白,total不一定总和其他领域。它可能是一个给定的P_ID显示不同的description,然后可能属于不同的类别。根据您的数据,可能因此我的答案显然是错误的。

+0

进度表的列已被logged_when –

+0

bc.Description在选择查询中使用,因此我需要使用Category_tbl。要访问Category_tbl我需要其余的表加入。 –

+0

我使用LEFT OUTER JOIN在bc.Description == null中获取非匹配行以获得非成员 –

1

以下是您可以使用的技巧。

WITH T AS 
(
SELECT DISTINCT CASE 
        WHEN bc.Description != 'S' THEN 'M' 
        WHEN bc.Description = 'S' THEN 'S' 
        WHEN bc.Description IS NULL THEN 'N' 
       END AS type, 
       bp.P_ID 
FROM progress_tbl AS progress 
     INNER JOIN Person_tbl AS bp 
     ON bp.P_ID = progress.person_id 
     LEFT OUTER JOIN Status_tbl AS bm 
     ON bm.MS_ID = bp.MembershipStatusID 
     LEFT OUTER JOIN Membership_tbl AS m 
     ON m.M_ID = bp.CurrentMembershipID 
     LEFT OUTER JOIN Category_tbl AS bc 
     ON bc.MC_ID = m.MembershipCategoryID 
WHERE logged_when BETWEEN '2017-01-01' AND '2017-01-31' 
) 
SELECT COUNT(DISTINCT P_ID) AS total, 
     COUNT(CASE WHEN type= 'M' THEN P_ID END) AS m_count, 
     COUNT(CASE WHEN type= 'S' THEN P_ID END) AS s_count, 
     COUNT(CASE WHEN type= 'N' THEN P_ID END) AS n_count 
FROM T 

我会在一个更简单的例子上演示它。

假设你现有的查询是

SELECT 
    COUNT(DISTINCT number) AS total, 
    COUNT(DISTINCT CASE WHEN name != 'S' THEN number END) AS m_count, 
    COUNT(DISTINCT CASE WHEN name = 'S' THEN number END) AS s_count, 
    COUNT(DISTINCT CASE WHEN name IS NULL THEN number END) AS n_count 
FROM master..spt_values; 

可以按如下

WITH T AS 
(
SELECT DISTINCT CASE 
        WHEN name != 'S' 
        THEN 'M' 
        WHEN name = 'S' 
        THEN 'S' 
        ELSE 'N' 
       END AS type, 
       number 
FROM master..spt_values 
) 
SELECT COUNT(DISTINCT number) AS total, 
     COUNT(CASE WHEN type= 'M' THEN number END) AS m_count, 
     COUNT(CASE WHEN type= 'S' THEN number END) AS s_count, 
     COUNT(CASE WHEN type= 'N' THEN number END) AS n_count 
FROM T 

注重写作为相当便宜成本核算及计划要简单得多重写。

enter image description here

+0

感谢您的回复。试过你的,它将子树成本从36.98降低到26.87。您认为我们无法进一步优化或者因为数据无法进一步降低子树成本吗? –

+0

@KapilaPerera - 无法说,因为它将取决于联接和WHERE的执行计划,并且您显示的计划不包括这些。无论如何,这将是一个不同的问题。你在这里问的问题是关于摆脱线轴。 –