Использование T-SQL AVG или получение среднего значения после результатов, возвращенных с помощью LINQ
-
20-09-2019 - |
Вопрос
У меня есть хранимая процедура, которая использует представление для извлечения 6 средних значений.Базой данных SQL является SQL Server 2000.Когда я запускаю его в анализаторе запросов, это занимает примерно 9 секунд.Что я могу сделать, чтобы повысить производительность?Должен ли я возвращать строки с помощью LINQ и определять среднее значение таким образом?Будет ли это быстрее?
Вот пример моего текущего sproc:
create procedure [TestAvg]
(
@CustomerNumber int
)
as
select
(select AVG(OrderTime) from OrderDetails where ProductID = 12 and DateDiff(day, DateFulfilled, GetDate()) <= 7 and CustomerNumber = @CustomerNumber) as P12D7,
(select AVG(OrderTime) from OrderDetails where ProductID = 12 and DateDiff(day, DateFulfilled, GetDate()) <= 30 and CustomerNumber = @CustomerNumber) as P12D30,
(select AVG(OrderTime) from OrderDetails where ProductID = 12 and DateDiff(day, DateFulfilled, GetDate()) <= 90 and CustomerNumber = @CustomerNumber) as P12D90,
(select AVG(OrderTime) from OrderDetails where ProductID = 16 and DateDiff(day, DateFulfilled, GetDate()) <= 7 and CustomerNumber = @CustomerNumber) as P16D7,
(select AVG(OrderTime) from OrderDetails where ProductID = 16 and DateDiff(day, DateFulfilled, GetDate()) <= 30 and CustomerNumber = @CustomerNumber) as P16D30,
(select AVG(OrderTime) from OrderDetails where ProductID = 16 and DateDiff(day, DateFulfilled, GetDate()) <= 90 and CustomerNumber = @CustomerNumber) as P16D90
Кроме того, позвольте мне прояснить точку зрения, упомянутую выше.Поскольку это SQL Server 2000, я не могу использовать индексированное представление, потому что оно использует подзапрос.Я полагаю, это можно переписать, чтобы использовать соединения.Однако в последний раз, когда мы взяли запрос и переписали его для использования объединений, данные отсутствовали (поскольку подзапрос может возвращать нулевое значение, в котором будет опущена вся строка).
Решение
Я бы рекомендовал сначала занести данные в табличный var, возможно, в 2 табличных vars, 1 для 12 и 1 для 16 ProductID.Исходя из этих табличных переменных, вычислите средние значения по мере необходимости, а затем верните их из sp.
DECLARE @OrderDetails12 TABLE(
DateFulfilled DATETIME,
OrderTime FLOAT
)
INSERT INTO @OrderDetails12
SELECT DateFulfilled,
OrderTime
FROM OrderDetails
WHERE ProductID = 12
AND DateDiff(day, DateFulfilled, GetDate()) <= 90
and CustomerNumber = @CustomerNumber
DECLARE @OrderDetails16 TABLE(
DateFulfilled DATETIME,
OrderTime FLOAT
)
INSERT INTO @OrderDetails16
SELECT DateFulfilled,
OrderTime
FROM OrderDetails
WHERE ProductID = 16
AND DateDiff(day, DateFulfilled, GetDate()) <= 90
and CustomerNumber = @CustomerNumber
Кроме того, создание правильных индексов в таблице очень поможет.
Другие советы
Каков был бы объем данных, покидающих сервер базы данных, если бы они были неагрегированы, и как долго требовалось для выполнения этой операции?Разница в размере данных будет определять, перевешивается ли время вычисления на сервере временем передачи и локальным вычислением.
Кроме того - посмотрите на это DATEDIFF
использование и измените его, чтобы упростить его оптимизацию (попробуйте DateFullfilled >= SomeCalculatedDate1 вместо DATEDIFF
) - просмотрите свой план выполнения, чтобы убедиться, что он может использовать поиск по индексу (best) или сканирование индекса (good) вместо table_scan.
Кроме того, убедитесь, что есть индекс для CustomerNumber, ProduceID, DateFulfilled.