优化 SQL Server 查询以提高速度
Posted
技术标签:
【中文标题】优化 SQL Server 查询以提高速度【英文标题】:Optimize SQL Server query for speed 【发布时间】:2015-10-16 07:45:25 【问题描述】:如何优化我的 SQL Server 查询?这是我要优化的代码
CREATE TABLE #Temp
(
TransactionId int PRIMARY KEY,
TransactionStepId int
)
INSERT INTO #Temp(TransactionId, TransactionStepId)
SELECT
TransactionId, MAX(TransactionStepId) TransactionStepId
FROM
[WarehouseMgmt].[FactPaymentTrans] FPT
JOIN
WarehouseMgmt.DimTimeZone DTZ on FPT.[TimeId] = DTZ.TimeUTCId
WHERE
FactType = 'SOURCE'
AND (DTZ.TimeId BETWEEN @DimStartDate AND @DimEndDate)
GROUP BY
TransactionId
IF(UPPER(@ReportBy) = 'TRANSACTION')
BEGIN
SET @sql = '
INSERT INTO #Results (
[PaymentTypeId],
[TransactionDate],
[PaymentMethodId],
[3DSecureId],
[ProductId],
[ProductTypeId],
[TransactionStatusId],
[Amount],
[Currency],
[PlayerId],
[PlayerSourceOrigId],
[Username],
[FirstName],
[LastName],
[BrandId],
[VIPLevelId],
[MarketingChannelId],
[MarketingSourceId],
[CommentId],
[CommentRefId],
[AdminName],
[OriginalTransactionId],
[TransactionId],
[RelatedTransactionId],
[ProviderTransactionOrigId]
)
SELECT
DTST.[Id],
FPT.[StartTime],
FPT.[PaymentMethodId],
FPT.[3DSecureId],
FPT.[ProductId],
DPT.[Id],
FPT.[TransactionStatusId],
FPT.[Amount],
FPT.CurrencyId,
FPT.[PlayerId],
DPL.[SourceOrigId],
DPL.[Username],
DPL.[FirstName],
DPL.[LastName],
DPL.[BrandId],
DPL.[VIPLevelId],
DPL.[MarketingChannelId],
DPL.[MarketingSourceId],
FPT.[PaymentReasonTextId],
FPT_Ref.[PaymentReasonTextId],
FPT.CreatedByAdminId,
FPT.[OriginalTransactionId],
FPT.[TransactionId],
FPT_Ref.[OriginalTransactionId],
FPT.[ProviderTransactionOrigId]
FROM WarehouseMgmt.FactPaymentTrans AS FPT
JOIN #Temp T ON FPT.TransactionId = T.TransactionId AND FPT.TransactionStepId = T.TransactionStepId
JOIN WarehouseMgmt.DimTransactionStepType AS DTST ON FPT.[TransactionStepTypeId] = DTST.[Id]
JOIN WarehouseMgmt.DimPlayer AS DPL ON FPT.PlayerId = DPL.Id
JOIN WarehouseMgmt.DimProduct AS DP ON DP.Id = FPT.ProductId
JOIN WarehouseMgmt.DimProductType AS DPT ON DPT.Id = DP.ProductTypeId
--JOIN WarehouseMgmt.DimTimeZone DTZ on FPT.[TimeId] = DTZ.TimeUTCId
JOIN [WarehouseMgmt].[DimLoyaltyProgramLevel] DLPL ON DLPL.[Id]=DPL.VipLevelId
LEFT JOIN
(
SELECT FPT_Ref_1.TransactionId,FPT_Ref_1.FactType,FPT_Ref_1.OriginalTransactionId,FPT_Ref_1.[PaymentReasonTextId]
FROM WarehouseMgmt.FactPaymentTrans AS FPT_Ref_1
JOIN #Temp T ON T.TransactionId = FPT_Ref_1.OriginalTransactionId AND T.TransactionStepId = FPT_Ref_1.TransactionStepId
) AS FPT_Ref ON FPT_Ref.OriginalTransactionId = FPT.TransactionId AND FPT_Ref.FactType = ''SOURCE''
WHERE (FPT.FactType = ''SOURCE'') ' + @sqlFilters
我试着把这个
SELECT TransactionId,MAX(TransactionStepId) TransactionStepId
FROM [WarehouseMgmt].[FactPaymentTrans]
WHERE FactType = ''SOURCE''
GROUP BY TransactionId
在临时表中,但这比没有临时表更糟糕。我想选择最新的 TransactionId(由 MAX(TransactionStepId) 制作,并且还要选择左侧 JOIN 中的最后一个 TransactionId
我的执行计划是:
【问题讨论】:
你能分享一个执行计划吗?有关表上的索引的详细信息?此外,查询末尾还有一个小撇号。这是否有任何目的(可能缺少一些代码?)还是一个错误? 您可以试试我的查询,看看执行时间是否有任何改进? 【参考方案1】:您是否考虑过使用 ROW_NUMBER 而不是两次加入您的表?请试试这个:
;WITH FactPaymentTrans_Last
AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY TransactionID ORDER BY TransactionStepID DESC) AS RN
FROM WarehouseMgmt.FactPaymentTrans
)
SELECT DTST.[Id]
, FPT.[StartTime]
, FPT.[PaymentMethodId]
, FPT.[3DSecureId]
, FPT.[ProductId]
, DPT.[Id]
, FPT.[TransactionStatusId]
, FPT.[Amount]
, FPT.CurrencyId
, FPT.[PlayerId]
, DPL.[SourceOrigId]
, DPL.[Username]
, DPL.[FirstName]
, DPL.[LastName]
, DPL.[BrandId]
, DPL.[VIPLevelId]
, DPL.[MarketingChannelId]
, DPL.[MarketingSourceId]
, FPT.[PaymentReasonTextId]
, FPT_Ref.[PaymentReasonTextId]
, FPT.CreatedByAdminId
, FPT.[OriginalTransactionId]
, FPT.[TransactionId]
, FPT_Ref.[OriginalTransactionId]
, FPT.[ProviderTransactionOrigId]
FROM FactPaymentTrans_Last AS FPT
INNER JOIN WarehouseMgmt.DimTransactionStepType AS DTST
ON FPT.[TransactionStepTypeId] = DTST.[Id]
INNER JOIN WarehouseMgmt.DimPlayer AS DPL
ON FPT.PlayerId = DPL.Id
INNER JOIN WarehouseMgmt.DimProduct AS DP
ON DP.Id = FPT.ProductId
WHERE FPT.RN = 1;
这只是一个 sn-p,让您了解如何根据其 TransactionStepId
使用它来获取最新的 TransactionIds
。
如果还不够 - 请发布这些:
-
您的表结构
它们的索引
您的执行计划
这将有助于给你建议。
【讨论】:
我在我的问题中添加了执行计划【参考方案2】:有多种因素可以提高查询性能,其中一个可以做到,而不必知道有关索引、数据库架构、数据分布等的详细信息。JOIN
s 在查询中的顺序。
我已经重构了您的查询,我认为您应该得到与以前相同的结果,但执行时间有所改进:
SELECT DTST.[Id]
,FPT.[StartTime]
,FPT.[PaymentMethodId]
,FPT.[3DSecureId]
,FPT.[ProductId]
,DPT.[Id]
,FPT.[TransactionStatusId]
,FPT.[Amount]
,FPT.CurrencyId
,FPT.[PlayerId]
,DPL.[SourceOrigId]
,DPL.[Username]
,DPL.[FirstName]
,DPL.[LastName]
,DPL.[BrandId]
,DPL.[VIPLevelId]
,DPL.[MarketingChannelId]
,DPL.[MarketingSourceId]
,FPT.[PaymentReasonTextId]
,FPT_Ref.[PaymentReasonTextId]
,FPT.CreatedByAdminId
,FPT.[OriginalTransactionId]
,FPT.[TransactionId]
,FPT_Ref.[OriginalTransactionId]
,FPT.[ProviderTransactionOrigId]
FROM WarehouseMgmt.FactPaymentTrans AS FPT
INNER JOIN WarehouseMgmt.DimPlayer AS DPL
ON FPT.PlayerId = DPL.Id
INNER JOIN WarehouseMgmt.DimProduct AS DP
ON DP.Id = FPT.ProductId
INNER JOIN WarehouseMgmt.DimProductType AS DPT
ON DPT.Id = DP.ProductTypeId
INNER JOIN WarehouseMgmt.DimTransactionStepType AS DTST
ON FPT.[TransactionStepTypeId] = DTST.[Id]
WHERE (FPT.FactType = '' SOURCE '')
AND EXISTS (SELECT 1
FROM [WarehouseMgmt].[FactPaymentTrans]
WHERE FactType = '' SOURCE ''
AND FPT.TransactionId = TransactionId
AND FPT.TransactionStepId = TransactionStepId)
AND EXISTS (SELECT 1
FROM [WarehouseMgmt].[DimLoyaltyProgramLevel] DLPL
WHERE DLPL.[Id] = DPL.VipLevelId)
AND EXISTS (SELECT 1
FROM WarehouseMgmt.DimTimeZone DTZ
WHERE FPT.[TimeId] = DTZ.TimeUTCId
AND DTZ.TimeId BETWEEN @DimStartDate AND @DimEndDate)
【讨论】:
首先您没有 FPT_Ref 表,其次无法过滤时间然后对该表进行连接。它返回错误。请查看我的代码并进行更改以保持相同 @user2171512 这个想法是它不应该是相同的(一些查询是多余的)。我已对查询进行了更正,以便过滤器与“时间”一起使用。请尝试新的查询。 我仍然有 FPT_Ref.[PaymentReasonTextId] 和 FPT_Ref.[OriginalTransactionId] 错误。那是我的参考表(连接表)。我怎样才能把它修复成和以前一样? @user2171512 好的,我现在明白我错过了什么。 您有更新的优化解决方案吗?以上是关于优化 SQL Server 查询以提高速度的主要内容,如果未能解决你的问题,请参考以下文章