【发布时间】:2014-05-13 11:39:54
【问题描述】:
我之前发布过类似的内容,但我现在从不同的方向来处理这个问题,所以我提出了一个新问题。我希望这没问题。
我一直在与 CTE 合作,该 CTE 根据父费用创建费用总和。 SQL和细节可以在这里看到:
CTE Index recommendations on multiple keyed table
我认为我在 CTE 上没有遗漏任何内容,但是当我将它与大数据表(350 万行)一起使用时遇到了问题。
表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 中。快速查询的树如下所示:
慢查询的计划是:
我尝试过重新索引、通过优化顾问和各种子查询组合运行查询。只要连接包含 PK 以外的任何内容,查询就会很慢。
我在这里也有类似的问题:
SQL Server Query time out depending on Where Clause
它使用函数对子行进行求和,而不是 CTE。这是使用 CTE 进行的重写,以尝试避免我现在遇到的相同问题。我已经阅读了该答案中的回复,但我并不聪明 - 我阅读了一些关于提示和参数的信息,但我无法让它发挥作用。我曾认为使用 CTE 重写会解决我的问题。在几千行的 tblCharge 上运行时,查询速度很快。
在 SQL 2008 R2 和 SQL 2012 中测试
编辑:
我已将查询压缩为一条语句,但同样的问题仍然存在:
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
编辑: 多玩玩,我就是不明白。
这个查询是即时的(2ms):
Select t.* from
vwChargeShareSubCharges t
Where t.MasterChargeID = 1291094
而这需要 3 分钟:
DECLARE @ChargeID int = 1291094
Select t.* from
vwChargeShareSubCharges t
Where t.MasterChargeID = @ChargeID
即使我将成堆的数字放在“In”中,查询仍然是即时的:
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
【问题讨论】:
-
只是一个快速的想法...如果您使用查询
Select t.* from vwChargeShareSubCharges t,将视图vwChargeShareSubCharges替换为其实际的tsql 定义,酌情加入其他表,然后运行查询,是更快吗? -
完全一样,如果我粘贴完整的 CTE。
标签: sql sql-server-2008-r2 common-table-expression