Этот отчет занимал около 16 секунд, когда для обработки было 8000 строк. Теперь 50000 строк и отчет занимает 2:30 минуты.
Это был мой первый проход, и клиент нуждался в нем вчера, поэтому я написал этот код в логическом порядке того, что нужно было сделать, но без оптимизации.
Теперь, когда отчет увеличивается по мере увеличения данных, мне нужно еще раз взглянуть на это и оптимизировать его. Я имею в виду индексированные представления, табличные функции и т. Д.
Я думаю, что самым большим узким местом является циклическое перемещение по временной таблице, создание 4 операторов выбора и обновление временной таблицы ... 50000 раз.
Я думаю, что могу сжать ВСЕ это в один большой SELECT либо (a) 4 соединениями в одну и ту же таблицу, чтобы получить 4 статуса, но тогда я не уверен, как получить ТОП 1, или я могу попробуйте (b) использовать вложенные подзапросы, но по сравнению с текущим кодом они кажутся очень грязными.
Я не ожидаю, что кто-нибудь напишет для меня код, но если некоторые эксперты по SQL смогут просмотреть этот код и рассказать мне о любых очевидных недостатках и альтернативных методах, или способах ускорения этого, или методах, которые я должен использовать вместо это было бы оценено.
PS: предположим, что эта БД по большей части нормализована, но плохо спроектирована, и что я не могу добавлять индексы. Я в основном должен работать с этим, как есть.
Там, где код говорит (меньше чем), мне пришлось заменить символ «меньше чем», потому что он обрезал часть моего кода.
Спасибо!
CREATE PROCEDURE RptCollectionAccountStatusReport AS
SET NOCOUNT ON;
DECLARE @Accounts TABLE
(
[AccountKey] INT IDENTITY(1,1) NOT NULL,
[ManagementCompany] NVARCHAR(50),
[Association] NVARCHAR(100),
[AccountNo] INT UNIQUE,
[StreetAddress] NVARCHAR(65),
[State] NVARCHAR(50),
[PrimaryStatus] NVARCHAR(100),
[PrimaryStatusDate] SMALLDATETIME,
[PrimaryDaysRemaining] INT,
[SecondaryStatus] NVARCHAR(100),
[SecondaryStatusDate] SMALLDATETIME,
[SecondaryDaysRemaining] INT,
[TertiaryStatus] NVARCHAR(100),
[TertiaryStatusDate] SMALLDATETIME,
[TertiaryDaysRemaining] INT,
[ExternalStatus] NVARCHAR(100),
[ExternalStatusDate] SMALLDATETIME,
[ExternalDaysRemaining] INT
);
INSERT INTO
@Accounts (
[ManagementCompany],
[Association],
[AccountNo],
[StreetAddress],
[State])
SELECT
mc.Name AS [ManagementCompany],
a.LegalName AS [Association],
c.CollectionKey AS [AccountNo],
u.StreetNumber + ' ' + u.StreetName AS [StreetAddress],
CASE WHEN c.InheritedAccount = 1 THEN 'ZZ' ELSE u.State END AS [State]
FROM
ManagementCompany mc WITH (NOLOCK)
JOIN
Association a WITH (NOLOCK) ON a.ManagementCompanyKey = mc.ManagementCompanyKey
JOIN
Unit u WITH (NOLOCK) ON u.AssociationKey = a.AssociationKey
JOIN
Collection c WITH (NOLOCK) ON c.UnitKey = u.UnitKey
WHERE
c.Closed IS NULL;
DECLARE @MaxAccountKey INT;
SELECT @MaxAccountKey = MAX([AccountKey]) FROM @Accounts;
DECLARE @index INT;
SET @index = 1;
WHILE @index (less than) @MaxAccountKey BEGIN
DECLARE @CollectionKey INT;
SELECT @CollectionKey = [AccountNo] FROM @Accounts WHERE [AccountKey] = @index;
DECLARE @PrimaryStatus NVARCHAR(100) = NULL;
DECLARE @PrimaryStatusDate SMALLDATETIME = NULL;
DECLARE @PrimaryDaysRemaining INT = NULL;
DECLARE @SecondaryStatus NVARCHAR(100) = NULL;
DECLARE @SecondaryStatusDate SMALLDATETIME = NULL;
DECLARE @SecondaryDaysRemaining INT = NULL;
DECLARE @TertiaryStatus NVARCHAR(100) = NULL;
DECLARE @TertiaryStatusDate SMALLDATETIME = NULL;
DECLARE @TertiaryDaysRemaining INT = NULL;
DECLARE @ExternalStatus NVARCHAR(100) = NULL;
DECLARE @ExternalStatusDate SMALLDATETIME = NULL;
DECLARE @ExternalDaysRemaining INT = NULL;
SELECT TOP 1
@PrimaryStatus = a.StatusName, @PrimaryStatusDate = c.StatusDate, @PrimaryDaysRemaining = c.DaysRemaining
FROM CollectionAccountStatus c WITH (NOLOCK) JOIN AccountStatus a WITH (NOLOCK) ON c.AccountStatusKey = a.AccountStatusKey
WHERE c.CollectionKey = @CollectionKey AND a.StatusType = 'Primary Status' AND a.StatusName 'Cleared'
ORDER BY c.sysCreated DESC;
SELECT TOP 1
@SecondaryStatus = a.StatusName, @SecondaryStatusDate = c.StatusDate, @SecondaryDaysRemaining = c.DaysRemaining
FROM CollectionAccountStatus c WITH (NOLOCK) JOIN AccountStatus a WITH (NOLOCK) ON c.AccountStatusKey = a.AccountStatusKey
WHERE c.CollectionKey = @CollectionKey AND a.StatusType = 'Secondary Status' AND a.StatusName 'Cleared'
ORDER BY c.sysCreated DESC;
SELECT TOP 1
@TertiaryStatus = a.StatusName, @TertiaryStatusDate = c.StatusDate, @TertiaryDaysRemaining = c.DaysRemaining
FROM CollectionAccountStatus c WITH (NOLOCK) JOIN AccountStatus a WITH (NOLOCK) ON c.AccountStatusKey = a.AccountStatusKey
WHERE c.CollectionKey = @CollectionKey AND a.StatusType = 'Tertiary Status' AND a.StatusName 'Cleared'
ORDER BY c.sysCreated DESC;
SELECT TOP 1
@ExternalStatus = a.StatusName, @ExternalStatusDate = c.StatusDate, @ExternalDaysRemaining = c.DaysRemaining
FROM CollectionAccountStatus c WITH (NOLOCK) JOIN AccountStatus a WITH (NOLOCK) ON c.AccountStatusKey = a.AccountStatusKey
WHERE c.CollectionKey = @CollectionKey AND a.StatusType = 'External Status' AND a.StatusName 'Cleared'
ORDER BY c.sysCreated DESC;
UPDATE
@Accounts
SET
[PrimaryStatus] = @PrimaryStatus,
[PrimaryStatusDate] = @PrimaryStatusDate,
[PrimaryDaysRemaining] = @PrimaryDaysRemaining,
[SecondaryStatus] = @SecondaryStatus,
[SecondaryStatusDate] = @SecondaryStatusDate,
[SecondaryDaysRemaining] = @SecondaryDaysRemaining,
[TertiaryStatus] = @TertiaryStatus,
[TertiaryStatusDate] = @TertiaryStatusDate,
[TertiaryDaysRemaining] = @TertiaryDaysRemaining,
[ExternalStatus] = @ExternalStatus,
[ExternalStatusDate] = @ExternalStatusDate,
[ExternalDaysRemaining] = @ExternalDaysRemaining
WHERE
[AccountNo] = @CollectionKey;
SET @index = @index + 1;
END;
SELECT
[ManagementCompany],
[Association],
[AccountNo],
[StreetAddress],
[State],
[PrimaryStatus],
CONVERT(VARCHAR, [PrimaryStatusDate], 101) AS [PrimaryStatusDate],
[PrimaryDaysRemaining],
[SecondaryStatus],
CONVERT(VARCHAR, [SecondaryStatusDate], 101) AS [SecondaryStatusDate],
[SecondaryDaysRemaining],
[TertiaryStatus],
CONVERT(VARCHAR, [TertiaryStatusDate], 101) AS [TertiaryStatusDate],
[TertiaryDaysRemaining],
[ExternalStatus],
CONVERT(VARCHAR, [ExternalStatusDate], 101) AS [ExternalStatusDate],
[ExternalDaysRemaining]
FROM
@Accounts
ORDER BY
[ManagementCompany],
[Association],
[StreetAddress]
ASC;