У меня есть код ETL, работающий на SQL Server 2008 Standard. Относительно небольшое количество строк (~ 50 000) обрабатывается и загружается в временную таблицу. Затем я выполняю запрос на вставку для копирования по строкам, которых нет в гораздо более крупной таблице (~ 1,000,000 + rows). Таблица temp содержит тот же первичный ключ и кластеризованный индекс, что и таблица назначения.SQL Server: Странный план выполнения
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
Когда я запускаю этот план исполнения делает что-то необычное. Он отказывается использовать кластерный индекс PK в таблице dest и пытается использовать любой другой индекс, доступный вместо этого. Любопытно, что он использует этот индекс для восстановления идентификаторов ClaimID и StatusCd. Если я отключу индексы в таблице dest, один за другим, план выполнения будет продолжать пытаться использовать другие индексы, пока я не отключил их всех, кроме кластеризованных, и в этот момент он, наконец, дает и использует его, но создает пучок растровых операций. Запрос выполняется быстрее, когда это происходит.
Я также экспериментировал с добавлением указательного указателя: с (индекс (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 использовать конкретный план выполнения, поскольку подсказки индексов часто могут иметь неприятные последствия.
Update
- Повторное вычисление статистики таблицы не помогло
- Изменение слева присоединитесь к «где не существует» не влияет на выбор индекса используется, но он изменить план немного. Вместо хеш-матча (Left Join), теперь он выполняет Hash Match (Left Anti Semi Join), который, предположительно, быстрее.
Ваша статистика обновлена в вашей целевой таблице? – Aushin
Не уверен. Как я могу проверить или обновить их? – Trent
Вы можете обновить их, запустив это в своей таблице. Http://msdn.microsoft.com/en-us/library/ms187348.aspx – Aushin