Napisałem coś podobnego wcześniej, ale zbliżam się do tego z innego kierunku, więc otworzyłem nowe pytanie. Mam nadzieję, że to jest w porządku.CTE bardzo powolny, gdy dołączyłem
Pracowałem z CTE, który tworzy sumę opłat w oparciu o Parent Charge. SQL i szczegóły można zobaczyć tutaj:
CTE Index recommendations on multiple keyed table
Nie sądzę, brakuje mi niczego na CTE, ale jestem coraz problem, gdy używam go z dużym stołem danych (3,5 mln wydziwianie).
Tabela tblChargeShare
zawiera kilka innych informacji, których potrzebuję, takich jak InvoiceID
, więc umieściłem mój CTE w widoku vwChargeShareSubCharges
i dołączyłem go do stołu.
Zapytanie:
Select t.* from vwChargeShareSubCharges t
inner join
tblChargeShare s
on t.CustomerID = s.CustomerID
and t.MasterChargeID = s.ChargeID
Where s.ChargeID = 1291094
Zwraca wynik w ciągu kilku ms.
Zapytanie:
Select ChargeID from tblChargeShare Where InvoiceID = 1045854
zwraca 1 wiersz:
1291094
Ale zapytania:
Select t.* from vwChargeShareSubCharges t
inner join
tblChargeShare s
on t.CustomerID = s.CustomerID
and t.MasterChargeID = s.ChargeID
Where InvoiceID = 1045854
trwa 2-3 minut, aby uruchomić.
Zapisałem plany wykonania i wczytałem je do SQL Sentry. Drzewo do szybkiego zapytania wygląda następująco:
Plan z powolnym zapytania jest:
Próbowałem reindeksowania, uruchamiając zapytanie poprzez doradcę strojenia i różnych kombinacjach podrzędnych zapytań. Gdy sprzężenie zawiera coś innego niż PK, zapytanie jest wolne.
miałem podobne pytanie tutaj:
SQL Server Query time out depending on Where Clause
Które używane funkcje zrobić summimg wierszy podrzędnych zamiast CTE. To jest przepisywanie za pomocą CTE, aby spróbować uniknąć tego samego problemu, którego teraz doświadczam. Przeczytałem odpowiedzi w tej odpowiedzi, ale nie jestem mądrzejszy - przeczytałem kilka informacji o podpowiedziach i parametrach, ale nie mogę tego zrobić. Myślałem, że przepisanie za pomocą CTE rozwiąże mój problem. Zapytanie jest szybkie, gdy działa na tblCharge z kilkoma tysiącami wierszy.
badana w obu SQL 2008 R2 i SQL 2012
Edit:
Mam skondensowane zapytanie do pojedynczej instrukcji, ale ten sam problem będzie się powtarzał:
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
Edycja : Więcej zabawy, po prostu tego nie rozumiem.
Ta kwerenda jest błyskawiczne (2 ms):
Select t.* from
vwChargeShareSubCharges t
Where t.MasterChargeID = 1291094
niniejsza trwa 3 minuty:
DECLARE @ChargeID int = 1291094
Select t.* from
vwChargeShareSubCharges t
Where t.MasterChargeID = @ChargeID
Nawet jeśli kładę stosy liczb w "in", zapytanie jest jeszcze chwila :
Where t.MasterChargeID in (1291090, 1291091, 1291092, 1291093, 1291094, 1291095, 1291096, 1291097, 1291098, 1291099, 129109)
Edit 2:
można replikować to od podstaw przy użyciu ten przykład dane:
Stworzyłem niektóre dane manekina do replikowania problem. To nie jest tak istotna, jak tylko dodaje 100.000 wierszy, ale zły plan wykonania nadal dzieje (prowadzony w trybie 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
Następnie uruchomić te dwa zapytania:
--Slow Query:
Declare @ChargeID int = 60900
Select *
from [vwChargeShareSubCharges]
Where MasterChargeID = @ChargeID
--Fast Query:
Select *
from [vwChargeShareSubCharges]
Where MasterChargeID = 60900
Tylko szybka myśl ... Jeśli wziąć zapytanie 'Wybierz t. * Od vwChargeShareSubCharges t' wymienić pogląd' vwChargeShareSubCharges' z jego rzeczywistej definicji tsql, przyłączyć do innych tabel w stosownych przypadkach, a run zapytanie, czy to szybciej? – DMason
Dokładnie to samo, jeśli wkleję w pełnym CTE. – Molloch