Раньше этот отчет занимал около 16 секунд при обработке 8000 строк. Теперь есть 50000 строк, и отчет занимает 2:30 минут.
Это был мой первый проход, и клиенту он понадобился вчера, поэтому я написал этот код в логическом порядке, в котором необходимо было сделать, но без учета оптимизации.
Теперь, когда отчет занимает больше времени по мере увеличения данных, мне нужно еще раз взглянуть на это и оптимизировать его. Я думаю об индексированных представлениях, табличных функциях и т. Д.
Я думаю, что самым большим узким местом является цикл по временной таблице, выполнение 4 операторов выбора и обновление временной таблицы ... 50 000 раз.
Я думаю, что могу объединить ВСЕ это в один большой 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;