作為一個.NET開發者,我們經常會發現自己置身於SQL Server查詢和存儲過程當中,一個很好的例子就是我最近開發的一個ASP.Net應用軟件。
該軟件已經開發完成並交付用戶進行測試,這個軟件使用了一個先有的SQL Server數據庫,大部分T-SQL已經包含在預先定義的存儲過程中了(也就是說,我並沒有編寫它們),當我把軟件提交給用戶的時候,他們向我抱怨了性能問題。瓶頸源於數據庫層,所以我花費了大量的時間來調整T-SQL以提升性能。
在這篇文章中,我將和您共享一些在項目中發現的技巧,我使用的是SQL Server,不過很多項目對所有的數據庫平台都是適用的。
難以避免
盡管大部分企業都擁有數據庫管理員和開發人員,但是很難避免對SQL Server的開發,這是開發管理的迷題之一,很多數據庫開發人員告訴我因為我知道軟件的需求,所以由我來編寫查詢,盡管這種邏輯很難爭辯,但是要想精通T-SQL確實非常困難,而同時作為開發者還要學習.Net平台的多個層面。但是,基本的T-SQL語言還是具有一致性的,因此,讓我們來看看如何編寫高效的數據庫代碼。
優化要點
和編寫任何程序代碼一樣,構建T-SQL查詢的方法也不止一種,以下是提升性能的一些指導方針。
WHERE語句
您應當適用WHERE語句來控制返回的數據行的數量,如果不使用WHERE語句,SQL Server會執行對整個表格進行掃描並返回所有的行(如果確實需要這樣做,您可以不必適用WHERE語句,但是所有其他的情況下都要使用WHERE語句。)
您應當使用WHERE語句來支持HAVING語句,當您將GROUP BY和HAVING語句一起使用的時候,GROUP BY會將數據行分為不同的組並聚合它們的值,然後HAVING語句會剔除不需要的組。在有些情況下,您可以編寫只包含WHERE和GROUP BY的語句而不需要HAVING語句。
數據列
使用星號(*)可以在查詢中很容易地返回所有數據列的值,您應當只獲取必需的數據行。結果集合中的數據列越少,數據量就會越少,這樣網絡流量的負擔就會減小。性能的提升依賴於數據列的數量,所以對數據列進行限定是一種良好的習慣。
避免指針
SQL Server的指針功能可以在掃描結果中進行循環,但是這一功能的代價就是性能。指針功能對於每夜的服務器任務來講是不錯的,但是要在您的應用軟件的代碼/過程中避免使用指針。最好使用選擇語句來返回需要的值並在客戶端處理這些數據。
作為一個.NET開發者,我們經常會發現自己置身於SQL Server查詢和存儲過程當中,一個很好的例子就是我最近開發的一個ASP.Net應用軟件。
該軟件已經開發完成並交付用戶進行測試,這個軟件使用了一個先有的SQL Server數據庫,大部分T-SQL已經包含在預先定義的存儲過程中了(也就是說,我並沒有編寫它們),當我把軟件提交給用戶的時候,他們向我抱怨了性能問題。瓶頸源於數據庫層,所以我花費了大量的時間來調整T-SQL以提升性能。
在這篇文章中,我將和您共享一些在項目中發現的技巧,我使用的是SQL Server,不過很多項目對所有的數據庫平台都是適用的。
難以避免
盡管大部分企業都擁有數據庫管理員和開發人員,但是很難避免對SQL Server的開發,這是開發管理的迷題之一,很多數據庫開發人員告訴我因為我知道軟件的需求,所以由我來編寫查詢,盡管這種邏輯很難爭辯,但是要想精通T-SQL確實非常困難,而同時作為開發者還要學習.Net平台的多個層面。但是,基本的T-SQL語言還是具有一致性的,因此,讓我們來看看如何編寫高效的數據庫代碼。
優化要點
和編寫任何程序代碼一樣,構建T-SQL查詢的方法也不止一種,以下是提升性能的一些指導方針。
WHERE語句
您應當適用WHERE語句來控制返回的數據行的數量,如果不使用WHERE語句,SQL Server會執行對整個表格進行掃描並返回所有的行(如果確實需要這樣做,您可以不必適用WHERE語句,但是所有其他的情況下都要使用WHERE語句。)
您應當使用WHERE語句來支持HAVING語句,當您將GROUP BY和HAVING語句一起使用的時候,GROUP BY會將數據行分為不同的組並聚合它們的值,然後HAVING語句會剔除不需要的組。在有些情況下,您可以編寫只包含WHERE和GROUP BY的語句而不需要HAVING語句。
數據列
使用星號(*)可以在查詢中很容易地返回所有數據列的值,您應當只獲取必需的數據行。結果集合中的數據列越少,數據量就會越少,這樣網絡流量的負擔就會減小。性能的提升依賴於數據列的數量,所以對數據列進行限定是一種良好的習慣。
避免指針
SQL Server的指針功能可以在掃描結果中進行循環,但是這一功能的代價就是性能。指針功能對於每夜的服務器任務來講是不錯的,但是要在您的應用軟件的代碼/過程中避免使用指針。最好使用選擇語句來返回需要的值並在客戶端處理這些數據。
有多少行?
T-SQL的COUNT函數可以在查詢中返回項目的數量,但是使用這個函數的時候可以指定一個數據列,從而提高性能,原因在於SELECT COUNT(*)在表格中執行了一個全表格的掃描然後返回總數。
您可以在函數調用中指定一個數據列,如果只需要計算表格有多少數據行,您可以使用sysindexes表格(不必使用WHERE語句),在sysindexes表格中有一個名為ROWS的數據列,它包含了數據庫中所有表格的行數,以下的代碼可以返回指定表格的數據行數量:
SELECT rows FROM sysindexes WHERE id = OBJECT_ID('table_name') AND indid < 2
唯一值
很多開發者喜歡在查詢中使用DISTINCT選項,它允許您返回唯一的數據行數值,絕無重復,但是問題在於它降低了性能,所以您應當在絕對需要的情況下使用它。
返回一部分數據行
您可能只需要一個查詢的子集,無論查詢可以返回的總數有多少,TOP操作符都可以幫您指定需要返回的項目的具體數字或者百分比,以下的查詢返回了10個項目:
SELECT TOP 10 CustomerID FROM Northwind.dbo.Orders WHERE Freight < 50.0
或者,您可以在總結果中返回一定的百分比:
SELECT TOP 5 percent CustomerID FROM Northwind.dbo.Orders WHERE Freight < 50.0
避免哪些代碼
您應當避免沒有任何功能的代碼,這聽上去像是廢話,但是我確實碰到了無數的含有不執行任何功能代碼的存儲過程,這可能是由於存儲過程的版本變化而遺留下來的,但是您應當刪除掉這些不需要的代碼,或者您可以將它們變為注釋,這樣可以避免任何性能上的損失。
使用數據庫服務器
您應當充分利用服務器平台的優勢使用存儲過程而不是在您的客戶端代碼中使用T-SQL,因為存儲過程是經過服務器平台優化過的,所以應該一直使用存儲過程以確保代碼運行的效率,此外,視圖功能也應當用來替換大規模的查詢從而提高性能。
索引是您的朋友
如果正確使用索引可以提高查詢的性能,如何創建索引已經超出了本文的范圍,但是有大量的資源提供了相關的信息。此外,SQL Server還提供了SQL Profiler工具來定位性能的瓶頸。
前路漫漫
即使您的.Net代碼通過了測試,一切也都按照計劃實現了功能,但是依然有很多數據庫端的工作要做,您可以通過多種方式來解決查詢的性能問題,我希望本文所介紹的方法為您提供了一個起點。另外,您還可以使用SQL Server的工具來識別查詢相關的問題。請在文章的討論區共享您在優化查詢性能方面的經驗。