如果删除未使用的联接,查询会变慢

时间:2017-08-07 14:49:48

标签: sql-server tsql

我遇到了一个"问题"我无法弄清楚如何解决。我有一个运行大约15秒的查询,当我然后添加一个连接(在选择中没有使用)时,查询实际上加速了大约4秒,即使你没有选择其他连接。我想SQL Server选择一个更快的不同执行计划 - 但是我如何强制它每次选择最快的查询计划?

此查询大约需要15秒:

SELECT
    O.Lvl1_Business_Area_Cd
   ,O.Lvl1_Business_Area_Nm
   ,O.Lvl2_Division_Cd
   ,O.Lvl2_Division_Nm
   ,SUM(F.Economic_Capital) AS Economic_Capital
FROM
    Facts.Financials AS F
    LEFT JOIN Dimensions.Customer AS C ON F.Customer_Id = C.Customer_Id
    LEFT JOIN Dimensions.Organization AS O ON C.CRU_Id = O.CRU_Id
WHERE 
    F.Year_Month_Id = 201706
    AND Lvl1_Business_Area_Cd = 6008000
GROUP BY
    O.Lvl1_Business_Area_Cd
   ,O.Lvl1_Business_Area_Nm
   ,O.Lvl2_Division_Cd
   ,O.Lvl2_Division_Nm

此查询大约需要4秒钟:

SELECT
    O.Lvl1_Business_Area_Cd
   ,O.Lvl1_Business_Area_Nm
   ,O.Lvl2_Division_Cd
   ,O.Lvl2_Division_Nm
   ,SUM(F.Economic_Capital) AS Economic_Capital
FROM
    Facts.Financials AS F
    LEFT JOIN Dimensions.Customer AS C ON F.Customer_Id = C.Customer_Id
    LEFT JOIN Dimensions.Organization AS O ON C.CRU_Id = O.CRU_Id
    LEFT JOIN Dimensions.Nace AS N ON C.NACE_Id = N.NACE_Id
WHERE 
    F.Year_Month_Id = 201706
    AND Lvl1_Business_Area_Cd = 6008000
GROUP BY
    O.Lvl1_Business_Area_Cd
   ,O.Lvl1_Business_Area_Nm
   ,O.Lvl2_Division_Cd
   ,O.Lvl2_Division_Nm

两个查询之间的唯一区别是LEFT JOIN Dimensions.Nace AS N ON C.NACE_Id = N.NACE_Id。但是,在select语句中没有使用此表中的任何内容。

Facts.Financials有大约60百万。行,Dimensions.Customer~17 mio。 rows,Dimensions.Organization~25.000,Dimensions.Nace~1000行。

Customer_Id = bigint
CRU_Id = bigint
Nace_id = varchar(4)

我对表格有以下看法:

Facts.Financials: Clustered Index (YearMonth, Customer_Id), Non-Clustered (Customer_Id), Non-clustered columnstore index (Economic_Capital)
Dimensions.Customer: Clustered (Customer_Id, CRU_Id), Non-clustered (CRU_Id), Non-clustered (Nace_Id)
Dimensions.Organization: Clustered (CRU_Id), Non-clustered (Lvl1_Cd, Lvl2_Cd, Lvl3_Cd) Include (Lvl1_Nm, Lvl2_Nm, Lvl3_Nm, Lvl4_Cd, Lvl4_Nm, CRU_Id, CRU_Name)
Dimensions.Nace: Clustered (Nace_Id)

这是慢查询的执行计划(15秒)

Slow execution plan 缓慢的执行计划XML:Slow execution plan

这是快速执行计划(4秒)

Fast execution plan 快速执行计划XML:Fast execution plan

有人能指出我错过的正确方向吗?我有错误的索引或者这怎么可能发生?

我正在运行SQL Server 2014

3 个答案:

答案 0 :(得分:1)

  

然而,在select语句中没有使用此表中的任何内容。

但是你在join中使用它。所以sql server优化器会选择不同的计划,这里有一些Paul White解释的连接效果: Joining 100 tables

因此即使你没有在选择中使用它,连接可能会有不同的副作用

  

它可以添加额外的列(来自连接表)
      它可以添加额外的行(连接的表可能不止一次匹配源行)
      它可以删除行(连接的表可能没有匹配)
      它可以引入NULL(对于RIGHT或FULL JOIN)

因此,如果你的加入没有添加任何上述副作用,那么你可能会像另一个那样得到计划

答案 1 :(得分:0)

我将采取相反的观点。您正在寻找业务优先和各年/月的总计。因为该字段" Lvl1_Business_Area_Cd"来自您的组织表,并且在WHERE子句中,它强制您从LEFT JOIN到INNER JOIN的查询。同样,客户表因此将成为财务所需的内部联系。

现在,我还要确保此字段和CRU_ID的索引,因为它是加入客户的基础......所以

create index Lvl1CruID on Organization ( Lvl1_Business_Area_Cd, CRU_ID )

同样,客户和财务之间的加入速度更快

create index CruID_CustomerID on Customer ( Cru_ID, Customer_ID )

通过这种方式,引擎无需转到原始数据页面即可获得从组织到财务的连接条件,以及客户表中的每条记录。

最后,您的财务表索引年/月和客户应该是好的。我将标准移到了JOIN而不是WHERE。

SELECT
      O.Lvl1_Business_Area_Cd,
      O.Lvl1_Business_Area_Nm,
      O.Lvl2_Division_Cd,
      O.Lvl2_Division_Nm,
      SUM(F.Economic_Capital) Economic_Capital
   FROM
      Dimensions.Organization O 
         JOIN Dimensions.Customer C 
            ON O.CRU_Id = C.CRU_Id
               JOIN Facts.Financials F
                  ON F.Year_Month_Id = 201706
                 AND C.Customer_Id = F.Customer_Id 
   WHERE 
      O.Lvl1_Business_Area_Cd = 6008000
   GROUP BY
      O.Lvl1_Business_Area_Cd,
      O.Lvl1_Business_Area_Nm,
      O.Lvl2_Division_Cd,
      O.Lvl2_Division_Nm

拥有良好的索引并更好地了解它们如何工作至关重要,尤其是在多个表之间传递以获取基础细节。

现在,如果您想要所有组织,即使他们没有任何财务活动,您也可以将金融联接更改为LEFT JOIN。

通过尝试预聚合方法,这可能会更好..

SELECT
      O.Lvl1_Business_Area_Cd,
      O.Lvl1_Business_Area_Nm,
      O.Lvl2_Division_Cd,
      O.Lvl2_Division_Nm,
      PreQuery.Economic_Capital
   FROM
      Dimensions.Organization O 
         JOIN Dimensions.Customer C 
            ON O.CRU_Id = C.CRU_Id
               JOIN 
               ( select F.Customer_ID, 
                        SUM(F.Economic_Capital) Economic_Capital
                    from
                       Facts.Financials F
                    where 
                       F.Year_Month_Id = 201706
                    group by
                       F.Customer_ID ) PreQuery
                 AND C.Customer_Id = PreQuery.Customer_Id 
   WHERE 
      O.Lvl1_Business_Area_Cd = 6008000

答案 2 :(得分:0)

一两天后,SQL Server已经制定了一个新的查询计划,使得两者几乎同样快。还是不知道为什么。

之后我切换到主表上的聚集columstore索引,为我的查询提供更快的响应时间。

相关问题