2015-04-15 7 views
1

Этот запрос выполняется очень быстро (< 100 мс):Почему этот запрос работает так медленно?

SELECT TOP (10) 
    [Extent2].[CompanyId] AS [CompanyId] 
    ,[Extent1].[Id] AS [Id] 
    ,[Extent1].[Status] AS [Status] 
FROM [dbo].[SplittedSms] AS [Extent1] 
INNER JOIN [dbo].[Sms] AS [Extent2] 
    ON [Extent1].[SmsId] = [Extent2].[Id] 
WHERE [Extent2].[CompanyId] = 4563 
    AND ([Extent1].[NotifiedToClient] IS NULL) 

Если добавить только фильтр времени, он занимает слишком много времени (22 секунд!):

SELECT TOP (10) 
    [Extent2].[CompanyId] AS [CompanyId] 
    ,[Extent1].[Id] AS [Id] 
    ,[Extent1].[Status] AS [Status] 
FROM [dbo].[SplittedSms] AS [Extent1] 
INNER JOIN [dbo].[Sms] AS [Extent2] 
    ON [Extent1].[SmsId] = [Extent2].[Id] 
WHERE [Extent2].Time > '2015-04-10' 
    AND [Extent2].[CompanyId] = 4563 
    AND ([Extent1].[NotifiedToClient] IS NULL) 

Я попытался добавить индекс на столбце [Time] таблицы Sms, но оптимизатор, похоже, не использует индекс. Пробовал использовать With (index (Ix_Sms_Time)); но, к моему удивлению, требуется еще больше времени (29 секунд!).

Вот фактический план выполнения: enter image description here

План выполнения одинакова для обоих запросов. Таблицы, упомянутые здесь, имеют от 5М до 8М строк (индексы < 1% фрагментированы и статистика обновляется). Я использую MS SQL Server 2008R2 на 16-битной 32-Гбайт памяти Windows 2008 R2)

+0

Попробуйте добавить ORDER BY ASC или DESC TIME столбец и проверьте. Он должен работать быстрее. –

+3

Во-первых, без 'ORDER BY' строки, возвращаемые запросом' TOP', не являются детерминированными. Лучшей практикой является указание 'ORDER BY' с' TOP'. Чтобы повысить производительность второго запроса, попробуйте составной некластеризованный индекс для CompanyID и Time. Это позволит избежать касания строк <= '2015-04-10'. –

+0

Tried 'Order By [Time]'; хуже, 29 секунд! – mshsayem

ответ

0

я узнал, что не было никакого индекса на столбце внешнего ключа (SmsId) на SplittedSms таблицы. Я сделал один, и кажется, второй запрос почти так же быстро, как и первый сейчас

план выполнения Сейчас:.

enter image description here

Спасибо всем за усилия.

0

Помогает ли это, когда вы вынуждаете фильтр времени срабатывать только после запуска фильтра клиента?

FI как в этом примере:

;WITH ClientData AS ( 
    SELECT 
     [E2].[CompanyId] 
     ,[E2].[Time] 
     ,[E1].[Id] 
     ,[E1].[Status] 
    FROM [dbo].[SplittedSms] AS [E1] 
    INNER JOIN [dbo].[Sms] AS [E2] 
     ON [E1].[SmsId] = [E2].[Id] 
    WHERE [E2].[CompanyId] = 4563 
     AND ([E1].[NotifiedToClient] IS NULL) 
) 
SELECT TOP 10 
    [CompanyId]  
    ,[Id] 
    ,[Status] 
FROM ClientData 
WHERE [Time] > '2015-04-10' 
0

Создание индекса на Sms со следующим Index Key Columns (в указанном порядке):

  1. CompanyID
  2. Время

You может или не нужно добавлять Id в качестве Included Column.

0

Какой тип данных является вашим столбцом времени? Если это дата и время, попробуйте преобразовать «2015-04-10» в эквивалентный тип данных, чтобы он мог использовать индекс.

Declare @test datetime 
Set @test='2015-04-10' 

Затем измените условие:

[Extent2].Time > @test  

Сервер SQL неявно ставит в соответствии типа данных, если имеется несоответствие типов данных. И любая функция или операция литья предотвращают использование индексов.

+1

Изменение даты в переменной заставит оптимизатор оптимизировать предложение для неизвестного значения (если это не хранимая процедура), а в случае полей даты и времени, близких к текущему дню, это может ухудшить ситуацию. Наличие даты и времени в правильном формате, например. '20150410' должно быть в порядке. –

0

Я на той же трассе с @JonTirjan, индекс с просто времени приводит к много ключевых поисков, так что вы должны попытаться по крайней мере, следующее:

create index xxx on Sms (Time, CompanyId) include (Id) 

или

create index xxx on Sms (CompanyId, Time) include (Id) 

Если Id - ваш кластеризованный индекс, тогда он не нужен в предложении include. Если значительная часть ваших данных принадлежит CompanyID 4563, вполне возможно, что она будет также включать столбцы include.

Проценты, которые вы видите в фактическом плане, являются просто оценками, основанными на предположениях о подсчете строк, поэтому иногда это бывает совершенно неправильно. Глядя на фактическое количество строк/исполнений + статистика вывода IO должна дать вам представление о том, что происходит на самом деле.

0

Две вещи приходят на ум:

  1. Добавляя дополнительное ограничение будет «сложнее» для базы данных, чтобы найти первые 10 пунктов, которые соответствуют вашим ограничениям. Нахождение первых 10 строк, скажем, 10.000 предметов (из общего количества 1 миллион) легче найти первые 10 строк из, возможно, 100 предметов (из общего количества 1 миллион).
  2. Этот индекс не используется, вероятно, потому, что индекс создается в столбце datetime, что не очень эффективно, если вы также сохраняете в них время. Возможно, вы захотите создать кластерный индекс в столбце [время] (но тогда вам придется удалить кластерный индекс, который теперь находится в столбце [CompanyId], или вы можете создать вычисленный столбец, в котором хранится дата-часть [ время] колонок, создать индекс по этому вычисляемому столбцу и фильтру на этой колонке.
Смежные вопросы