У меня есть процедура 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 имеет такое поведение?