Sql 使用cte ROW_NUMBER()提高性能
我在下面的脚本中遇到了性能问题 开始时,脚本大约运行几秒钟 现在,它需要运行大约3分钟 我认为最主要的原因是Sql 使用cte ROW_NUMBER()提高性能,sql,sql-server,tsql,query-optimization,Sql,Sql Server,Tsql,Query Optimization,我在下面的脚本中遇到了性能问题 开始时,脚本大约运行几秒钟 现在,它需要运行大约3分钟 我认为最主要的原因是TransactionSendQueue表,它目前有300多万行。在“ctetran”中,我需要找出最新的记录并与temp表进行比较 我尝试添加不同的索引,但它不能改善它甚至更慢。关于如何提高绩效的任何建议 WITH ctetran AS --the lastest transaction ( SELECT Tran_ID, Field2,
TransactionSendQueue
表,它目前有300多万行。在“ctetran”中,我需要找出最新的记录并与temp表进行比较
我尝试添加不同的索引,但它不能改善它甚至更慢。关于如何提高绩效的任何建议
WITH ctetran AS --the lastest transaction
(
SELECT
Tran_ID,
Field2,
Field3,
Field4,
Field5,
Field6,
Field7,
Field8,
Field9,
ROW_NUMBER() OVER (PARTITION BY Tran_ID
ORDER BY LastUpdate DESC) AS rn
FROM
TransactionSendQueue
WHERE
STATUS = '1'
) --where 1 mean complete
UPDATE temp
SET STATUS = CASE
WHEN temp.f2 = cte.Field2
AND temp.f3 = cte.Field3
AND temp.f4 = cte.Field4
AND temp.f5 = cte.Field5
AND temp.f6 = cte.Field6
AND temp.f7 = cte.Field7
AND temp.f8 = cte.Field8
AND temp.f9 = cte.Field9
THEN '2' -- where 2 mean skip
ELSE '3' --where 3 mean ready to execute
END
FROM #TempTran temp
INNER JOIN ctetran cte ON temp.Tran_ID = cte.Tran_ID
AND cte.rn = 1;
表格设计:
CREATE TABLE [dbo].[TransactionSendQueue]
(
[Batch_ID] [CHAR](20) NOT NULL,
[Tran_ID] [VARCHAR](20) NOT NULL,
[Field2] [VARBINARY](100) NULL,
[Field3] [VARBINARY](100) NULL,
[Field4] [VARBINARY](100) NULL,
[Field5] [VARBINARY](100) NULL,
[Field6] [VARBINARY](100) NULL,
[Field7] [VARBINARY](100) NULL,
[Field8] [VARBINARY](100) NULL,
[Field9] [VARBINARY](100) NULL,
[LastUpdate] [DATETIME] NOT NULL,
[STATUS] [INTEGER] NOT NULL,
CONSTRAINT [PK_TransactionSendQueue]
PRIMARY KEY CLUSTERED([Batch_ID], [Tran_ID])
);
使用多个步骤执行SQL查询时,一个核心原则是:尽早消除尽可能多的数据。当您只需要每个事务ID的最新事务时,您的CTE从TransactionSendQueue加载所有行。处理的数据越多,加载的数据写入磁盘的风险越高,这对性能极为不利。写入磁盘的数据越多,影响就越严重。你可以查看你的执行计划,看看是否是这样,但我认为这可能是考虑到执行时间 CTE每行只能返回一行,这些行可能会在#tentran表中更新。您可以使用附加的CTE首先检索最新的更新,然后在ctetran中使用该信息来减少在update语句中搜索的数据量(行)
WITH LatestTran AS --the lastest transaction
(
SELECT
Tran_ID,
MAX(LastUpdate) AS LastUpdate
FROM
TransactionSendQueue
WHERE
STATUS = '1' --where 1 mean complete
GROUP BY
Tran_ID
), ctetran AS
(
SELECT
Tran_ID,
Field2,
Field3,
Field4,
Field5,
Field6,
Field7,
Field8,
Field9
FROM
TransactionSendQueue TSQ
INNER JOIN LatestTran LT ON
TSQ.Tran_ID = LT.Tran_ID AND
TSQ.LastUpdate = LT.LastUpdate
)
UPDATE temp
SET STATUS = CASE
WHEN temp.f2 = cte.Field2
AND temp.f3 = cte.Field3
AND temp.f4 = cte.Field4
AND temp.f5 = cte.Field5
AND temp.f6 = cte.Field6
AND temp.f7 = cte.Field7
AND temp.f8 = cte.Field8
AND temp.f9 = cte.Field9
THEN '2' -- where 2 mean skip
ELSE '3' --where 3 mean ready to execute
END
FROM #TempTran temp
INNER JOIN ctetran cte ON temp.Tran_ID = cte.Tran_ID
这将有多大的性能提升取决于每个Tran\u ID有多少批处理ID,越多性能提升越大
如果查询仍然运行缓慢,您还可以研究在TransactionSendQueue表中使用LastUpdate列的索引,因为查询现在在join语句中使用该索引
WITH LatestTran AS --the lastest transaction
(
SELECT
Tran_ID,
MAX(LastUpdate) AS LastUpdate
FROM
TransactionSendQueue
WHERE
STATUS = '1' --where 1 mean complete
GROUP BY
Tran_ID
), ctetran AS
(
SELECT
Tran_ID,
Field2,
Field3,
Field4,
Field5,
Field6,
Field7,
Field8,
Field9
FROM
TransactionSendQueue TSQ
INNER JOIN LatestTran LT ON
TSQ.Tran_ID = LT.Tran_ID AND
TSQ.LastUpdate = LT.LastUpdate
)
UPDATE temp
SET STATUS = CASE
WHEN temp.f2 = cte.Field2
AND temp.f3 = cte.Field3
AND temp.f4 = cte.Field4
AND temp.f5 = cte.Field5
AND temp.f6 = cte.Field6
AND temp.f7 = cte.Field7
AND temp.f8 = cte.Field8
AND temp.f9 = cte.Field9
THEN '2' -- where 2 mean skip
ELSE '3' --where 3 mean ready to execute
END
FROM #TempTran temp
INNER JOIN ctetran cte ON temp.Tran_ID = cte.Tran_ID
请告诉我查询时间减少了多少,我很想知道。对于性能相关的问题,我们需要使用“粘贴计划”查看执行计划。使用CTE尝试的简单方法是将其具体化到临时表中。因此,将您的cte查询结果放入临时表中,然后对cte结果执行您通常执行的任何操作。这通常可以解决cte性能问题。不过基本的cte查询仍然很慢,那么我们需要执行计划。@DaleK谢谢。执行计划很难共享。我正在尝试将其转换为临时表并再次测试。谢谢我说的使用“粘贴计划”-它正是为了这个目的。请添加索引的定义,以及临时表的定义,也共享查询计划