SQL Server 2008 Оптимизация FULL JOIN с помощью операторов ISNULL - PullRequest
2 голосов
/ 28 сентября 2010

HI All

Я надеялся, что кто-нибудь может помочь мне улучшить запрос, который я должен периодически запускать.На данный момент выполнение занимает более 40 минут.В это время он использует полностью выделенную память, но загрузка ЦП в основном колеблется от 2% до 5%, время от времени скачкообразно повышаясь до 40% в течение нескольких секунд.

У меня есть эта таблица (упрощенный пример):

    CREATE TABLE [dbo].[dataTable]
    (
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [dteEffectiveDate] [date] NULL,
    [dtePrevious] [date] NULL,
    [dteNext] [date] NULL,
    [Age] [int] NULL,
    [Count] [int] NULL
    ) ON [PRIMARY]

    GO

Вот некоторые входные значения:

INSERT INTO [YourDB].[dbo].[dataTable]
           ([dteEffectiveDate]
           ,[dtePrevious]
           ,[dteNext]
           ,[Age]
           ,[Count])
     VALUES
('2009-01-01',NULL,'2010-01-01',40,300),
('2010-01-01','2009-01-01', NULL,40,200),
('2009-01-01',NULL, '2010-01-01',20,100),
('2010-01-01','2009-01-01', NULL,20,50),
('2009-01-01',NULL,'2010-01-01',30,10)
GO

Каждая запись имеет поле dteEffectiveDate.Кроме того, у каждого есть dtePrevious и dteNext, которые отражают даты ближайшей предыдущей / следующей даты вступления в силу.Теперь мне нужен запрос, который вычислит среднее значение в полях Count между последовательными периодами в определенном возрасте.

Так, например, в данных выше, для 40 лет у нас есть 300 в 2009 году/ 01/01 и 200 в 2010/01/01, поэтому запрос должен дать 250.

Обратите внимание, что возраст 30 имеет только одну запись, 10. Это в 2009/01/01.На 2010/01/01 запись отсутствует, но мы знаем, что данные были собраны на этом этапе, поэтому тот факт, что ничего нет, означает, что 30 на 0 на эту дату.Следовательно, запрос должен выдать 5.

. Для этого я использую FULL JOIN таблицы на себя и использую ISNULL для выбора значений.Вот мой код:

SELECT

    ISNULL(T1.dteEffectiveDate,T2.dtePrevious) as [Start Date]
    ,ISNULL(T1.dteNext,T2.dteEffectiveDate)  as [End Date]
    ,ISNULL(T1.Age,T2.Age) as Age 
    ,ISNULL(T1.[Count],0) as [Count Start]
    ,ISNULL(T2.[Count],0)   as [Count End]
    ,(ISNULL(T1.[Count],0)+ISNULL(T2.[Count],0))/2 as [Mid Count]

    FROM
    [ExpDBClient].[dbo].[dataTable] as T1
    FULL JOIN [ExpDBClient].[dbo].[dataTable] as T2

    ON 
    T2.dteEffectiveDate = T1.dteNext
    AND T2.Age = T1.Age

    WHERE ISNULL(T1.dteEffectiveDate,T2.dtePrevious) is not null
    AND ISNULL(T1.dteNext,T2.dteEffectiveDate) is not null

GO

, который выводит:

Start Date  End Date    Age Count Start Count End   Mid Lives
2009-01-01  2010-01-01  40  300         200         250
2009-01-01  2010-01-01  20  100         50          75
2009-01-01  2010-01-01  30  10          0           5

Он работает отлично, но когда я запускаю это на реальных данных, которые составляют около 7 м записей, это мучительно долговыполнить.

У кого-нибудь есть предложения?

Спасибо
Карл

1 Ответ

2 голосов
/ 28 сентября 2010

Трудно дать много рекомендаций.

Одна вещь, которую я определенно рекомендовал бы, это индексы для тех столбцов, которые вы используете в качестве внешних ключей в своих условиях JOIN, например,

  • Age
  • dteEffectiveDate
  • dteNext

Создайте НЕКЛАСТЕРНЫЙ индекс для каждого из этих столбцов в отдельности и повторите измерение. С несколькими строками данных улучшение не поддается измерению, но с миллионами строк это может иметь значение.

...