若是你正在負責一個基於SQL Server的項目,或者你剛剛接觸SQL Server,你都有可能要面臨一些數據庫性能的問題,這篇文章會爲你提供一些有用的指導(其中大多數也能夠用於其它的DBMS)。在這裏,我不打算介紹使用SQL Server的竅門,也不能提供一個包治百病的方案,我所作的是總結一些經驗----關於如何造成一個好的設計。 程序員
1、瞭解你用的工具 數據庫
不要輕視這一點,這是我在這篇文章中講述的最關鍵的一條。也許你也看到有不少的SQL Server程序員沒有掌握所有的T-SQL命令和SQL Server提供的那些有用的工具。
「什麼?我要浪費一個月的時間來學習那些我永遠也不會用到的SQL命令???」,你也許會這樣說。對的,你不須要這樣作。可是你應該用一個週末瀏覽全部的 T-SQL命令。在這裏,你的任務是瞭解,未來,當你設計一個查詢時,你會記起來:「對了,這裏有一個命令能夠徹底實現我須要的功能」,因而,到MSDN 查看這個命令的確切語法。 編程
2、不要使用遊標 小程序
讓我再重複一遍:不要使用遊標。若是你想破壞整個系統的性能的話,它們卻是你最有效的首選辦法。大多數的初學者都使用遊標,而沒有意識到它們對性能形成的影響。它們佔用內存,還用它們那些難以想象的方式鎖定表,另外,它們簡直就像蝸牛。而最糟糕的是,它們可使你的DBA所能作的一切性能優化等於沒作。不知你是否知道每執行一次FETCH就等於執行一次SELECT命令?這意味着若是你的遊標有10000條記錄,它將執行10000次SELECT!若是你使用一組SELECT、UPDATE或者DELETE來完成相應的工做,那將有效率的多。
初學者通常認爲使用遊標是一種比較熟悉和溫馨的編程方式,可很不幸,這會致使糟糕的性能。顯然,SQL的整體目的是你要實現什麼,而不是怎樣實現。
我曾經用T-SQL重寫了一個基於遊標的存儲過程,那個表只有100,000條記錄,原來的存儲過程用了40分鐘才執行完畢,而新的存儲過程只用了10秒鐘。在這裏,我想你應該能夠看到一個不稱職的程序員究竟在幹了什麼!!!
咱們能夠寫一個小程序來取得和處理數據而且更新數據庫,這樣作有時會更有效。記住:對於循環,T-SQL無能爲力。
我再從新提醒一下:使用遊標沒有好處。除了DBA的工做外,我歷來沒有看到過使用遊標能夠有效的完成任何工做。 安全
3、規範化你的數據表 性能優化
爲何不規範化數據庫?大概有兩個藉口:出於性能的考慮和純粹由於懶惰。至於第二點,你早晚得爲此付出代價。而關於性能的問題,你不須要優化根本就不慢的東西。我常常看到一些程序員「反規範化」數據庫,他們的理由是「原來的設計太慢了」,可結果卻經常是他們讓系統更慢了。DBMS被設計用來處理規範數據庫 的,所以,記住:按照規範化的要求設計數據庫。 服務器
4、不要使用SELECT * 網絡
這點不太容易作到,我太瞭解了,由於我本身就常常這樣幹。但是,若是在SELECT中指定你所須要的列,那將會帶來如下的好處:
1 減小內存耗費和網絡的帶寬
2 你能夠獲得更安全的設計
3 給查詢優化器機會從索引讀取全部須要的列 工具
5、瞭解你將要對數據進行的操做 性能
爲你的數據庫建立一個健壯的索引,那但是功德一件。可要作到這一點簡直就是一門藝術。每當你爲一個表添加一個索引,SELECT會更快了,可INSERT 和DELETE卻大大的變慢了,由於建立了維護索引須要許多額外的工做。顯然,這裏問題的關鍵是:你要對這張表進行什麼樣的操做。這個問題不太好把握,特別是涉及DELETE和UPDATE時,由於這些語句常常在WHERE部分包含SELECT命令。
6、不要給「性別」列建立索引
首先,咱們必須瞭解索引是如何加速對錶的訪問的。你能夠將索引理解爲基於必定的標準上對錶進行劃分的一種方式。若是你給相似於「性別」這樣的列建立了一個 索引,你僅僅是將表劃分爲兩部分:男和女。你在處理一個有1,000,000條記錄的表,這樣的劃分有什麼意義?記住:維護索引是比較費時的。當你設計索 引時,請遵循這樣的規則:根據列可能包含不一樣內容的數目從多到少排列,好比:姓名+省份+性別。
7、使用事務
請使用事務,特別是當查詢比較耗時。若是系統出現問題,這樣作會救你一命的。通常有些經驗的程序員都有體會-----你常常會碰到一些不可預料的狀況會致使存儲過程崩潰。
8、當心死鎖
按照必定的次序來訪問你的表。若是你先鎖住表A,再鎖住表B,那麼在全部的存儲過程當中都要按照這個順序來鎖定它們。若是你(不經意的)某個存儲過程當中先鎖定表B,再鎖定表A,這可能就會致使一個死鎖。若是鎖定順序沒有被預先詳細的設計好,死鎖是不太容易被發現的。
9、不要打開大的數據集
一個常常被提出的問題是:我怎樣才能迅速的將100000條記錄添加到ComboBox中?這是不對的,你不能也不須要這樣作。很簡單,你的用戶要瀏覽 100000條記錄才能找到須要的記錄,他必定會詛咒你的。在這裏,你須要的是一個更好的UI,你須要爲你的用戶顯示不超過100或200條記錄。
10、不要使用服務器端遊標
與服務器端遊標比起來,客戶端遊標能夠減小服務器和網絡的系統開銷,而且還減小鎖定時間。
11、使用參數查詢
有時,我在CSDN技術論壇看到相似這樣的問題:「SELECT * FROM a WHERE a.id='A'B,由於單引號查詢發生異常,我該怎麼辦?」,而廣泛的回答是:用兩個單引號代替單引號。這是錯誤的。這樣治標不治本,由於你還會在其餘一些字符上遇到這樣的問題,更況且這樣會致使嚴重的bug,除此之外,這樣作還會使SQL Server的緩衝系統沒法發揮應有的做用。使用參數查詢,釜底抽薪,這些問題通通不存在了。
12、在程序編碼時使用大數據量的數據庫
程序員在開發中使用的測試數據庫通常數據量都不大,可常常的是最終用戶的數據量都很大。咱們一般的作法是不對的,緣由很簡單:如今硬盤不是很貴,可爲何性能問題卻要等到已經無可挽回的時候才被注意呢?
十3、不要使用INSERT導入大批的數據
請不要這樣作,除非那是必須的。使用UTS或者BCP,這樣你能夠一舉而兼得靈活性和速度。
十4、注意超時問題
查詢數據庫時,通常數據庫的缺省都比較小,好比15秒或者30秒。而有些查詢運行時間要比這長,特別是當數據庫的數據量不斷變大時。
十5、不要忽略同時修改同一記錄的問題
有時候,兩個用戶會同時修改同一記錄,這樣,後一個修改者修改了前一個修改者的操做,某些更新就會丟失。處理這種狀況不是很難:建立一個timestamp字段,在寫入前檢查它,若是容許,就合併修改,若是存在衝突,提示用戶。
十6、在細節表中插入紀錄時,不要在主表執行SELECT MAX(ID)
這是一個廣泛的錯誤,當兩個用戶在同一時間插入數據時,這會致使錯誤。你可使用SCOPE_IDENTITY,IDENT_CURRENT和IDENTITY。若是可能,不要使用IDENTITY,由於在有觸發器的狀況下,它會引發一些問題(詳見這裏的討論)。
十7、避免將列設爲NULLable
若是可能的話,你應該避免將列設爲NULLable。系統會爲NULLable列的每一行分配一個額外的字節,查詢時會帶來更多的系統開銷。另外,將列設爲NULLable使編碼變得複雜,由於每一次訪問這些列時都必須先進行檢查。
我並非說NULLS是麻煩的根源,儘管有些人這樣認爲。我認爲若是你的業務規則中容許「空數據」,那麼,將列設爲NULLable有時會發揮很好的做用,可是,若是在相似下面的狀況中使用NULLable,那簡直就是自討苦吃。
CustomerName1
CustomerAddress1
CustomerEmail1
CustomerName2
CustomerAddress2
CustomerEmail3
CustomerName1
CustomerAddress2
CustomerEmail3
若是出現這種狀況,你須要規範化你的表了。
十8、儘可能不要使用TEXT數據類型
除非你使用TEXT處理一個很大的數據,不然不要使用它。由於它不易於查詢,速度慢,用的很差還會浪費大量的空間。通常的,VARCHAR能夠更好的處理你的數據。
十9、儘可能不要使用臨時表
儘可能不要使用臨時表,除非你必須這樣作。通常使用子查詢能夠代替臨時表。使用臨時表會帶來系統開銷,若是你是用COM+進行編程,它還會給你帶來很大的麻 煩,由於COM+使用數據庫鏈接池而臨時表卻自始至終都存在。SQL Server提供了一些替代方案,好比Table數據類型。
二10、學會分析查詢
SQL Server查詢分析器是你的好夥伴,經過它你能夠了解查詢和索引是如何影響性能的。
二11、使用參照完整性
定義主健、惟一性約束和外鍵,這樣作能夠節約大量的時間。