當有8000行要處理時,此報告大約需要16秒。現在有50000行,報告需要2:30分鐘。SQL查詢優化
這是我第一次通過這個,客戶需要它,所以我按照需要完成的邏輯順序編寫了這段代碼,但沒有考慮優化。
現在隨着數據的增加,報告花費的時間越來越長,我需要再看看這個並優化它。我正在考慮索引視圖,表函數等
我認爲最大的瓶頸是循環通過臨時表,使4選擇語句,並更新臨時表... 50,000次。
我想我可以將所有這一切壓縮成一個大的SELECT,或者(a)4個連接到同一個表以獲得4個狀態,但是我不知道如何獲得TOP 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;
您正在使用什麼版本的SQL Server? – Lamak 2011-02-07 17:32:03
SQL 2008 R2是該版本。 – Blackcoil 2011-02-07 17:35:16