Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL Server:奇怪的执行计划_Sql_Sql Server_Sql Server 2008 - Fatal编程技术网

SQL Server:奇怪的执行计划

SQL Server:奇怪的执行计划,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我有一些在SQLServer2008标准上运行的ETL代码。相对较少的行(约50000行)被处理并加载到临时表中。然后,我执行一个insert查询,对大得多的表~1000000+行中不存在的行进行复制。临时表包含与目标表相同的主键和聚集索引 create table #NewClaims(ExtractDate datetime, SiteName nvarchar(50), SiteCd nvarchar(50), ContractTypeCd nvarchar(50), ClaimRate

我有一些在SQLServer2008标准上运行的ETL代码。相对较少的行(约50000行)被处理并加载到临时表中。然后,我执行一个insert查询,对大得多的表~1000000+行中不存在的行进行复制。临时表包含与目标表相同的主键和聚集索引

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表上的索引,执行计划将继续尝试使用其他索引,直到我禁用了除集群之外的所有索引,此时它最终放弃并使用它,但会生成一系列位图操作。发生这种情况时,查询运行得更快

我还尝试添加索引提示:使用index1。这个提示使它能够像我预期的那样工作,使用索引并运行得比非提示版本快得多。强制索引查找在执行计划中显示标量运算符-这是否表明存在问题

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使用特定的执行计划,因为索引提示常常会适得其反

更新

重新计算表统计数据没有帮助 从left join更改为where not exists不会影响所用索引的选择,但它确实稍微改变了计划。它不再使用散列匹配左连接,而是使用散列匹配左反半连接,这可能会更快。
没有更多的信息很难说,但你可以测试一下。有时,获取要插入到表变量@PKIDs中的PK ID的输出可能会更快,然后在update语句中,使用“select…”。。。从newClaims内部连接@PKIDs'。没有计划和数据集很难说,但在你的情况下,这可能会有所帮助。如果使用内部连接,则可以对PK使用索引提示。NewClaims表也可能只需要ClaimID和ClaimStatusCd上的PK,从而缩短构建新Claims的时间

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

您的目的地表上的统计数据是最新的吗?不确定。如何检查或刷新它们?您可以通过在表上运行此命令来更新它们。当然,它使用任何其他索引,因为其他索引占用的磁盘空间更少=IO更少,而且它们都包含PK/聚集索引数据。并不是说这永远是最优的,而是优化器重视IO保存。你能复制实际的执行计划吗,有索引提示和没有索引提示?如果索赔表的创建表和索引与新索赔表不同,也可以创建索赔表和索引