Запрос выполняется очень медленно, есть ли способ улучшить его?


9

У меня следующий запрос, и из-за большого количества SUMвызовов функций мой запрос выполняется слишком медленно. У меня есть много записей в моей базе данных, и я хотел бы получить отчет за текущий и прошлый год (последние 30 дней, последние 90 дней и последние 365 дней) для каждой из них:

SELECT 
    b.id as [ID]
    ,d.[Title] as [Title]
    ,e.Class as [Class]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 30 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 30 Days Col2]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 90 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 90 Days Col2]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 365 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 365 Days Col2]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 30 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 30 Days Col2]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 90 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 90 Days Col2]

    ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 365 Days Col1]
    ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 365 Days Col2]


    FROM 
    tb1 a
INNER JOIN 
    tb2 b on a.id=b.fid and a.col3 = b.col4
INNER JOIN 
    tb3 c on b.fid = c.col5
INNER JOIN       
    tb4 d on c.id = d.col6
INNER JOIN 
    tb5 e on c.col7 = e.id
GROUP BY
    b.id, d.Title, e.Class

У кого-нибудь есть идеи, как я могу улучшить свой запрос, чтобы он работал быстрее?

РЕДАКТИРОВАТЬ: мне было рекомендовано переместить DATEADDвызов функции в whereоператор и сначала загрузить два года, а затем отфильтровать их в столбцах, но я не уверен, что предложенный ответ выполнен и работает, его можно найти здесь: https: // stackoverflow. ком / а / 59944426/12536284

Если вы согласны с вышеуказанным решением, пожалуйста, покажите мне, как я могу применить его в моем текущем запросе?

Просто к сведению, я использую этот SP в C #, Entity Framework (DB-First), что-то вроде этого:

var result = MyDBEntities.CalculatorSP();

4
Покажите нам свой план выполнения ...
Дейл К

1
На что угодно - это то, что может сделать запрос медленным
Фабио


2
Опять, пожалуйста, опубликуйте план выполнения.
Полиция SQL

2
Тем не менее мы не видим Execution Plan. Пожалуйста,
отправьте

Ответы:


10

Как уже упоминалось, план выполнения будет действительно полезным в этом случае. Судя по тому, что вы показали, кажется, что вы извлекли 12 столбцов из 15 столбцов tb1 (a), поэтому вы можете попытаться выполнить запрос без какого-либо объединения и просто с помощью команды, tb1чтобы увидеть, работает ли ваш запрос, как ожидалось. Поскольку я не вижу ничего плохого в ваших вызовах функций SUM, я думаю, у вас есть проблема с вашими объединениями, я бы предложил сделать следующее. Вы можете начать, исключив, например, последнее объединение INNER JOIN tb5 e on c.col7 = e.idи любое его использование, например, e.Class as [Class]иe.Classв вашей группе по заявлению. Мы не собираемся исключать это полностью, это всего лишь тест, чтобы убедиться, что проблема в этом или нет, если ваш запрос выполняется лучше и, как и ожидалось, вы можете попробовать использовать временную таблицу в качестве обходного пути вместо последнего соединения , что-то вроде этого:

SELECT *
INTO #Temp
FROM
  (
     select * from tb5
  ) As tempTable;

SELECT 
    b.id as [ID]
    ,d.[Title] as [Title]
    ,e.Class as [Class]

    -- SUM Functions

FROM 
    tb1 a
INNER JOIN 
    tb2 b on a.id=b.fid and a.col3 = b.col4
INNER JOIN 
    tb3 c on b.fid = c.col5
INNER JOIN       
    tb4 d on c.id = d.col6
INNER JOIN 
    #Temp e on c.col7 = e.id
GROUP BY
    b.id, d.Title, e.Class

Фактически, временные таблицы - это таблицы, которые временно существуют на SQL Server. Временные таблицы полезны для хранения наборов непосредственных результатов, к которым обращаются несколько раз. Вы можете прочитать больше об этом здесь https://www.sqlservertutorial.net/sql-server-basics/sql-server-teilitary-tables/ А здесь https://codingsight.com/introduction-to-tevent-tables-in -SQL-сервер /

Также я настоятельно рекомендую, если вы используете хранимую процедуру, установите NOCOUNTдля ON, это также может обеспечить значительное повышение производительности, поскольку сетевой трафик значительно уменьшается:

SET NOCOUNT ON
SELECT *
INTO #Temp
-- The rest of code

На основании этого :

SET NOCOUNT ON - это оператор set, который запрещает сообщение, показывающее количество строк, затронутых операторами запроса T-SQL. Это используется в хранимых процедурах и триггерах, чтобы не показывать сообщение о поврежденных строках. Использование SET NOCOUNT ON в хранимой процедуре может значительно повысить производительность хранимой процедуры.


1
Не могли бы вы объяснить, почему копирование всего tb5в #Tempтаблицу и присоединение к временной таблице работают быстрее, чем tb5прямое соединение ? как правило, они содержат одинаковые данные (и #Tempможет отсутствовать индекс, если он существовал в tb5). Я действительно не могу понять, почему это более эффективно (насколько я знаю, должно быть менее эффективно копировать все данные и объединяться).
Зиг

2
@zig Вы правы в этом случае, но что если tb5он находится на другом сервере? В этом случае использование временной таблицы определенно быстрее, чем прямое соединение с другим сервером. Это было просто предложение протестировать и посмотреть, изменилось ли что-нибудь, у меня была похожая ситуация в прошлом, и, к счастью, временная таблица помогла OP и в этом случае.
Салах Акбари

2

Наилучшим подходом является вставка в переменную таблицы / хеш-таблицу (если число строк мало, используйте переменную таблицы или хеш-таблицу, если количество строк довольно велико). Затем обновите агрегацию и, наконец, выберите переменную таблицы или хэш-таблицу. Изучение плана запроса необходимо.

DECLARE @MYTABLE TABLE (ID INT, [Title] VARCHAR(500), [Class] VARCHAR(500),
[Current - Last 30 Days Col1] INT, [Current - Last 30 Days Col2] INT,
[Current - Last 90 Days Col1] INT,[Current - Last 90 Days Col2] INT,
[Current - Last 365 Days Col1] INT, [Current - Last 365 Days Col2] INT,
[Last year - Last 30 Days Col1] INT, [Last year - Last 30 Days Col2] INT,
[Last year - Last 90 Days Col1] INT, [Last year - Last 90 Days Col2] INT,
[Last year - Last 365 Days Col1] INT, [Last year - Last 365 Days Col2] INT)



INSERT INTO @MYTABLE(ID, [Title],[Class], 
[Current - Last 30 Days Col1], [Current - Last 30 Days Col2],
[Current - Last 90 Days Col1], [Current - Last 90 Days Col2],
[Current - Last 365 Days Col1], [Current - Last 365 Days Col2],
[Last year - Last 30 Days Col1], [Last year - Last 30 Days Col2],
[Last year - Last 90 Days Col1], [Last year - Last 90 Days Col2],
[Last year - Last 365 Days Col1], [Last year - Last 365 Days Col2]
  )
SELECT    b.id  ,d.[Title] ,e.Class ,0,0,0,0,0,0,0,0,0,0,0,0        
FROM     tb1 a
INNER JOIN   tb2 b on a.id=b.fid and a.col3 = b.col4
INNER JOIN   tb3 c on b.fid = c.col5
INNER JOIN   tb4 d on c.id = d.col6
INNER JOIN  tb5 e on c.col7 = e.id
GROUP BY b.id, d.Title, e.Class

UPDATE T 
SET [Current - Last 30 Days Col1]=K.[Current - Last 30 Days Col1] , 
[Current - Last 30 Days Col2]    =K.[Current - Last 30 Days Col2],
[Current - Last 90 Days Col1]    = K.[Current - Last 90 Days Col1], 
[Current - Last 90 Days Col2]    =K.[Current - Last 90 Days Col2] ,
[Current - Last 365 Days Col1]   =K.[Current - Last 365 Days Col1], 
[Current - Last 365 Days Col2]   =K.[Current - Last 365 Days Col2],
[Last year - Last 30 Days Col1]  =K.[Last year - Last 30 Days Col1],
 [Last year - Last 30 Days Col2] =K.[Last year - Last 30 Days Col2],
[Last year - Last 90 Days Col1]  =K.[Last year - Last 90 Days Col1], 
[Last year - Last 90 Days Col2]  =K.[Last year - Last 90 Days Col2],
[Last year - Last 365 Days Col1] =K.[Last year - Last 365 Days Col1],
 [Last year - Last 365 Days Col2]=K.[Last year - Last 365 Days Col2]
    FROM @MYTABLE T JOIN 
     (
SELECT 
    b.id as [ID]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Current - Last 30 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Current - Last 30 Days Col2]

    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Current - Last 90 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Current - Last 90 Days Col2]

    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Current - Last 365 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Current - Last 365 Days Col2]

    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Last year - Last 30 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Last year - Last 30 Days Col2]

    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Last year - Last 90 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Last year - Last 90 Days Col2]

    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END),0) as [Last year - Last 365 Days Col1]
    ,ISNULL(Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END),0) as [Last year - Last 365 Days Col2]
    FROM     tb1 a
INNER JOIN   tb2 b on a.id=b.fid and a.col3 = b.col4
INNER JOIN   tb3 c on b.fid = c.col5
INNER JOIN   tb4 d on c.id = d.col6
INNER JOIN  tb5 e on c.col7 = e.id
GROUP BY    b.id
) AS K ON T.ID=K.ID


SELECT *
FROM @MYTABLE

0

Я предполагаю, что tb1 - большая таблица (относительно tb2, tb3, tb4 и tb5).

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

Если используется только небольшая часть tb1, например, потому что объединения с tb2, tb3, tb4 и tb5 сокращают необходимые строки до нескольких процентов, то вам следует проверить, проиндексированы ли таблицы по столбцам, которые вы используете в соединениях. ,

Если используется большая часть tb1, то может иметь смысл сгруппировать результаты, прежде чем объединять их с tb2, tb3, tb4 и tb5. Ниже приведен пример этого.

SELECT 
    b.id as [ID]
    ,d.[Title] as [Title]
    ,e.Class as [Class]
    ,SUM(a.[Current - Last 30 Days Col1]) AS [Current - Last 30 Days Col1]
    ,SUM(a.[Current - Last 30 Days Col2]) AS [Current - Last 30 Days Col2]
    ,SUM(a.[Current - Last 90 Days Col1]) AS [Current - Last 90 Days Col1]
    -- etc.
    FROM (
      SELECT a.id, a.col3

      ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 30 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 30 Days Col2]

      ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 90 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 90 Days Col2]

      ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Current - Last 365 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Current - Last 365 Days Col2]

      ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 30 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(MONTH,-13,GETDATE()) and a.DateCol <= DATEADD(MONTH,-12,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 30 Days Col2]

      ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 90 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(QUARTER,-5,GETDATE()) and a.DateCol <= DATEADD(QUARTER,-4,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 90 Days Col2]

      ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col1 ELSE 0 END) as [Last year - Last 365 Days Col1]
      ,Sum(CASE WHEN a.DateCol >= DATEADD(YEAR,-2,GETDATE()) and a.DateCol <= DATEADD(YEAR,-1,GETDATE()) THEN a.col2 ELSE 0 END) as [Last year - Last 365 Days Col2]

      FROM  tb1 a
      WHERE a.DateCol >= DATEADD(YEAR,-2,GETDATE())
      GROUP BY a.id, a.col3
    ) AS a
INNER JOIN 
    tb2 b on a.id=b.fid and a.col3 = b.col4
INNER JOIN 
    tb3 c on b.fid = c.col5
INNER JOIN       
    tb4 d on c.id = d.col6
INNER JOIN 
    tb5 e on c.col7 = e.id
GROUP BY
    b.id, d.Title, e.Class

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

Я действительно ненавижу, что мой пост получает отрицательный результат без объяснения причин. Конечно, я согласен с тем, что, чтобы понять суть проблемы с производительностью, нужно проверить план выполнения. Сказав это, я придерживаюсь своей рекомендации о проверке индексов для любых внешних ключей, которые имеют отношение к запросу.
Герт-

1
Вы «предполагаете» что-то, не зная. Таким образом, вы отправляете ответ на основе неизвестного. Поэтому понизить. Лучше поручить ОП улучшить свой вопрос, разместив план выполнения.
Полиция SQL

Это не все, что я написал. Лично я бы понизил голос, только если ответ плохой или неправильный, а не тогда, когда я просто не согласен. Но спасибо за ответ.
Герт-

В некотором смысле это неправильно, потому что, как вы можете доказать, что это правильно?
Полиция SQL


0

Для оптимизации таких вычислений вы можете предварительно рассчитать некоторые значения. Идея предварительных вычислений состоит в том, чтобы уменьшить количество строк, которые необходимо прочитать или продолжить.

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

Так, в приведенном ниже примере я создаю таблицу RowIDи RowDatetimeстолбцы и вставку 1 миллион строк. Я использую индексированное представление для подсчета сущностей в днях, поэтому вместо запроса 1 миллиона строк в год я буду запрашивать 365 строк в год для подсчета этих показателей.

DROP TABLE IF EXISTS [dbo].[DataSource];
GO

CREATE TABLE [dbo].[DataSource]
(
    [RowID] BIGINT IDENTITY(1,1) PRIMARY KEY
   ,[RowDateTime] DATETIME2
);

GO

DROP VIEW IF EXISTS [dbo].[vw_DataSource];
GO

CREATE VIEW [dbo].[vw_DataSource] WITH SCHEMABINDING
AS
SELECT YEAR([RowDateTime]) AS [Year]
      ,MONTH([RowDateTime]) AS [Month]
      ,DAY([RowDateTime]) AS [Day]
      ,COUNT_BIG(*) AS [Count]
FROM [dbo].[DataSource]
GROUP BY YEAR([RowDateTime])
        ,MONTH([RowDateTime])
        ,DAY([RowDateTime]);
GO

CREATE UNIQUE CLUSTERED INDEX [IX_vw_DataSource] ON [dbo].[vw_DataSource]
(
    [Year] ASC,
    [Month] ASC,
    [Day] ASC
);

GO

DECLARE @min bigint, @max bigint
SELECT @Min=1 ,@Max=1000000

INSERT INTO [dbo].[DataSource] ([RowDateTime])
SELECT TOP (@Max-@Min+1) DATEFROMPARTS(2019,  1.0 + floor(12 * RAND(convert(varbinary, newid()))), 1.0 + floor(28 * RAND(convert(varbinary, newid())))          )       
FROM master..spt_values t1 
CROSS JOIN master..spt_values t2

GO


SELECT *
FROM [dbo].[vw_DataSource]


SELECT SUM(CASE WHEN DATEFROMPARTS([Year], [Month], [Day]) >= DATEADD(MONTH,-1,GETDATE()) THEN [Count] ELSE 0 END) as [Current - Last 30 Days Col1]
      ,SUM(CASE WHEN DATEFROMPARTS([Year], [Month], [Day]) >= DATEADD(QUARTER,-1,GETDATE()) THEN [Count] ELSE 0 END) as [Current - Last 90 Days Col1]
      ,SUM(CASE WHEN DATEFROMPARTS([Year], [Month], [Day]) >= DATEADD(YEAR,-1,GETDATE()) THEN [Count] ELSE 0 END) as [Current - Last 365 Days Col1]
FROM [dbo].[vw_DataSource];

Успех такого решения во многом зависит от того, как распределены данные и сколько у вас строк. Например, если у вас есть одна запись в день для каждого дня года, представление и таблица будут иметь одинаковое совпадение строк, поэтому операции ввода-вывода не будут сокращены.

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


0

Я бы использовал таблицу поиска "Dates", чтобы объединить мои данные с индексом DatesId. Я использую даты в качестве фильтра, когда я хочу просмотреть исторические данные. Соединение быстрое, поэтому фильтрация в качестве DatesId является кластерным первичным индексом (первичным ключом). Добавьте столбец даты (как включенный столбец) для вашей таблицы данных.

Таблица дат имеет следующие столбцы:

DatesId, Дата, Год, Квартал, ГодQuarter, MonthNum, MonthNameShort, YearWeek, WeekNum, DayOfYear, DayOfMonth, DayNumOfWeek, DayName

Пример данных: 20310409 2031-04-09 2031 2 2031-Q2 4 апреля апрель 2031_15 15 99 9 3 среда

Вы можете отправить мне сообщение в личку, если вам нужен CSV-файл, чтобы вы могли импортировать его в базу данных, но я уверен, что вы можете легко найти что-то подобное в Интернете и сделать свой собственный.

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

SELECT * FROM dbo.dates where dateIndex BETWEEN (getDateIndexDate(getDate())-30 AND getDateIndexDate(getDate())+0) --30 days ago

Это позволяет мне легко вернуться к определенному периоду. Это довольно легко создать свои собственные взгляды на это. Конечно, вы можете использовать функцию ROW_NUMBER (), чтобы делать это годами, неделями и т. Д.

Как только я получу желаемый диапазон дат, я присоединяюсь к данным. Работает очень быстро!


0

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

SELECT f.id, f.[Title], f.Class,
    SUM(CASE WHEN f.MonthDiff = 1 THEN col1 ELSE 0 END) as [Current - Last 30 Days Col1],
    -- etc
FROM (
    SELECT 
        b.id,
        d.[Title],
        e.Class,
        DateDiff(Month, a.DateCol, GETDATE()) as MonthDiff,
        Sum(a.col1) as col1,
        Sum(a.col2) as col2
    FROM  tb1 a
    INNER JOIN tb2 b on a.id = b.fid and a.col3 = b.col4
    INNER JOIN tb3 c on b.fid = c.col5
    INNER JOIN tb4 d on c.id = d.col6
    INNER JOIN tb5 e on c.col7 = e.id
    WHERE a.DateCol between DATEADD(YEAR,-2,GETDATE() and GETDATE()
    GROUP BY b.id, d.Title, e.Class, DateDiff(Month,  a.DateCol, GETDATE())
) f
group by f.id, f.[Title], f.Class

-2

Чтобы повысить скорость SQL-запроса, вы должны добавить индексы. Для каждой объединенной таблицы необходимо добавить один индекс.

Как этот пример кода для оракула:

CREATE INDEX supplier_idx
ON supplier (supplier_name);

это не плохое предложение. из OP вы видите, что временная таблица создается без индекса - INNER JOIN #Temp e на c.col7 = e.id. В то время как в ответе есть место для улучшения, я не думаю, что его нужно массово отвергать. особенно для нового пользователя.
smoore4

@ smoore4 Согласитесь, этот вариант понижения голосов без четкого аргумента должен быть удален. Существует большая злоупотребление этой функциональностью
Greggz
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.