Хранимая процедура не может правильно использовать индекс вида - PullRequest
0 голосов
/ 15 января 2020

У меня есть процедура Store, в которой используется индексированное представление.

ALTER PROCEDURE [dbo].[usp_ODS_GetIntegrityReport] 
   @StartDate AS DATE,
   @EndDate AS DATE,
   @Type AS VARCHAR(20) = 'Report'
AS
BEGIN
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

    CREATE TABLE #TargetLayer (_TargetLayerID INT, _TargetLayerLinkID INT, TargetLayerType VARCHAR(50), Pos VARCHAR(100), Store VARCHAR(100), Enterprise VARCHAR(100), Code VARCHAR(50));    
    INSERT INTO #TargetLayer 

    SELECT _TargetLayerID, _TargetLayerLinkID, TargetLayerType, Pos, Store, Enterprise, Code FROM vFilteredTargetLayers; 

    SELECT  A.[Date],
                A.Code,
                A._TargetLayerLinkID,
                A.Enterprise,
                A.Store,
                MAX(A.Pos) AS Pos,
                SUM(A.Total) AS Total,
                SUM(A.Fin_Total) AS Fin_Total,
                ABS(CONVERT(DECIMAL(18,2), SUM(A.Total) - SUM(A.Fin_Total))) AS Diff,
                CASE WHEN SUM(A.Total) = 0 THEN 0
                     WHEN SUM(A.Fin_Total) = 0 THEN 0
                     ELSE (1 - ABS((CONVERT(DECIMAL(18,2), SUM(A.Total) - SUM(A.Fin_Total))) / ISNULL(IIF(SUM(A.Fin_Total) = 0, NULL, SUM(A.Fin_Total)), 1))) * 100 
                END AS IntegrityPrc
        FROM
        (
            SELECT t.TransactionDate AS [Date], 
                   tl._TargetLayerLinkID,
                   tl.Enterprise,
                   tl.Store,
                   tl.Pos,
                   tl.Code,
                   SUM(t.Price) AS Total,
                   0 AS Fin_Total
            FROM vSales t
            JOIN #TargetLayer tl ON tl._TargetLayerID = t._TargetLayerID
            WHERE t.TransactionDate >= @StartDate AND t.TransactionDate <= @EndDate AND
                  t.TransactionStatus = 'CLOSED' AND TransactionType = 'INVOICE' AND
                  tl.TargetLayerType = 'POS'                  
            GROUP BY t.TransactionDate, tl._TargetLayerID, tl._TargetLayerLinkID, tl.Enterprise, tl.Store, tl.Pos, tl.Code

            UNION ALL

            SELECT FIN.[DateAdd] AS [Date],
                   FIN._TargetLayerID AS _TargetLayerLinkID,
                   tl.Enterprise,
                   tl.Store,
                   tl_pos.Pos,
                   fin.TermNbr AS Code,
                   0 AS Total,
                   fin.Total
            FROM vIntegrityFinancial fin
            JOIN #TargetLayer tl ON tl._TargetLayerID = fin._TargetLayerID
            LEFT JOIN #TargetLayer tl_pos ON tl_pos._TargetLayerLinkID = tl._TargetLayerID AND tl_pos.Code = fin.TermNbr AND tl.TargetLayerType = 'STORE'
            WHERE FIN.[DateAdd] >= @StartDate AND FIN.[DateAdd] <= @EndDate AND FIN.Totalizer = 3
            AND tl_pos.TargetLayerType = 'POS'
        ) AS A
        GROUP BY A._TargetLayerLinkID,
                 A.Enterprise,
                 A.Store,
                 A.[Date], 
                 A.Code
        ORDER BY A.[Date],
                 A.Code

    END

    DROP TABLE #TargetLayer
END

Представление имеет следующий индекс:

CREATE UNIQUE CLUSTERED INDEX [UIDX_vSales] ON [dbo].[vSales]
(
  [TransactionDate] DESC,
  [_TargetLayerID] ASC,
  [_TransactionBodyID] ASC
)

Если я беру содержимое своей хранимой процедуры и измените параметры даты @StartDate и @EndDate напрямую для требуемого значения, например:

 ...
 ...
 WHERE t.TransactionDate >= '2019-09-01' AND t.TransactionDate <= '2019-09-07' AND
              t.TransactionStatus = 'CLOSED' AND TransactionType = 'INVOICE' AND
              tl.TargetLayerType = 'POS'

Для запуска требуется около 1 секунды (у меня 500 000 + записей для этих дат.

Но когда я запускаю свою хранимую процедуру следующим образом:

exec usp_ODS_GetIntegrityReport  @StartDate ='2019-09-01',  @EndDate='2019-09-02'

Это может занять от 1 минуты до 1 минуты 30 секунд.

Я проанализировал план выполнения, и похоже, что хранимая процедура не использует индекс представления, когда параметры используются, но используют индекс, когда значения находятся непосредственно в предложении where.

Я много раз искал и уже пытался использовать переменные параметры, чтобы избежать перехвата параметров et c, но ничего не работает.

Есть идеи, почему sql имеет такое поведение?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...