У меня следующий запрос, и из-за большого количества 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();
Execution Plan
. Пожалуйста,Ответы:
Как уже упоминалось, план выполнения будет действительно полезным в этом случае. Судя по тому, что вы показали, кажется, что вы извлекли 12 столбцов из 15 столбцов
tb1 (a)
, поэтому вы можете попытаться выполнить запрос без какого-либо объединения и просто с помощью команды,tb1
чтобы увидеть, работает ли ваш запрос, как ожидалось. Поскольку я не вижу ничего плохого в ваших вызовах функций SUM, я думаю, у вас есть проблема с вашими объединениями, я бы предложил сделать следующее. Вы можете начать, исключив, например, последнее объединениеINNER JOIN tb5 e on c.col7 = e.id
и любое его использование, например,e.Class as [Class]
и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
, это также может обеспечить значительное повышение производительности, поскольку сетевой трафик значительно уменьшается:На основании этого :
источник
tb5
в#Temp
таблицу и присоединение к временной таблице работают быстрее, чемtb5
прямое соединение ? как правило, они содержат одинаковые данные (и#Temp
может отсутствовать индекс, если он существовал вtb5
). Я действительно не могу понять, почему это более эффективно (насколько я знаю, должно быть менее эффективно копировать все данные и объединяться).tb5
он находится на другом сервере? В этом случае использование временной таблицы определенно быстрее, чем прямое соединение с другим сервером. Это было просто предложение протестировать и посмотреть, изменилось ли что-нибудь, у меня была похожая ситуация в прошлом, и, к счастью, временная таблица помогла OP и в этом случае.Наилучшим подходом является вставка в переменную таблицы / хеш-таблицу (если число строк мало, используйте переменную таблицы или хеш-таблицу, если количество строк довольно велико). Затем обновите агрегацию и, наконец, выберите переменную таблицы или хэш-таблицу. Изучение плана запроса необходимо.
источник
Я предполагаю, что tb1 - большая таблица (относительно tb2, tb3, tb4 и tb5).
Если это так, то здесь имеет смысл ограничить выбор этой таблицы (с помощью предложения WHERE).
Если используется только небольшая часть tb1, например, потому что объединения с tb2, tb3, tb4 и tb5 сокращают необходимые строки до нескольких процентов, то вам следует проверить, проиндексированы ли таблицы по столбцам, которые вы используете в соединениях. ,
Если используется большая часть tb1, то может иметь смысл сгруппировать результаты, прежде чем объединять их с tb2, tb3, tb4 и tb5. Ниже приведен пример этого.
источник
Просто используйте вычисленные столбцы
пример
Укажите вычисляемые столбцы в таблице
источник
Для оптимизации таких вычислений вы можете предварительно рассчитать некоторые значения. Идея предварительных вычислений состоит в том, чтобы уменьшить количество строк, которые необходимо прочитать или продолжить.
Одним из способов достижения этого является использование индексированного представления и оставление механизма для выполнения расчетов самостоятельно. Поскольку у этого типа представлений есть некоторые ограничения, вы в итоге создаете простую таблицу и вместо этого выполняете вычисления. В основном это зависит от потребностей бизнеса.
Так, в приведенном ниже примере я создаю таблицу
RowID
иRowDatetime
столбцы и вставку 1 миллион строк. Я использую индексированное представление для подсчета сущностей в днях, поэтому вместо запроса 1 миллиона строк в год я буду запрашивать 365 строк в год для подсчета этих показателей.Успех такого решения во многом зависит от того, как распределены данные и сколько у вас строк. Например, если у вас есть одна запись в день для каждого дня года, представление и таблица будут иметь одинаковое совпадение строк, поэтому операции ввода-вывода не будут сокращены.
Кроме того, вышесказанное является лишь примером материализации данных и их чтения. В вашем случае вам может понадобиться добавить больше столбцов в определение представления.
источник
Я бы использовал таблицу поиска "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-файл, чтобы вы могли импортировать его в базу данных, но я уверен, что вы можете легко найти что-то подобное в Интернете и сделать свой собственный.
Я также добавляю столбец идентификаторов, чтобы вы могли получить целое число для каждой даты. Это немного облегчает работу, но не является обязательным требованием.
Это позволяет мне легко вернуться к определенному периоду. Это довольно легко создать свои собственные взгляды на это. Конечно, вы можете использовать функцию ROW_NUMBER (), чтобы делать это годами, неделями и т. Д.
Как только я получу желаемый диапазон дат, я присоединяюсь к данным. Работает очень быстро!
источник
Поскольку вы всегда группируете значения на основе целого числа месяцев, я бы сначала сгруппировал по месяцам в подзапросе в предложении from. Это похоже на использование временной таблицы. Не уверен, что это действительно ускорит ваш запрос.
источник
Чтобы повысить скорость SQL-запроса, вы должны добавить индексы. Для каждой объединенной таблицы необходимо добавить один индекс.
Как этот пример кода для оракула:
источник