2015-02-13 3 views
0

Я ищу способ оптимизации запроса SELECT с левым соединением между таблицей измерения даты и таблицей фактов, которая должна отображать сумму меры за 2014 год.Медленный запрос в SQL Server с левым соединением

Вот запрос:

select SUM(coalesce(f.NBSCANS,0)) as somme 
from DIM_DATE as d 
left join FCT_SCAN as f 
on d.DATE = CAST(f.DATE_HEURE as DATE) 
and CAST(d.HEURE as varchar(4)) = CAST(CAST(f.DATE_HEURE as time) as varchar(4)) 
where d.ANNEE = 2014 

Этот запрос слишком медленно, потому что я никогда не видел результатов. Если я добавлю предложение WHERE в месяц (например: d.MOIS = 11), требуется 1 минута (так немного).

Но если добавить ИНЕКЕ в день тоже, как это результаты отображаются в 4 секунды:

select SUM(coalesce(f.NBSCANS,0)) as somme 
from DIM_DATE as d 
left join FCT_SCAN as f 
on d.DATE = CAST(f.DATE_HEURE as DATE) 
and CAST(d.HEURE as varchar(4)) = CAST(CAST(f.DATE_HEURE as time) as varchar(4)) 
where d.ANNEE = 2014 
and d.MOIS = 11 
and d.JOUR = 5 

Для информации, здесь являются CREATE TABLE Сценарий DIM_DATE:

CREATE TABLE [dbo].[DIM_DATE](
    [DATE_HEURE] [datetime] NOT NULL, 
    [ANNEE] [int] NULL, 
    [MOIS] [int] NULL, 
    [JOUR] [int] NULL, 
    [DATE] [date] NULL, 
    [JOUR_SEM_DATE] [varchar](10) NULL, 
    [NUM_JOUR_SEM_DATE] [int] NULL, 
    [HEURE] [time](0) NULL, 
    [TRANCHE_1H] [time](0) NULL, 
    [TRANCHE_DEMIH] [time](0) NULL, 
    [TRANCHE_QUARTH] [time](0) NULL, 
    [TRANCHE_10M] [time](0) NULL, 
CONSTRAINT [PK_DIM_DATE] PRIMARY KEY NONCLUSTERED 
(
    [DATE_HEURE] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

Поле DATE_HEURE в FCT_SCAN такое же, что и в DIM_DATE.

В DIM_DATE есть запись через каждые 10 минут:

DATE_HEURE 
2015-06-17 12:00:00.000 
2015-06-17 12:10:00.000 
2015-06-17 12:20:00.000 
2015-06-17 12:30:00.000 
2015-06-17 12:40:00.000 
2015-06-17 12:50:00.000 
2015-06-17 13:00:00.000 
2015-06-17 13:10:00.000 
2015-06-17 13:20:00.000 
2015-06-17 13:30:00.000 

Так что мой вопрос заключается в следующем: как оптимизировать этот запрос, зная, что я должен держать LEFT JOIN? (для пакета Cognos)

Редактировать: Вот план выполнения.

|--Compute Scalar(DEFINE:([Expr1006]=CASE WHEN [globalagg1013]=(0) THEN NULL ELSE [globalagg1015] END)) 
    |--Stream Aggregate(DEFINE:([globalagg1013]=SUM([partialagg1012]), [globalagg1015]=SUM([partialagg1014]))) 
     |--Parallelism(Gather Streams) 
      |--Stream Aggregate(DEFINE:([partialagg1012]=COUNT_BIG([Expr1007]), [partialagg1014]=SUM([Expr1007]))) 
        |--Compute Scalar(DEFINE:([Expr1007]=CASE WHEN [DECIS_DM_PARCOURS_PAX].[dbo].[FCT_SCAN].[NBSCANS] as [f].[NBSCANS] IS NOT NULL THEN CONVERT_IMPLICIT(int,[DECIS_DM_PARCOURS_PAX].[dbo].[FCT_SCAN].[NBSCANS] as [f].[NBSCANS],0) ELSE (0) END)) 
         |--Nested Loops(Left Outer Join, OUTER REFERENCES:([d].[DATE], [Expr1009])) 
          |--Compute Scalar(DEFINE:([Expr1009]=CONVERT(varchar(4),[DECIS_DM_PARCOURS_PAX].[dbo].[DIM_DATE].[HEURE] as [d].[HEURE],121))) 
          | |--Table Scan(OBJECT:([DECIS_DM_PARCOURS_PAX].[dbo].[DIM_DATE] AS [d]), WHERE:([DECIS_DM_PARCOURS_PAX].[dbo].[DIM_DATE].[ANNEE] as [d].[ANNEE]=(2014))) 
          |--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1003]) OPTIMIZED) 
           |--Compute Scalar(DEFINE:([Expr1021]=BmkToPage([Bmk1003]))) 
           | |--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1019], [Expr1020], [Expr1018])) 
           |   |--Compute Scalar(DEFINE:(([Expr1019],[Expr1020],[Expr1018])=GetRangeThroughConvert([DECIS_DM_PARCOURS_PAX].[dbo].[DIM_DATE].[DATE] as [d].[DATE],[DECIS_DM_PARCOURS_PAX].[dbo].[DIM_DATE].[DATE] as [d].[DATE],(62)))) 
           |   | |--Constant Scan 
           |   |--Index Seek(OBJECT:([DECIS_DM_PARCOURS_PAX].[dbo].[FCT_SCAN].[IDX_DATE_HEURE] AS [f]), SEEK:([f].[DATE_HEURE] > [Expr1019] AND [f].[DATE_HEURE] < [Expr1020]), WHERE:([DECIS_DM_PARCOURS_PAX].[dbo].[DIM_DATE].[DATE] as [d].[DATE]=CONVERT(date,[DECIS_DM_PARCOURS_PAX].[dbo].[FCT_SCAN].[DATE_HEURE] as [f].[DATE_HEURE],0) AND [Expr1009]=CONVERT(varchar(4),CONVERT(time(7),[DECIS_DM_PARCOURS_PAX].[dbo].[FCT_SCAN].[DATE_HEURE] as [f].[DATE_HEURE],0),121)) ORDERED FORWARD) 
           |--RID Lookup(OBJECT:([DECIS_DM_PARCOURS_PAX].[dbo].[FCT_SCAN] AS [f]), SEEK:([Bmk1003]=[Bmk1003]) LOOKUP ORDERED FORWARD) 
+0

Я подозреваю, что здесь есть петля. У меня была такая же проблема. Можете ли вы опубликовать план выполнения? Если он скажет, что соединение цикла, попытаетесь ли вы изменить «левое соединение» в «левом хеш-соединении»? –

ответ

1

Попробуйте это вместо этого. Это должно улучшить производительность. Вы можете улучшить его еще больше, создав вычисленный столбец PERSISTED в таблице FCT_SCAN. Это позволило бы использовать индекс.

SELECT 
    coalesce(SUM(f.NBSCANS),0) as somme 
FROM 
    DIM_DATE as d 
LEFT JOIN 
    FCT_SCAN as f 
on 
    f.DATE_HEURE>= d.DATE_HEURE 
    and f.DATE_HEURE < dateadd(minute, 10, d.DATE_HEURE) 
WHERE 
    d.ANNEE = 2014 
    and d.MOIS = 11 
    and d.JOUR = 5 
+0

Msg 402, уровень 16, состояние 1, строка 8 Типы данных datetime и time несовместимы с оператором, большим или равным. –

+0

попробуйте сейчас, у меня была опечатка HEURE вместо DATE_HEURE –

+0

Я нашел решение, и я написал его в ответ. –

1

Благодаря плану выполнения, я нашел решение. Это был индекс для поля DATE_HEURE в FCT_SCAN, который много стоил в запросе, поэтому я удалил его. Теперь время выполнения составляет несколько секунд.

Спасибо всем за ваши предложения!

+0

, пожалуйста, попробуйте опубликованные ответы. Я уверен, что некоторые из них быстрее и читаемы, чем ваши. –

+0

Хорошо, я попробую эти запросы, спасибо! –

0

Необоснованные соединения всегда плохие.

Вы должны изменить логику: Truncate f.DATE_HEURE до 0/10/20/30/40/50 минут, а затем присоединиться.

select SUM(coalesce(f.NBSCANS,0)) as somme 
from DIM_DATE as d 
left join 
    (select 
     DATEADD(minute, DATEDIFF(minute, 0, DATE_HEURE)/10 * 10, 0) as x 
     , ... 
    from FCT_SCAN 
) as f 
on d.DATE = f.x 
where d.ANNEE = 2014 

Добавление аналогичное условие на FCT_SCAN.DATE_HEURE ограничить в тот же период (например, 2014 год) также может помочь.

+0

Хорошо, я попробую это, спасибо! –

Смежные вопросы