Я опубликовал что-то подобное раньше, но сейчас я приближаюсь к этому с другого направления, поэтому я открыл новый вопрос. Я надеюсь, что все в порядке.
Я работаю с CTE, который создает сумму сборов на основе родительской платы. SQL и детали можно увидеть здесь:
Рекомендации CTE в таблице с несколькими ключами
Я не думаю, что я что-то пропускаю в CTE, но у меня возникает проблема, когда я использую его с большой таблицей данных (3,5 миллиона строк).
В таблице tblChargeShare
содержится другая информация, которая мне нужна, например InvoiceID
, поэтому я поместил CTE в представление vwChargeShareSubCharges
и присоединил его к таблице.
Запрос:
Select t.* from vwChargeShareSubCharges t
inner join
tblChargeShare s
on t.CustomerID = s.CustomerID
and t.MasterChargeID = s.ChargeID
Where s.ChargeID = 1291094
Возвращает результат в несколько мс.
Запрос:
Select ChargeID from tblChargeShare Where InvoiceID = 1045854
Возвращает 1 строку:
1291094
Но запрос:
Select t.* from vwChargeShareSubCharges t
inner join
tblChargeShare s
on t.CustomerID = s.CustomerID
and t.MasterChargeID = s.ChargeID
Where InvoiceID = 1045854
Выполняется 2-3 минуты.
Я сохранил планы выполнения и загрузил их в SQL Sentry. Дерево для быстрого запроса выглядит следующим образом:
План медленного запроса:
Я попытался переиндексировать, выполнив запрос через советник по настройке и различные комбинации подзапросов. Всякий раз, когда соединение содержит что-либо, кроме ПК, запрос выполняется медленно.
У меня был аналогичный вопрос:
Тайм-аут запроса SQL Server в зависимости от предложения Where
Какие используемые функции выполняют summimg дочерних строк вместо CTE. Это переписать с помощью CTE, чтобы попытаться избежать той же проблемы, с которой я сейчас сталкиваюсь. Я прочитал ответы в этом ответе, но я не мудрее - я прочитал некоторую информацию о подсказках и параметрах, но я не могу заставить его работать. Я думал, что переписывание с использованием CTE решит мою проблему. Запрос выполняется быстро при запуске на tblCharge с несколькими тысячами строк.
Протестировано как в SQL 2008 R2, так и в SQL 2012
Edit:
Я сконфигурировал запрос в один оператор, но та же проблема сохраняется:
WITH RCTE AS
(
SELECT ParentChargeId, s.ChargeID, 1 AS Lvl, ISNULL(TotalAmount, 0) as TotalAmount, ISNULL(s.TaxAmount, 0) as TaxAmount,
ISNULL(s.DiscountAmount, 0) as DiscountAmount, s.CustomerID, c.ChargeID as MasterChargeID
from tblCharge c inner join tblChargeShare s
on c.ChargeID = s.ChargeID Where s.ChargeShareStatusID < 3 and ParentChargeID is NULL
UNION ALL
SELECT c.ParentChargeID, c.ChargeID, Lvl+1 AS Lvl, ISNULL(s.TotalAmount, 0), ISNULL(s.TaxAmount, 0), ISNULL(s.DiscountAmount, 0) , s.CustomerID
, rc.MasterChargeID
from tblCharge c inner join tblChargeShare s
on c.ChargeID = s.ChargeID
INNER JOIN RCTE rc ON c.PArentChargeID = rc.ChargeID and s.CustomerID = rc.CustomerID Where s.ChargeShareStatusID < 3
)
Select MasterChargeID as ChargeID, rcte.CustomerID, Sum(rcte.TotalAmount) as TotalCharged, Sum(rcte.TaxAmount) as TotalTax, Sum(rcte.DiscountAmount) as TotalDiscount
from RCTE inner join tblChargeShare s on rcte.ChargeID = s.ChargeID and RCTE.CustomerID = s.CustomerID
Where InvoiceID = 1045854
Group by MasterChargeID, rcte.CustomerID
GO
Изменить: Больше играть, я просто не понимаю этого.
Этот запрос мгновен (2 мс):
Select t.* from
vwChargeShareSubCharges t
Where t.MasterChargeID = 1291094
Если это занимает 3 минуты:
DECLARE @ChargeID int = 1291094
Select t.* from
vwChargeShareSubCharges t
Where t.MasterChargeID = @ChargeID
Даже если я помещаю кучи чисел в "В", запрос все еще мгновен:
Where t.MasterChargeID in (1291090, 1291091, 1291092, 1291093, 1291094, 1291095, 1291096, 1291097, 1291098, 1291099, 129109)
Изменить 2:
Я могу воспроизвести это с нуля, используя данные этого примера:
Я создал некоторые фиктивные данные для репликации проблемы. Это не так важно, так как я добавил только 100 000 строк, но плохой план выполнения все еще выполняется (выполняется в режиме SQLCMD):
CREATE TABLE [tblChargeTest](
[ChargeID] [int] IDENTITY(1,1) NOT NULL,
[ParentChargeID] [int] NULL,
[TotalAmount] [money] NULL,
[TaxAmount] [money] NULL,
[DiscountAmount] [money] NULL,
[InvoiceID] [int] NULL,
CONSTRAINT [PK_tblChargeTest] PRIMARY KEY CLUSTERED
(
[ChargeID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
END
GO
Insert into tblChargeTest
(discountAmount, TotalAmount, TaxAmount)
Select ABS(CHECKSUM(NewId())) % 10, ABS(CHECKSUM(NewId())) % 100, ABS(CHECKSUM(NewId())) % 10
GO 100000
Update tblChargeTest
Set ParentChargeID = (ABS(CHECKSUM(NewId())) % 60000) + 20000
Where ChargeID = (ABS(CHECKSUM(NewId())) % 20000)
GO 5000
CREATE VIEW [vwChargeShareSubCharges] AS
WITH RCTE AS
(
SELECT ParentChargeId, ChargeID, 1 AS Lvl, ISNULL(TotalAmount, 0) as TotalAmount, ISNULL(TaxAmount, 0) as TaxAmount,
ISNULL(DiscountAmount, 0) as DiscountAmount, ChargeID as MasterChargeID
FROM tblChargeTest Where ParentChargeID is NULL
UNION ALL
SELECT rh.ParentChargeID, rh.ChargeID, Lvl+1 AS Lvl, ISNULL(rh.TotalAmount, 0), ISNULL(rh.TaxAmount, 0), ISNULL(rh.DiscountAmount, 0)
, rc.MasterChargeID
FROM tblChargeTest rh
INNER JOIN RCTE rc ON rh.PArentChargeID = rc.ChargeID --and rh.CustomerID = rc.CustomerID
)
Select MasterChargeID, ParentChargeID, ChargeID, TotalAmount, TaxAmount, DiscountAmount , Lvl
FROM RCTE r
GO
Затем запустите эти два запроса:
--Slow Query:
Declare @ChargeID int = 60900
Select *
from [vwChargeShareSubCharges]
Where MasterChargeID = @ChargeID
--Fast Query:
Select *
from [vwChargeShareSubCharges]
Where MasterChargeID = 60900