Присоединение к CTE преобразование таблицы - PullRequest
2 голосов
/ 18 февраля 2011

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

Я привел пример с большой таблицей и таблицей меньших цен.

Введите таблицу CarPrices, в которой указаны цены по марке / модели автомобиля с датами начала и окончания.Я хочу объединить все проданные автомобили с продажной ценой в таблице CarPrices, по критерию SaleDate BETWEEN PriceStartingDate и PriceEndingDate, но если цены за период отсутствуют, я хочу присоединиться к самой новой найденной цене.

Я могу сделать это так, но это ужасно медленно:

WITH CarPricesTransformation AS (
    SELECT CarBrand, CarModel, PriceStartingDate,
        CASE WHEN row_number() OVER (PARTITION BY CarBrand, CarModel, 
            ORDER BY PriceStartingDate DESC) = 1
            THEN NULL ELSE PriceEndingDate END PriceEndingDate,
        Price
    FROM CarPrices
)
SELECT SUM(Price)
FROM LargeCarDataBase C
INNER JOIN CarPricesTransformation P
ON C.CarBrand = P.CarBrand
AND C.CarModel = P.CarModel
AND C.SaleDate >= P.PriceStartingDate
AND (C.SaleDate <= P.PriceEndingDate OR P.PriceEndingDate IS NULL)

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

Есть мысли ...?

Ответы [ 2 ]

0 голосов
/ 06 апреля 2011

Вы пробовали Индексированные просмотры ?

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

    CREATE VIEW [dbo].[SuperFastCarPrices] WITH SCHEMABINDING AS
    SELECT  C.CarBrand,
            C.CarModel,
            C.SaleDate,
            SUM(P.Price) AS Price
    FROM CarPrices P
    INNER JOIN LargeCarDataBase C
        ON C.CarBrand = P.CarBrand
        AND C.CarModel = P.CarModel
        AND C.SaleDate >= P.PriceStartingDate
        AND (P.PriceEndingDate IS NULL OR C.SaleDate <= P.PriceEndingDate)
    GROUP BY C.CarBrand, C.CarModel, C.SaleDate

    CREATE UNIQUE CLUSTERED INDEX [IDX_SuperFastCarPrices] 
    ON [dbo].[SuperFastCarPrices](CarBrand, CarModel, SaleDate)

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

Есть и обратная сторона: индексированные представления замедляют изменения базовых таблиц. Если вас беспокоит стоимость вставки записей в таблицу LargeCarDataBase после создания этого представления, вы можете создать индекс по столбцам CarBrand, CarModel и SaleDate, который должен ускорить вставку и обновление этой таблицы.

Подробнее об индексированных представлениях см. Статья Microsoft .

0 голосов
/ 02 марта 2011

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

Select
  Sum(Coalesce(ActivePrice.Price, LatestPrice.Price))
From
  LargeCarDataBase As Sales
  Left Outer Join CarPrices As ActivePrice
    On Sales.CarBrand = ActivePrice.CarBrand
    And Sales.CarModel = ActivePrice.CarModel
    And (((Sales.SaleDate >= ActivePrice.PriceStartingDate)
          And ((Sales.SaleDate <= ActivePrice.PriceEndingDate)
               Or (ActivePrice.PriceEndingDate Is Null)))
  Left Outer Join CarPrices As LatestPrice
    On Sales.CarBrand = LatestPrice.CarBrand
    And Sales.CarModel = LatestPrice.CarModel
    And LatestPrice.PriceEndingDate Is Null
...