从执行计划中删除索引扫描

时间:2015-12-31 13:28:17

标签: sql-server sql-server-2012

我正在调整以下SQL查询

    SELECT C.zoneId                  ,
       Count(DISTINCT J.id)      ,
       Sum(BP.InstalledSubtotal) 
FROM   cust C
       INNER JOIN Jobs J
               ON J.CustomerId = C.id
       LEFT OUTER JOIN(SELECT DISTINCT GZZ.ZipAndPostalCodeId,
                                       GZZ.GeographicalZoneId,
                                       gz.DEALERId
                       FROM   GeoZip GZZ
                              INNER JOIN GeographicalZone GZ
                                      ON GZZ.GeographicalZoneId = GZ.Id) CGZ
                    ON CGZ.ZipAndPostalCodeId = C.PhysicalZipId
                       AND CGZ.DEALERId = c.DEALERId
       INNER JOIN BndProduct BP
               ON BP.TableRowId = J.id
                  AND BP.TableId = 23
                  AND BP.InstalledSubtotal <> 0
WHERE  BP.DateCreated BETWEEN 'Nov  1 2015 12:00AM' AND 'Nov 20 2015 11:59PM'
       AND ( Cast(BP.DateCreated AS DATE) <> Cast(J.ContractDate AS DATE)
              OR ( Cast(BP.DateCreated AS DATE) = Cast(J.ContractDate AS DATE)
                   AND BP.EmployeeId <> J.SalesRepId ) )
       AND ( BP.EmployeeId <> 0
             AND BP.EmployeeId IS NOT NULL )
       AND ( J.SalesRepId <> 0
             AND J.SalesRepId IS NOT NULL )
       AND ( EXISTS (SELECT 1
                     FROM   ServLead ISL
                            INNER JOIN Appts IA
                                    ON IA.ServiceLeadId = ISL.id
                            INNER JOIN CalEve IE
                                    ON IE.TableId = 1
                                       AND IE.TableRowId = IA.id
                            INNER JOIN ApptRst IAR
                                    ON IAR.EventId = IE.id
                            INNER JOIN Job IJ
                                    ON IJ.AppointmentResultId = IAR.id
                                       AND IJ.id = J.id
                     WHERE  ( ISL.IsTemporary = 0 )
                            AND ( IA.IsTemporary = 0 )
                            AND ( IE.IsTemporary = 0 )
                            AND ( IAR.IsTemporary = 0 ))
              OR J.ProductionTypeId = 2 )
       AND ( BP.IsDeleted = 0 )
       AND ( C.IsTemporary = 0 )
       AND ( J.IsTemporary = 0 )
       AND ( C.ZoneId = 0
              OR 0 = 0 )
       AND ( CGZ.GeographicalZoneId = 0
              OR 0 = 0 )
       AND CASE '0'
             WHEN 'STATE' THEN C.PhysicalState
             WHEN '' THEN 0
             ELSE 0
           END LIKE 0
       AND C.DEALERId = 23
GROUP  BY C.zoneId  

请参阅执行计划。

enter image description here

有一个索引扫描。我不知道如何将其改为索引搜索。

我尝试了如下所示的提示。

with (forceseek)

但是当我将普通SQL和SQL的结果与提示进行比较时。正常SQL比带有提示的SQL表现更好。

请提供任何即兴查询的建议。 目前它花了大约5至6秒。我试图把它减少到1-2秒。

@Devart:我已经实现了你的解决方案,但似乎执行时间相同。

请按照要求检查执行计划。

enter image description here

enter image description here

1 个答案:

答案 0 :(得分:1)

DECLARE @t TABLE (ID INT PRIMARY KEY)

INSERT INTO @t (ID)
SELECT /*DISTINCT*/ IJ.id
FROM ServLead ISL
JOIN Appts IA ON IA.ServiceLeadId = ISL.id
JOIN CalEve IE ON IE.TableId = 1 AND IE.TableRowId = IA.id
JOIN ApptRst IAR ON IAR.EventId = IE.id
JOIN Job IJ ON IJ.AppointmentResultId = IAR.id
WHERE ISL.IsTemporary = 0
    AND IA.IsTemporary = 0
    AND IE.IsTemporary = 0
    AND IAR.IsTemporary = 0

SELECT C.zoneId,
       COUNT(DISTINCT J.id),
       SUM(BP.InstalledSubtotal)
FROM cust C
JOIN Jobs J ON J.CustomerId = C.id
--LEFT JOIN (
--    SELECT DISTINCT GZZ.ZipAndPostalCodeId,
--                    GZZ.GeographicalZoneId,
--                    GZ.DEALERId
--    FROM GeoZip GZZ
--    JOIN GeographicalZone GZ ON GZZ.GeographicalZoneId = GZ.id
--) CGZ ON CGZ.ZipAndPostalCodeId = C.PhysicalZipId
--    AND CGZ.DEALERId = C.DEALERId
JOIN BndProduct BP ON BP.TableRowId = J.id
    AND BP.TableId = 23
    AND BP.InstalledSubtotal <> 0
WHERE BP.DateCreated BETWEEN '20151101 12:00AM' AND '20151120 11:59PM'
    AND (
            CAST(BP.DateCreated AS DATE) <> CAST(J.ContractDate AS DATE)
        OR (
                CAST(BP.DateCreated AS DATE) = CAST(J.ContractDate AS DATE)
            AND
                BP.EmployeeId <> J.SalesRepId)
        )
    AND BP.EmployeeId <> 0
    AND J.SalesRepId <> 0
    AND (EXISTS (
        SELECT 1
        FROM @t IJ
        WHERE IJ.id = J.id
    ) OR J.ProductionTypeId = 2)
    AND BP.IsDeleted = 0
    AND C.IsTemporary = 0
    AND J.IsTemporary = 0
    AND (C.ZoneId = 0 OR 0 = 0)
    --AND (CGZ.GeographicalZoneId = 0 OR 0 = 0)
    AND C.DEALERId = 23
GROUP BY C.zoneId
OPTION(RECOMPILE)

更新 -

CREATE NONCLUSTERED INDEX ix
    ON dbo.ServLead (id) WHERE IsTemporary = 0
GO
CREATE NONCLUSTERED INDEX ix
    ON dbo.Appts (ServiceLeadId) INCLUDE(id) WHERE IsTemporary = 0
GO
CREATE NONCLUSTERED INDEX ix
    ON dbo.CalEve (TableRowId) INCLUDE(id) WHERE IsTemporary = 0 AND TableId = 1 
GO
CREATE NONCLUSTERED INDEX ix
    ON dbo.ApptRst (EventId) INCLUDE(id) WHERE IsTemporary = 0
GO
CREATE NONCLUSTERED INDEX ix
    ON dbo.Job (AppointmentResultId) INCLUDE(id)
GO

ALTER TABLE dbo.BndProduct
    ADD DateCreated_DT AS CAST(DateCreated AS DATE) PERSISTED
GO
ALTER TABLE dbo.Jobs
    ADD ContractDate_DT AS CAST(ContractDate AS DATE) PERSISTED
GO

DECLARE @t TABLE (ID INT PRIMARY KEY)
INSERT INTO @t
SELECT /*DISTINCT*/ IJ.id
FROM dbo.ServLead ISL
JOIN dbo.Appts IA ON IA.ServiceLeadId = ISL.id
JOIN dbo.CalEve IE ON IE.TableId = 1 AND IE.TableRowId = IA.id
JOIN dbo.ApptRst IAR ON IAR.EventId = IE.id
JOIN dbo.Job IJ ON IJ.AppointmentResultId = IAR.id
WHERE ISL.IsTemporary = 0
    AND IA.IsTemporary = 0
    AND IE.IsTemporary = 0
    AND IAR.IsTemporary = 0
--OPTION(RECOMPILE)

DECLARE @c TABLE
(
    ZipAndPostalCodeId INT,
    DEALERId INT,
    GeographicalZoneId INT,
    PRIMARY KEY (ZipAndPostalCodeId, DEALERId, GeographicalZoneId)
)
INSERT INTO @c (ZipAndPostalCodeId, GeographicalZoneId, DEALERId)
SELECT DISTINCT GZZ.ZipAndPostalCodeId,
                GZZ.GeographicalZoneId,
                GZ.DEALERId
FROM dbo.GeoZip GZZ
JOIN dbo.GeographicalZone GZ ON GZZ.GeographicalZoneId = GZ.id

SELECT C.zoneId,
       COUNT(DISTINCT J.id),
       SUM(BP.InstalledSubtotal)
FROM dbo.cust C
JOIN dbo.Jobs J ON J.CustomerId = C.id
LEFT JOIN @c CGZ ON CGZ.ZipAndPostalCodeId = C.PhysicalZipId AND CGZ.DEALERId = C.DEALERId
JOIN dbo.BndProduct BP ON BP.TableRowId = J.id
WHERE BP.DateCreated BETWEEN '20151101 12:00AM' AND '20151120 11:59PM'
    AND (
            BP.DateCreated_DT <> J.ContractDate_DT
        OR (
                BP.DateCreated_DT = J.ContractDate_DT
            AND
                BP.EmployeeId <> J.SalesRepId)
        )
    AND BP.EmployeeId <> 0
    AND BP.TableId = 23
    AND BP.InstalledSubtotal <> 0
    AND J.SalesRepId <> 0
    AND (J.id IN (SELECT t.ID FROM @t t) OR J.ProductionTypeId = 2)
    AND BP.IsDeleted = 0
    AND C.IsTemporary = 0
    AND J.IsTemporary = 0
    AND (C.ZoneId = 0 OR 0 = 0)
    AND (CGZ.GeographicalZoneId = 0 OR 0 = 0)
    AND C.DEALERId = 23
GROUP BY C.zoneId
OPTION(RECOMPILE)