如何诊断缓慢/不一致的SQL Server查询?

时间:2019-02-23 01:41:00

标签: sql-server-2012 windows-server-2012-r2 hyper-v recursive-cte

运行Windows Server 2012,Hyper-V,SQL Server 2012主动/被动故障转移群集,带有两个8处理器,60GB节点,单个实例,300个数据库。该查询产生的结果不一致,运行时间在10到30秒之间。

DECLARE @OrgID           BigInt = 780246
DECLARE @ActiveOnly      Bit = 0
DECLARE @RestrictToOrgID Bit = 0;

WITH og (OrgID, GroupID) AS
  (
  SELECT ID, ID FROM Common.com.Organizations WHERE ISNULL(ParentID, 0) <> ID 
  UNION ALL
  SELECT o.ID, og.GroupID FROM Common.com.Organizations o JOIN og ON og.OrgID = o.ParentID
  )

   SELECT e.*, v.Type AS VendorType, v.F1099, v.F1099Type, v.TaxID, v.TaxPercent,
          v.ContactName, v.ContactPhone, v.ContactEMail, v.DistrictWide, 
          a.*
     FROM og
     JOIN books.Organizations           bo ON  bo.CommonID = og.OrgID
     JOIN books.Organizations           po ON  po.CommonID = og.GroupID
     JOIN books.Entities                e  ON   e.OrgID    = po.ID
     JOIN Vendors                       v  ON   v.ID       =  e.ID 
                                           AND (e.OrgID    = bo.ID OR v.DistrictWide = 1)
LEFT JOIN Addresses                     a  ON   a.ID       =  e.AddressID
    WHERE bo.ID = @OrgID
      AND (@ActiveOnly      = 0 OR e.Active = 1)
      AND (@RestrictToOrgID = 0 OR e.OrgID  = @OrgID)
 ORDER BY e.EntityName

LEFT JOIN Addresses替换为JOIN Addresses

     JOIN Addresses                     a  ON   a.ID       =  e.AddressID
    WHERE bo.ID = @OrgID
      AND (@ActiveOnly      = 0 OR e.Active = 1)
      AND (@RestrictToOrgID = 0 OR e.OrgID  = @OrgID)
 ORDER BY e.EntityName

或将Addresses中选择的列的长度减少到少于100个字节

   SELECT e.*, v.Type AS VendorType, v.F1099, v.F1099Type, v.TaxID, v.TaxPercent,
          v.ContactName, v.ContactPhone, v.ContactEMail, v.DistrictWide, 
          a.Fax

将执行时间减少到大约0.5秒。

此外,使用SELECT DISTINCT并将books.EntitiesVendors连接起来

   SELECT DISTINCT e.*, v.Type AS VendorType, v.F1099, v.F1099Type, v.TaxID, v.TaxPercent,
          v.ContactName, v.ContactPhone, v.ContactEMail, v.DistrictWide, 
          a.*
     FROM og
     JOIN books.Organizations           bo ON  bo.CommonID = og.OrgID
     JOIN books.Organizations           po ON  po.CommonID = og.GroupID
     JOIN Vendors                       v  
     JOIN books.Entities                e  ON   v.ID       =  e.ID 
                                           ON   e.OrgID    = bo.ID OR (e.OrgID = po.ID AND v.DistrictWide = 1)

将时间减少到大约.75秒。

摘要

这些条件表明,SQL Server实例中存在某种资源限制,导致这些不稳定的结果,而且我不知道如何进行诊断。如果我将有问题的数据库复制到运行SQL Server 2012的笔记本电脑上,则不会出现此问题。我可以继续更改SQL,并希望获得最佳结果,但我希望找到更确定的解决方案。

任何建议都值得赞赏。

更新2/27/18

未经修改的查询的执行计划将针对“地址”表的聚簇索引寻求作为问题。 Clustered Index Seek against the Addresses table

Addresses中选择的列的长度减少到少于100个字节

   SELECT e.*, v.Type AS VendorType, v.F1099, v.F1099Type, v.TaxID, v.TaxPercent,
          v.ContactName, v.ContactPhone, v.ContactEMail, v.DistrictWide, 
          a.Fax

将聚簇索引搜索替换为聚簇索引扫描以检索a.Fax,并使用散列匹配将该值加入结果中。

Hash Match

Addresses表主键的创建过程如下:

   ALTER TABLE dbo.Addresses 
ADD CONSTRAINT PK_Addresses PRIMARY KEY CLUSTERED (ID ASC)
          WITH (PAD_INDEX = OFF, 
                STATISTICS_NORECOMPUTE = OFF, 
                SORT_IN_TEMPDB         = OFF, 
                IGNORE_DUP_KEY         = OFF, 
                ONLINE                 = OFF, 
                ALLOW_ROW_LOCKS        = ON, 
                ALLOW_PAGE_LOCKS       = ON) 
            ON  PRIMARY

每天根据需要对索引进行碎片整理和优化。

到目前为止,对于为什么聚簇索引查找为查询增加了这么多时间,我找不到任何帮助。

1 个答案:

答案 0 :(得分:0)

好吧,就像通常这样,不是一个问题,而是两个问题。这是一个复杂的问题分析可能导致错误结论的例子。

原来的主要问题是递归CTE og,该CTE返回一个透视表,该透视表给出了组织之间的父/子关系。但是,对执行计划的分析似乎表明,问题是优化器中的某种故障,与从左联接表返回的数据量有关。这可能完全是我无法正确分析执行计划的结果,但是在这种情况下,SQL Server 2012 SP4如何创建执行计划似乎确实存在一些问题。

尽管在我们的生产服务器上更为重要,但是SQL Server递归CTE优化的问题在运行2012 SP4的本地主机和运行SP2的登台服务器上均显而易见。但是需要进一步的分析和一些猜测才能看到它。

解决方案

我用数据透视表替换了递归CTE,并向组织表添加了一个触发器以对其进行维护。

USE Common
GO

CREATE VIEW com.OrganizationGroupsCTE
AS
  WITH cte (OrgID, GroupID) AS
    (
    SELECT ID, ID FROM com.Organizations WHERE ISNULL(ParentID, 0) <> ID 
    UNION ALL
    SELECT o.ID, cte.GroupID FROM com.Organizations o JOIN cte ON cte.OrgID = o.ParentID
    )

  SELECT OrgID, GroupID FROM cte
GO

CREATE TABLE com.OrganizationGroups 
  (
  OrgID   BIGINT, 
  GroupID BIGINT
  )

INSERT com.OrganizationGroups 
SELECT OrgID, GroupID 
  FROM com.OrganizationGroupsCTE
GO

CREATE TRIGGER TR_OrganizationGroups ON com.Organizations AFTER INSERT,UPDATE,DELETE
AS
  DELETE og 
    FROM com.OrganizationGroups og 
    JOIN deleted                d   ON d.ID IN (og.groupID, og.orgID);

  INSERT com.OrganizationGroups 
  SELECT orgID, groupID 
    FROM inserted               i 
    JOIN OrganizationGroupsCTE  cte ON i.ID IN (cte.orgID, cte.groupID)
GO

修改查询以使用数据透视表后,

   SELECT e.*, v.Type AS VendorType, v.F1099, v.F1099Type, v.TaxID, v.TaxPercent,
          v.ContactName, v.ContactPhone, v.ContactEMail, v.DistrictWide, 
          a.*
     FROM Common.com.OrganizationGroups og
     JOIN books.Organizations           bo ON  bo.CommonID = og.OrgID
     JOIN books.Organizations           po ON  po.CommonID = og.GroupID
     JOIN books.Entities                e  ON   e.OrgID    = po.ID
     JOIN Vendors                       v  ON   v.ID       =  e.ID 
                                           AND (e.OrgID    = bo.ID OR v.DistrictWide = 1)
LEFT JOIN Addresses                     a  ON   a.ID       =  e.AddressID
    WHERE bo.ID = @OrgID
      AND (@ActiveOnly      = 0 OR e.Active = 1)
      AND (@RestrictToOrgID = 0 OR e.OrgID  = @OrgID)
 ORDER BY e.EntityName

在所有三个环境中,SQL Server的性能均得到了改进,并且保持一致。生产服务器上的问题现在已消除。

SQL Server Performance