Использование итоги на агрегатах для повышения производительности
-
16-10-2019 - |
Вопрос
У меня есть две таблицы: детали и общие данные этих деталей.
Подробности (Медленное решение):
select
OrderId = r.OrderId
, TotalQty = SUM(r.Quantity)
, TotalGrossConsid = SUM(r.Price * r.Quantity)
from dbo.Order r
group by r.OrderId
Итого (Быстрое решение):
select
t.OrderId
, t.TotalQty
, t.TotalGrossConsid
, t.IsValid
from dbo.OrderTotal t
Иногда итоги становятся недействительными (некоторая работа должна пересматривать изменения, но это задержки). Как вы понимаете, второй запрос быстрее, а количество допустимых итоги больше, чем неверные. Таким образом, я ищу комбинированный запрос, который возвращает допустимые итоги со второй таблицы (итоги) и возвращает динамически пересчитанные итоги, используя первый медленный запрос. Таким образом, моя цель будет достигнута: все итоги являются действительными, и время до реагирования быстрее, чем полное пересчете.
Вот моя попытка (Гибридный раствор):
with fast_static(OrderId, TotalQty, TotalGrossConsid, IsValid)
as
(
select
t.OrderId
, t.TotalQty
, t.TotalGrossConsid
, t.IsValid
from dbo.OrderTotal t
)
, slow_dynamic(OrderId, TotalQty, TotalGrossConsid)
(
select
OrderId = r.OrderId
, TotalQty = SUM(r.Quantity)
, TotalGrossConsid = SUM(r.Price * r.Quantity)
from dbo.Order r
)
select
OrderId, TotalQty, TotalGrossConsid
from fast_static
where IsValid = 1
union all
select
OrderId, TotalQty, TotalGrossConsid
from slow_dynamic s
--inner join fast_static ff
--on ff.OrderId = s.OrderId
where --ff.Valid = 0 -- too slow!!!
s.OrderId in (select OrderId from fast_static f where f.Valid = 0)
Я сравнил быстрое решение и гибридный, я получил от 32% до 68% (относительные затраты на запрос). Если вы видите комментарий к варианту, он равен от 1% до 99% (слишком плохо). Можно ли улучшить этот запрос?
ДОБАВЛЕН
@GBN:
Valid = case when i.OrderId is null then 1 else 0 end
...
dbo.OrderTotal t left join dbo.InvalidOrders i
Да, у меня есть работа по пересчете итоги, и этот процесс не синхронизирован с запросами. Таблицы недействительных - это маленькая, которая хранит записи, чтобы знать, что итоги недействительны (должны быть пересчитаны)
РЕШЕНИЕ
Индексированные взгляды - лучший выбор. Помните о SQL Server Edition (noexpand подсказка для не входных изданий) и будьте готовы к воссоздать некоторые объекты базы данных (SET ANSI_NULLS ON, SET QUOTED_IDENTIFIER ON
) начать использовать индексированные представления на стороне клиента.
Решение
Я не могу понять, почему вы не можете агрегировать на лету и почему это так медленно. Является ли «действительная» идея обходной точки
Обе эти идеи отказываются от таблицы недействительных задержков, которая является обходным путем для плохой индексации.
- Предложение 1:
Создать вычисленный столбец
ALTER TABLE dbo.Order ADD PriceXQuantity AS Price * Quantity PERSISTED
Добавьте индекс
CREATE INDEX IX_Totals ON dbo.Order (OrderID) INCLUDE Quantity, PriceXQuantity)
Посмотрите, что произойдет
- Предложение 2:
Используйте индексированный вид
CREATE VIEW OrderTotals
WITH SCHEMABINDING
AS
select
OrderId = r.OrderId
, TotalQty = SUM(r.Quantity)
, TotalGrossConsid = SUM(r.Price * r.Quantity)
, COUNT_BIG(*) AS Dummy
from dbo.Order r
group by r.OrderId
GO
CREATE UNIQUE CLUSTERED INDEX IXCU_OrderTotals ON OrderTotals (OrderId9
GO
Вы также можете использовать вычисленный столбец здесь
Другие советы
Если стоимость не будет слишком высокой, вы можете подумать о перемещении IsValid
флаг в Detail
Таблица и указать это? Это замедлит ваши транзакции, но улучшит производительность запроса как (предположительно) большие Detail
Таблица будет доступна в одном большом range scan