Пожалуйста, потерпите меня - я знаю, что это сложно.
У меня есть таблица с квартирами, а другая - с арендой этих квартир. Моя задача - выбрать из списка «наиболее актуальную» аренду. В общем, это означает самый последний договор аренды, но есть несколько причуд, которые делают его более сложным, чем просто упорядочивание по дате.
Это привело меня к созданию этого общего запроса табличного выражения внутри представления, к которому я затем ПРИСОЕДИНЯЮСЬ с рядом других внутри хранимой процедуры, чтобы получить нужные мне результаты:
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, которое я не могу в представлении. С более чем 10 000 договоров аренды на 16 зданий в таблице, возможность фильтрации с помощью WHERE может отбросить строки, затронутые от 90% до 95%.
Принимая во внимание все это, есть ли что-нибудь вопиющее, чего мне здесь не хватает? Я делаю что-то не так с View, что может вызвать ужасную производительность, или это просто вопрос меньшего набора результатов в таблице Temp, превышающего неограниченный набор результатов в CTE?
РЕДАКТИРОВАТЬ: Я должен добавить, что эта бизнес-логика выбора «наиболее подходящей аренды» является ключевой для многих отчетов в системе. Вот почему он изначально был помещен в View. Представление дает нам возможность «писать один раз, использовать много», тогда как временная таблица в хранимой процедуре должна быть воссоздана для каждой другой хранимой процедуры в системе. Уродливый.
РЕДАКТИРОВАТЬ №2: Могу ли я использовать табличную функцию вместо представления? Позволит ли это мне ограничить количество затронутых строк заранее и по-прежнему использовать полученный набор данных в JOIN с другими таблицами? Если он работает и имеет приличную производительность, это позволит мне хранить бизнес-логику в одном месте (функции) вместо того, чтобы дублировать ее в десятках хранимых процедур.