Как оптимизировать SQL выбор х делить на подзапрос с суммой (у) с другой таблицей? - PullRequest
3 голосов
/ 14 июля 2011

У меня есть этот запрос в T-SQL 2008:

SELECT a.Amount / (
    SELECT SUM(b.Amount) FROM Revenue b 
    WHERE YEAR(b.RevenueDate) = YEAR(a.ExpenseDate)
    AND MONTH(b.RevenueDate) = MONTH(a.ExpenseDate)
    AND b.HotelKey = a.HotelKey
)
FROM Expense a

Проблема в том, что для завершения запроса требуется слишком много времени. Я думаю, что это вызвано подзапросом «ВЫБЕРИТЕ СУММУ (b.Amount) ОТ Дохода b ...», который выполняется для каждой строки в таблице Расходы.

Как оптимизировать такой запрос? Есть ли лучшая альтернатива для запроса?

РЕДАКТИРОВАТЬ: Извините, я забыл предложение "AND b.HotelKey = a.HotelKey" в подзапросе. Приведенный выше исходный запрос был обновлен.

@ Дэмиен:

Ваш запрос добавлен с помощью присоединения HotelKey:

SELECT
    a.Amount / b.Amount
FROM
    Expense a
    inner join
    (SELECT
        HotelKey,
        DATEADD(month,DATEDIFF(month,0,RevenueDate),0) as MonthStart,
        DATEADD(month,1+DATEDIFF(month,0,RevenueDate),0) as MonthEnd,
        SUM(Amount) as Amount
     FROM
        Revenue
     GROUP BY
        HotelKey,
        DATEADD(month,DATEDIFF(month,0,RevenueDate),0),
        DATEADD(month,1+DATEDIFF(month,0,RevenueDate),0)
    ) b 
    ON
        a.ExpenseDate >= b.MonthStart and
        a.ExpenseDate < b.MonthEnd 
        and a.HotelKey = b.HotelKey

Ответы [ 4 ]

4 голосов
/ 14 июля 2011

Попробуйте изменить предложение where во внутреннем запросе на следующее:

where b.RevenueDate >= dateadd(month, datediff(month, 0, a.ExpenseDate), 0) and
      b.RevenueDate < dateadd(month, 1+datediff(month, 0, a.ExpenseDate), 0)

Это даст запросу возможность использовать индекс на Доходе. Дата восстановления, если он у вас есть.

3 голосов
/ 14 июля 2011

Если вы используете много строк в Revenue для удовлетворения этого запроса, вам лучше сделать один подзапрос, который вычисляет все итоги.(Кроме того, используя предложение Микаэля для того, чтобы разрешить некоторую индексацию):

SELECT
    a.Amount / b.Amount
FROM
    Expense a
        inner join
    (SELECT
         DATEADD(month,DATEDIFF(month,0,RevenueDate),0) as MonthStart,
         DATEADD(month,1+DATEDIFF(month,0,RevenueDate),0) as MonthEnd
         SUM(Amount) as Amount
     FROM
         Revenue
     GROUP BY
         DATEADD(month,DATEDIFF(month,0,RevenueDate),0),
         DATEADD(month,1+DATEDIFF(month,0,RevenueDate),0)
    ) b 
         ON
              a.ExpenseDate >= b.MonthStart and
              a.ExpenseDate < b.MonthEnd
1 голос
/ 14 июля 2011

Вы не указываете, насколько большие таблицы. Но вы можете ускорить запрос, создав вычисляемый столбец (и проиндексировав его) из комбинации year-month в таблице Revenue, а также в таблице Expense (если эта таблица не очень мала). Таким образом, эти вычисленные столбцы (и индексы) будут использоваться в запросе для объединения двух таблиц.

См .: Вычисляемые столбцы

и: Создание индексов для вычисляемых столбцов

0 голосов
/ 14 июля 2011

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

SELECT a.ExpenseAmount / b.RevenueAmount

FROM
(
    SELECT SUM(Expense.Amount) As ExpenseAmount,
    YEAR(Expense.ExpenseDate) AS ExpenseYear, 
    MONTH(Expense.ExpenseDate) AS ExpenseMonth
    GROUP BY 
    YEAR(Expense.RevenueDate), 
    MONTH(Expense.RevenueDate)
) AS a INNER JOIN 
(
    SELECT SUM(Revenue.Amount) AS RevenueAmount,
    YEAR(Revenue.RevenueDate) AS RevenueYear, 
    MONTH(Revenue.RevenueDate) AS RevenueMonth
    FROM Revenue
    GROUP BY YEAR(Revenue.RevenueDate), MONTH(Revenue.RevenueDate)
) as b ON a.ExpenseYear = b.RevenueYear AND a.ExpenseMonth = b.ExpenseMonth
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...