SQL CTE в представлении против временной таблицы в хранимой процедуре - PullRequest
2 голосов
/ 30 января 2011

Пожалуйста, потерпите меня - я знаю, что это сложно.

У меня есть таблица с квартирами, а другая - с арендой этих квартир. Моя задача - выбрать из списка «наиболее актуальную» аренду. В общем, это означает самый последний срок аренды, но есть несколько причуд, которые делают его более сложным, чем просто заказ по дате.

Это привело меня к созданию этого общего запроса табличного выражения в представлении, которое я затем СОЕДИНЯЛ со многими другими внутри хранимой процедуры, чтобы получить нужные мне результаты:

WITH TempTable AS (
    SELECT  l.BuildingID, l.ApartmentID, l.LeaseID, l.ApplicantID,
                ROW_NUMBER() OVER (PARTITION BY l.ApartmentID ORDER BY s.Importance DESC, MovedOut, MovedIN DESC, LLSigned DESC, Approved DESC, Applied DESC) AS 'RowNumber'
    FROM    dbo.NPleaseapplicant AS l INNER JOIN
            dbo.NPappstatus AS s ON l.BuildingID = s.BuildingID AND l.AppStatus = s.Code

)

SELECT  BuildingID, ApartmentID, LeaseID, ApplicantID
FROM    TempTable
WHERE   RowNumber = 1

Это работает и возвращает правильный результат. Проблема, с которой я сталкиваюсь, заключается в очень низкой производительности.

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

CREATE TABLE #Relevant (
    BuildingID int,
    ApartmentID int,
    LeaseID int,
    ApplicantID int,
    RowNumber int
)

INSERT INTO #Relevant (BuildingID, ApartmentID, LeaseID, ApplicantID, RowNumber)
SELECT  l.BuildingID, l.ApartmentID, l.LeaseID, l.ApplicantID,
            ROW_NUMBER() OVER (PARTITION BY l.ApartmentID ORDER BY s.Importance DESC, MovedOut, MovedIN DESC, LLSigned DESC, Approved DESC, Applied DESC) AS 'RowNumber'
FROM    dbo.NPleaseapplicant AS l INNER JOIN
        dbo.NPappstatus AS s ON l.BuildingID = s.BuildingID AND l.AppStatus = s.Code
WHERE   (l.BuildingID = @BuildingID)

DROP TABLE #Relevant

На первый взгляд это не значит для меня. Я слышал, что временные таблицы, как известно, плохо влияют на производительность. Проблема заключается в том, что я могу лучше ограничить запрос в таблице Temp с помощью предложения WHERE, чего нет в представлении. С более чем 10000 аренды в 16 зданиях в таблице, возможность фильтрации с ГДЕ может отбрасывать строки, затронутые 90% - 95%.

Имея все это в виду, есть что-то яркое, что я здесь скучаю? Я делаю что-то не так с представлением, которое может вызвать ужасную производительность, или это просто вопрос меньшего набора результатов в таблице временных параметров, превосходящего неограниченный набор результатов в CTE?

РЕДАКТИРОВАТЬ: Я должен добавить, что эта бизнес-логика выбора "наиболее подходящего аренды" является ключом ко многим отчетам в системе. Вот почему он был помещен в View для начала. Представление дает нам возможность «Один раз написать, использовать много», тогда как временная таблица в хранимой процедуре должна быть воссоздана для каждого другого хранимого процесса в системе. Некрасиво.

РЕДАКТИРОВАТЬ # 2: Могу ли я использовать табличную функцию вместо представления? Позволит ли это мне ограничить число строк, затронутых заранее, и по-прежнему использовать полученный набор данных в JOIN с другими таблицами? Если это работает - и имеет приличную производительность - это позволило бы мне хранить бизнес-логику в одном месте (функцию) вместо дублирования ее в десятках хранимых процедур.

Ответы [ 2 ]

4 голосов
/ 08 февраля 2011

Просто чтобы поклониться этому, вот что я в итоге сделал:

Вместо того, чтобы использовать View для объединения всех возможных строк из 2 или 3 таблиц, я создал функцию Table Based, которая делаеттот же основной запрос.В качестве одного из параметров я передаю идентификатор здания и использую его в предложении WHERE, например:

SELECT  l.BuildingID, l.ApartmentID, l.LeaseID, l.ApplicantID,
            ROW_NUMBER() OVER (PARTITION BY l.ApartmentID ORDER BY s.Importance DESC, MovedOut, MovedIN DESC, LLSigned DESC, Approved DESC, Applied DESC) AS 'RowNumber'
FROM    dbo.NPleaseapplicant AS l INNER JOIN
        dbo.NPappstatus AS s ON l.BuildingID = s.BuildingID AND l.AppStatus = s.Code
WHERE  (l.BuildingID = @BuildingID)

В результате резко сокращает количество требуемых объединенийи это значительно ускоряет запрос.

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

0 голосов
/ 20 февраля 2013

Вы также можете переписать представление с синтаксисом подзапроса:

SELECT  BuildingID, ApartmentID, LeaseID, ApplicantID
FROM
(
SELECT  l.BuildingID, l.ApartmentID, l.LeaseID, l.ApplicantID,
                ROW_NUMBER() OVER (PARTITION BY l.ApartmentID ORDER BY s.Importance DESC, MovedOut, MovedIN DESC, LLSigned DESC, Approved DESC, Applied DESC) AS 'RowNumber'
    FROM    dbo.NPleaseapplicant AS l INNER JOIN
            dbo.NPappstatus AS s ON l.BuildingID = s.BuildingID AND l.AppStatus = s.Code

)subquery
WHERE   RowNumber = 1

Это позволит применить ограничивающий Где (где используется представление) к подзапросу, тогда как случай CTE не ограничен.

Представления имеют меньше проблем с параллельными планами выполнения, чем табличные функции (хотя это, вероятно, в любом случае будет встроено, делая их фактически идентичными)

...