2015-12-31 135 views
1

删除索引扫描我的微调下面的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比使用Hint的SQL执行更好。

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

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

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

enter image description here

enter image description here

+2

你'FROM Object8 Object6 INNER JOIN Object9 Object7'是要闹事拍摄了很多的乐趣这走样!这似乎相反的直觉.....为什么别名?对我没有多大意义..... –

+2

因此,在您的情况下索引扫描执行比索引寻求更好:)为什么你想在这里需要索引搜索? –

+1

这也是一个**索引扫描** - SQL Server不扫描整个表 - 只有一个特定的索引。如果该索引很小(例如,只有一列或几列,只有像INT这样的小数据类型),这实际上可能非常有效!如果SQL Server查询优化器选择了此操作,则它可能比强制索引查找更有效...... –

回答

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) 

UPDATE -

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) 
+0

'评论' - 也许是不必要的代码 – Devart

+0

@NewUser需要去...新年快乐给大家! :) – Devart

+0

新年快乐感谢您的解决方案 – StackUser