2008-11-26 20 views
3

我有一個商業用戶,他試圖編寫他自己的SQL查詢項目統計報告(例如任務數量,里程碑等)。查詢首先聲明一個80列以上的臨時表。然後,通過近500行代碼,每個代碼包含他們自己的一小組業務規則,臨時表中有將近70條UPDATE語句。它以臨時表中的SELECT *結束。重構「極端」的SQL查詢

由於時間的限制和「其他因素」的影響,現在已經投入生產,現在我的團隊堅持支持它。性能令人震驚,雖然感謝一些整理,但閱讀和理解起來相當容易(儘管代碼味道很討厭)。

我們應該關注哪些關鍵領域,使其更快速並遵循良好的實踐?

+0

將此信息添加到主文章中,並在可能的情況下進行適當標記。 – 2008-11-26 15:34:38

回答

5

首先,如果這不會導致業務問題,則將其保留,直到問題出現。等到它成爲問題,然後解決所有問題。

當你決定修復它時,檢查是否有一條語句導致你的大部分速度問題... issolate並修復它。

如果速度問題已經覆蓋了所有的語句,並且可以將它們合併爲一個SELECT語句,這可能會節省您的時間。我曾經將一個proc轉換成一個SELECT(沒有更新),並且運行它的時間從3分鐘到3秒以內(沒有狗屎......我簡直不敢相信)。順便說一下,如果某些數據來自鏈接的服務器,請不要嘗試此操作。

如果您不想或無法做到這一點,那麼您可能需要調整現有的proc。這裏有一些事情我想看看:

  1. 如果你正在創建臨時表的索引,等到你的初始插件來填充它。

  2. 調整您的初始INSERT插入儘可能多的列。這可能會消除一些更新。

  3. 在運行更新之前對臨時表進行索引。不要在更新語句目標的任何列上創建索引,直到它們更新。

  4. 如果您的表格和分組允許,請將您的更新分組。對於只有80列的70個更新是相當多的,聽起來像是可能有機會這樣做。

好運

1

好吧,既然你告訴我們關於這個存儲過程的唯一的事情是它有一個80 +列臨時表,我可以推薦的唯一的東西就是刪除該表,並重寫其餘的表以刪除需要爲了它。

+0

感謝詹姆斯,現在提供了更多關於這個問題的細節。 – 2008-11-26 15:19:47

0

你應該得到一個工具,讓你得到你的應用程序將運行的所有查詢的解釋計劃。對於性能提高的SQL重型應用程序來說,這是最好的回報。如果你對解釋計劃告訴你的內容有所瞭解並作出反應。如果你在Oracle上,我們曾經使用的是Qwest的TOAD(?),我想。這是一個偉大的工具。

2

我會做的第一件事是檢查以確保有一個活動的索引維護作業定期運行。如果沒有,則重建所有現有索引,或者如果不可能,則至少獲得統計信息更新。

我會做的第二件事是建立一個跟蹤(如描述here),並找出哪些語句導致讀取次數最多。

然後,我會在SSMS中運行'顯示實際執行計劃',並用跟蹤結果結果。由此你應該能夠計算出是否缺少可以提高性能的索引。

編輯:如果你打算downvote,請留下評論爲什麼。

1

如果這是生成存儲過程的報告,那麼它多久運行一次?如果只需要每天運行一次,並且在夜間運行,則表現有多大的問題?

如果不是這樣,我建議您在選擇時慎重重新編寫它,因爲有可能會弄糟你的數字。

此外,它聽起來像是應該被拉進SSIS包的東西,建立一個新的永久表與結果,所以它只需要運行一次。

希望這是有道理

0

我會建議看涉及的表,最終的結果,並從頭開始看,如果查詢可以以更有效的方式來完成。保持查詢來驗證新的工作與舊工作完全相同,但嘗試忘記所有用於獲取最終結果的方法。

2

就像任何重構一樣,確保每次更改後都有自動驗證重構的方式(您可以使用查詢來檢查開發輸出與已知良好基線的關係)。這樣,你總是匹配已知的良好數據。當您進入決定是否切換到新版本流程並希望並行運行幾次迭代以確保正確性的階段時,這將使您對方法的正確性保持高度信心。

我也喜歡記錄批次中所有批次的批次和批次的運行時間,所以我可以判斷批次中的某個特定批次是否在某個時間點受到不利影響。我可以獲得流程的平均時間,並查看改進趨勢或發現潛在問題。這也可以讓我發現批次內的低掛果實,我可以做出最大的改進。

-1

我會從頭開始重寫它。

你說你明白它應該做什麼,所以它不應該那麼困難。我敢打賭,這段代碼的要求會不斷變化,所以如果你現在不重寫它,你最終可能會維護一些醜陋的怪物。

+0

這幾乎總是導致錯誤的代碼。 – 2008-11-26 15:13:24

1

你可以嘗試的一件事是用表變量替換臨時表。有時候這是更快的時候,而不是時候,你將不得不嘗試一下,看看。

看看70更新聲明。可以將它們中的任何一個組合起來?如果寫作人員沒有使用CASE陳述,則可能會做更少的陳述。

要看的其他顯而易見的事情 - 消除任何遊標,更改任何子查詢以連接到表或派生表。

2

有那麼幾乎70 UPDATE語句 到臨時表在 的代碼幾乎500行,每 包含自己的小集合 業務規則。它完成與 SELECT *從臨時表。

實際上,這聽起來像是它可以很好地遵循和理解,每個更新語句都有一個具有特定目的和業務規則的表。我認爲維護500行代碼的過程需要一個或幾個選擇語句來完成,這些語句用15個左右的連接構建的「所有事情」和case語句等遍佈整個地方,難度更大。雖然它會提高性能......

這對於SQL來說有點困難,編寫清晰簡潔的代碼(使用多個更新,創建函數等)總是會對性能產生很大的負面影響。試圖一次完成所有事情,這在其他編程語言中被認爲是不好的做法,似乎是面向集合的語言的核心。

1

重寫也許。一種硬件解決方案是確保您的數據庫臨時表在一個'快速'驅動器上運行,也許是一個固態硬盤(SSD),或者可以在內存中進行全部管理。

我的猜測是這個'解決方案'是由一個掌握和依賴於電子表格的人開發的,一個對'規範化'數據庫可能不太瞭解的人 - 如何構建和填充表以保留數據以用於報告目的,這可能是BI商業智能軟件可以使用的複雜而適應性強的產品。

你沒有說'更新過程在哪裏'正在運行。更新過程是否作爲來自單獨計算機(桌面)的SQL腳本針對數據所在的服務器運行?這種方法可能會產生嚴重的瓶頸和開銷。如果是這樣,考慮作爲一個編譯存儲過程直接在服務器上運行整個更新過程作爲本地作業,繞過網絡和(多)遊標管理開銷。它可能有計劃的運行時間和受控優先級,完成非高峯時間的業務數據使用時間。

評估更新語句序列確實需要「提交」語句的頻率......保存在一堆提交行上可顯着提高總體更新時間。數據庫客戶端驅動程序軟件中可能存在一些設置,這可能會產生顯着差異。

是否可以將用於更新條件的查詢作爲靜態'視圖'分解出來,這又可以在多個更新語句之間共享?視圖可以保存在經常訪問的內存數據/查詢行中。在提交最佳之前,可能會進行性能調整以確定可以提交多少更新數據。

可能需要評估觸發器是否可用於替換批作業更新順序。您不會從數據表中使用的數據來自......這可能有助於決策制定。我不知道您是否可以將觸發器添加到從中收集數據的數據庫表中。如果是這樣,向多個表中添加一些觸發器並不會真正降低整個系統的性能,但可能會在該更新過程中節省大量時間。您可以嘗試用觸發器逐個替換更新語句,並查看結果是否與以前相同。根據相同的更新過程創建一個類似的臨時表,然後仔細測試觸發器是否將更新提供給臨時表可以替換單個更新語句。也許你可能有一種'數據倉庫'應用程序。查看如何設置表格的「明星」模式以保留用於報告的彙總業務數據可能很有用。

創建一個全面且緩存的「視圖」,通過查詢每天更新一次,反映更新可能是另一種探索方法。