Эффективный запрос SQL для поиска первой (по дате) связанной записи в отношении 1-N - PullRequest
3 голосов
/ 10 июня 2009

Вот сценарий: есть таблица программного обеспечения (PK = SoftwareID) и связанная таблица выпуска (PK = [SoftwareID, версия]).

Релиз может быть основным или второстепенным, тип релиза определяется с помощью Release.ReleaseType ('MAJ', 'MIN').

Релиз также характеризуется датой: Release.ReleaseDate.

Программное обеспечение разделено на категории, идентифицируемые по Software.CategoryID.

Проблема: нужен эффективный T-SQL-запрос для получения списка всех программных компонентов определенной категории с первой датой выпуска, попадающей в заданный интервал, ограниченный @DateFrom, @DateTo. Единственные столбцы, необходимые в окончательном наборе результатов, - это SoftwareID и ReleaseDate.

Это не реальный сценарий, но я сформулировал его таким образом, чтобы его было легче понять. В реальном случае таблица Release будет содержать около 10 миллионов записей, а таблица Software - около 1 миллиона. Я уже нашел решение, но оно довольно медленное, и я чувствую, что эксперты здесь могут найти что-то лучшее.

Вот мое медленное решение:

select  s.SoftwareID, min(r.ReleaseDate)
from
    Software s inner join Release r on (s.SoftwareID = r.SoftwareID)
where s.CategoryID = @Category
      and r.ReleaseType = 'MAJ'
group by
    s.SoftwareID
having
    min(r.ReleaseDate) >= @DateFrom
    and min(r.ReleaseDate) < @DateTo

Спасибо.

Ответы [ 4 ]

2 голосов
/ 10 июня 2009

Ваш запрос хорош.

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

  • в «MSSQL Management Studio»: «Запрос» -> «Анализ запроса в помощнике по настройке ядра СУБД», затем следуйте «белому кролику» (предпочтительно)
  • в «MSSQL Management Studio»: «Запрос» -> «Включить фактический план выполнения». Затем запустите запрос и посмотрите, предлагает ли план выполнения новые индексы.
1 голос
/ 10 июня 2009

Спасибо всем за ваши предложения. Кажется, что проблема почти решена, и я думаю, что дальше ничего не поделаешь.

Консультант по запросам предложил 2 полезных индекса, один из которых выглядит примерно так:

CREATE NONCLUSTERED INDEX [IX_Release_1234] ON [dbo].[Release] 
(
    [ReleaseType] ASC,
    [SoftwareID] ASC
)
INCLUDE ( [ReleaseDate]) WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]

Настройка индекса сокращает время выполнения до менее 50%. Тем не менее, еще одно небольшое улучшение (25-30% от ранее сокращенного времени) состояло в том, чтобы реорганизовать запрос, сначала получая даты выпуска исключительно из таблицы выпуска, а затем объединяя этот подзапрос с программным обеспечением:

select s.SoftwareID, r.ReleaseDate
from Software s inner join (
    select   SoftwareID, min(ReleaseDate) as ReleaseDate
    from     Release
    where    ReleaseType = 'MAJ'
    group by SoftwareID
    having
        min(ReleaseDate) >= @DateFrom
        and min(ReleaseDate) < @DateTo
) r on (
    s.SoftwareID = r.SoftwareID
)
where
    s.CategoryID = @Category

Теперь я думаю, что индексная настройка должна быть переделана:) ...

Итог, по возможности используйте советника по настройке двигателя и еще раз всем спасибо.

1 голос
/ 10 июня 2009

Попробуйте что-нибудь вроде:

select  
  s.SoftwareID, 
  min(r.ReleaseDate)
from
  Software s 
  inner join Release r on s.SoftwareID = r.SoftwareID
where 
  s.CategoryID = @Category
  and r.ReleaseType = 'MAJ'
  and s.ReleaseDate >= @DateFrom
  and s.ReleaseDate < @DateTo
group by
  s.SoftwareID

Основная идея такова: почему вы фильтруете дату после группировки, когда вы можете предотвратить нежелательные записи, вводящие результат до группировки.

Вы группируете по s.SoftwareID. Мне кажется, что HAVING MIN(s.ReleaseDate) >= ... не повлияет на записи, отличные от WHERE s.ReleaseDate >= ....

1 голос
/ 10 июня 2009

У вас может быть проблема с индексом. Вы пытались создать индекс для столбца ReleaseDate или создать кластеризованный индекс для таблицы, содержащей ReleaseDate (отсортировано по ReleaseDate)?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...