2017-02-13 5 views
1

У меня есть запрос, который выполняется быстро, когда предложение даты "и датированный (день, con2.DT_DateIncluded), '2017-01-01') < = 0" в коде ниже isn 't используется в запросе, но работает медленно, когда он включен. Хотя он работает быстро, когда я запускаю только часть «select top 2 ID_Contact ...», даже включая предложение даты. У меня есть этот запрос в классическом приложении ASP, и он не может быть преобразован в хранимую процедуру (причины проекта). Можете ли вы помочь мне найти способ улучшить производительность полного запроса, просто изменив код запроса?Slow T-SQL-запрос с датированной функцией

select distinct top 10 
    ID_Contact, NO_CodCompany 
from 
    tblContacts con1 
where 
    ID_Contact in (select top 2 ID_Contact 
        from tblContacts con2 
        inner join tblCompanies cp on con2.NO_CodCompany = cp.ID_Company 
        where con2.NO_CodCompany = con1.NO_CodCompany 
        and datediff(day, con2.DT_DateIncluded), '2017-01-01') <= 0) 

ответ

1

Это, по существу, ваш запрос: Это ваш запрос:

select distinct top 10 ID_Contact, NO_CodCompany 
from tblContacts con1 
where ID_Contact in (select top 2 ID_Contact 
        from tblContacts con2 inner join 
          tblCompanies cp 
          on con2.NO_CodCompany = cp.ID_Company 
        where con2.NO_CodCompany = con1.NO_CodCompany and 
          datediff(day, con2.DT_DateIncluded), '2017-01-01') <= 0 
        ); 

Мое первое предложение изменить datediff() к простому сравнению дата:

select distinct top 10 ID_Contact, NO_CodCompany 
from tblContacts con1 
where ID_Contact in (select top 2 ID_Contact 
        from tblContacts con2 inner join 
          tblCompanies cp 
          on con2.NO_CodCompany = cp.ID_Company 
        where con2.NO_CodCompany = con1.NO_CodCompany and 
          con2.DT_DateIncluded < '2017-01-02' 
        ); 

Затем я удалит JOIN в подзапросе. Я не 100% уверен, что это точно эквивалентно, потому что это может зависеть от нюансов в данных:

select distinct top 10 ID_Contact, NO_CodCompany 
from tblContacts con1 
where con1.ID_Contact in (select top 2 con2.ID_Contact 
          from tblCompanies cp 
          where con1.NO_CodCompany = cp.ID_Company and 
           con1.DT_DateIncluded < '2017-01-02' 
         ); 

Затем, если вы можете удалить select distinct во внешнем запросе, вы должны сделать это.

+0

Привет, Гордон Линофф, и спасибо за ваш быстрый ответ SUPER. Хотя я должен сказать, что он продолжает работать медленно после того, как эти изменения будут предложены, я сохраню их в коде, так как они могут добавить какую-то производительность в любом случае ... ура! –

+0

'DATEDIFF ('2017-01-01 11:59:50', '2017-01-01')' все еще имеет значение '0'. Эквивалентным кодом будет 'DT_DateIncluded <'20170102'' вместо' DT_DateIncluded <' 20170101'' –

+0

@JoelCoehoorn. , , Непонятно, что поле «DateIncluded» будет иметь компонент времени, хотя это вполне разумно, если префикс «dt» подразумевает «datetime». Я обновил ответ. –

1

Попробуйте вместо этого:

con2.DT_DateIncluded < '20170102' 

Это лучше, потому что она по-прежнему позволяет серверу использовать любые индексы на DT_DateIncluded колонке. В настоящее время это невозможно. Хуже того, возможно, что запрос должен запускать эту функцию DATEDIFF() для каждой записи в таблице.

Обратите внимание, что это равно, что эквивалентно тому, что вы отправили, даже если оно может не соответствовать тому, что вы намеревались. Я подозреваю, что con2.DT_DateIncluded < '20170101' ближе к тому, что вы на самом деле имели в виду.

Я также подозреваю, что вы можете сделать это либо без второго экземпляра tblContacts, либо с помощью функции окон, чтобы получить гораздо лучшие результаты или, по крайней мере, с помощью JOIN вместо IN, чтобы отфильтровать результаты.

Наконец, по историческим причинам, при вводе даты только значения, вы должны использовать несортированный формат даты , как описано здесь:

The ultimate guide to the datetime datatypes

Для значений даты/времени, вы все равно можете использовать выделенный yyyy-mm-dd hh:mm:ss, к которому вы привыкли, но если у вас есть только дата, то yyyymmdd лучше.


Основываясь на этот комментарий:

Моя цель с этим запросом, чтобы получить контакты из компаний, но ограничивается «русских» контактов на компанию

Вы должны смотреть в APPLY оператор.К сожалению, до сих пор мне не ясно, как все совмещается, но я хотя бы обеспечить демонстрацию с помощью оператора APPLY, чтобы показать два контактов в компании, которую вы можете использовать в качестве отправной точки:

SELECT TOP 10 ct.ID_Contact, ct.NO_CodCompany 
FROM tblCompanies cp 
CROSS APPLY (
    SELECT TOP 2 ID_Contact, NO_CodCompany 
    FROM tblContacs 
    WHERE NO_CodCompany = cp.ID_Company 
     AND DT_DateIncluded < '20170102' 
    ORDER BY DT_DateIncluded DESC 
) ct 

APPLY работает вид как JOIN на вложенный запрос SELECT, где нет ON; условие соединения вместо этого включено как часть предложения WHERE в вложенный оператор SELECT.

Обратите внимание на использование CROSS. Это исключает компании, у которых вообще нет контактов. Если вы хотите включить эти компании, измените его на OUTER.

Вы также должны посмотреть, какие индексы вы определили. Единственный индекс в таблице tblContacts, который выглядит на NO_CodCompany и DT_DateIncluded (в таком порядке!), Может творить чудеса для этого запроса, особенно если он также имеет ID_Contact в предложении INCLUDES. Затем вы можете заполнить часть запроса tblContacts целиком из индекса.

+0

Привет всем, кто разместил комментарий. После добавления предложенных изменений до сих пор нет радости ... Моя цель с этим запросом - получить контакты от компаний, но ограничена «n» контактами для каждой компании (по запросу, который я использовал в качестве примера, n = 2). Запрос, который я опубликовал в качестве примера, отлично выполняет эту работу, но он становится «невероятно медленным», когда я добавляю в него предложение date. Это поле даты уже проиндексировано, и я уже изменил датированное выражение на простой DT_DateIncluded> = '20170101'. Но до сих пор нет радости ... Я был бы доволен другим запросом, который обычно работает с предложением даты или без него. –

+0

@ Claudio.hz см. Мой обновленный ответ. И если это поможет, я буду рад услышать до и после. –

1

Вместо `DATEDIFF() < 0' можно использовать:

and con2.DT_DateIncluded <= '2017-01-01' 

Кроме того, убедитесь, что существует индекс на` DT_DateIncluded»столбца.

Причина, по которой работает DATEDIFF(), заключается в том, что для ее выполнения требуется немного времени, оптимизатор запросов (вероятно) заканчивается запуском его для всей таблицы, и есть (возможно) нет индекса, чтобы помочь ему выберите нужные строки.

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