簡體   English   中英

SQL Server:奇怪的執行計划

[英]SQL Server: Strange execution plan

我在SQL Server 2008 Standard上運行了一些ETL代碼。 處理相對較少的行(〜50,000)並將其加載到臨時表中。 然后,我執行插入查詢以復制更大的表(〜1,000,000 +行)中不存在的行。 臨時表包含與目標表相同的主鍵和聚集索引。

create table #NewClaims(ExtractDate datetime, SiteName nvarchar(50), SiteCd nvarchar(50), ContractTypeCd nvarchar(50), 
ClaimRateType nvarchar(50), ClaimRateTypeCd nvarchar(50), ClaimStatus nvarchar(50), ClaimStatusCd nvarchar(50), 
CreationDt datetime, StatusDt datetime, ClaimID nvarchar(50), SeqNum int, CreationUserID nvarchar(50), 
SpecialClaimInd nvarchar(50), JobSeekerID nvarchar(50), InvoiceNum nvarchar(50), JobID nvarchar(50), JobRefId int,
RecoveryReason nvarchar(50), ClaimAmount money, GSTAmount money, ApprovedAmount money, ClaimCurrencyInd nvarchar(50), 
EmployerID nvarchar(50), BaseRateType nvarchar(50), BaseRateTypeCd nvarchar(50)
constraint PK_NewClaims primary key clustered(ClaimID, ClaimStatusCD));

這是將臨時表記錄加載到目標中的SQL

insert into dbo.Claim(
ExtractDate, SiteName, SiteCd, ContractTypeCd, ClaimRateType, ClaimRateTypeCd, ClaimStatus, ClaimStatusCd, CreationDt, 
StatusDt, ClaimID, SeqNum, CreationUserID, SpecialClaimInd, JobSeekerID, InvoiceNum, JobID, JobSeqNum, RecoveryReason, 
ClaimAmount, GSTAmount, ApprovedAmount, ClaimCurrencyInd, EmployerID, BaseRateType, BaseRateTypeCd
)
select 
n.ExtractDate,  n.SiteName, n.SiteCd, n.ContractTypeCd, n.ClaimRateType, n.ClaimRateTypeCd, n.ClaimStatus, n.ClaimStatusCd, 
n.CreationDt, n.StatusDt, n.ClaimID, n.SeqNum, n.CreationUserID, n.SpecialClaimInd, n.JobSeekerID, n.InvoiceNum, n.JobID, 
n.JobRefId, n.RecoveryReason, n.ClaimAmount, n.GSTAmount, n.ApprovedAmount, n.ClaimCurrencyInd, n.EmployerID, n.BaseRateType, 
n.BaseRateTypeCd
from #NewClaims as n
left join dbo.Claim as c on n.ClaimID = c.ClaimID and n.ClaimStatusCd = c.ClaimStatusCd
where c.ClaimID is null

當我運行此程序時,執行計划會執行一些異常操作。 它拒絕使用dest表上的PK聚集索引,而是嘗試使用任何其他可用索引。 奇怪的是,它使用此索引檢索ClaimID和StatusCd。 如果我逐個禁用dest表上的索引,則執行計划將繼續嘗試使用其他索引,直到我禁用了所有索引(除集群索引外)為止,這時它終於讓出並使用了它,但會產生一堆位圖操作。 發生這種情況時查詢運行得更快。

我還嘗試添加索引提示:(index(1))。 此提示使它按預期工作,使用索引,並且比非提示版本運行得快得多。 強制索引查找在執行計划中顯示標量運算符-這是否表明存在問題?

Seek Keys[1]: Prefix: [ESD4].[dbo].[Claim].ClaimID, [ESD4].[dbo].[Claim].ClaimStatusCd = Scalar Operator([tempdb].[dbo].[#NewClaims].[ClaimID] as [n].[ClaimID]), Scalar Operator([tempdb].[dbo].[#NewClaims].[ClaimStatusCd] as [n].[ClaimStatusCd])

有什么我想念的嗎? 我不想強迫SQL使用特定的執行計划,因為索引提示經常會適得其反。

更新

  • 重新計算表統計信息無濟於事
  • 從左聯接更改為“不存在的地方”不會影響所用索引的選擇,但確實會稍微改變計划。 代替哈希匹配(左聯接),它現在正在執行哈希匹配(左反半聯接),這可能更快。

沒有更多信息很難說,但是您可以測試一下。 有時,獲取要插入到表變量中的PK ID(@PKID)的輸出可能更快,然后在update語句中,使用“ select ... from #newClaims inner join @PKIDs”。 沒有計划和擁有數據集很難說,但是也許在您的情況下它會有所幫助。 如果您是內部聯接,則可以為PK使用索引提示。 #NewClaims表也可能只需要在ClaimID和ClaimStatusCd上使用PK,從而減少了構建#NewClaims的時間。

declare @PKIDs table (ClaimID INT PRIMARY KEY)

insert into @PKIDs (ClaimID)
select distinct n.ClaimID
from #NewClaims as n
where not exists (select 1 from dbo.Claim as c where c.ClaimID = n.ClaimID and n.ClaimStatusCd = c.ClaimStatusCd)

insert into dbo.Claim(
ExtractDate, SiteName, SiteCd, ContractTypeCd, ClaimRateType, ClaimRateTypeCd, ClaimStatus, ClaimStatusCd, CreationDt, 
StatusDt, ClaimID, SeqNum, CreationUserID, SpecialClaimInd, JobSeekerID, InvoiceNum, JobID, JobSeqNum, RecoveryReason, 
ClaimAmount, GSTAmount, ApprovedAmount, ClaimCurrencyInd, EmployerID, BaseRateType, BaseRateTypeCd
)
select 
n.ExtractDate,  n.SiteName, n.SiteCd, n.ContractTypeCd, n.ClaimRateType, n.ClaimRateTypeCd, n.ClaimStatus, n.ClaimStatusCd, 
n.CreationDt, n.StatusDt, n.ClaimID, n.SeqNum, n.CreationUserID, n.SpecialClaimInd, n.JobSeekerID, n.InvoiceNum, n.JobID, 
n.JobRefId, n.RecoveryReason, n.ClaimAmount, n.GSTAmount, n.ApprovedAmount, n.ClaimCurrencyInd, n.EmployerID, n.BaseRateType, 
n.BaseRateTypeCd
from #NewClaims as n
join @PKIDs as pkids on pkids.ClaimID = n.ClaimID

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM