如何提高數據庫查詢速度



轉載自:http://blog.csdn.net/screensky/article/details/7845256

1、用程序中,
保證在實現功能的基礎上,儘量減少對數據庫的訪問次數;
通過搜索參數,儘量減少對錶的訪問行數,最小化結果集,從而減輕網絡負擔;
能夠分開的操作儘量分開處理,提高每次的響應速度;
在數據窗口使用SQL時,儘量把使用的索引放在選擇的首列;
算法的結構儘量簡單;
在查詢時,不要過多地使用通配符如SELECT * FROM T1語句,要用到幾列就選擇幾列如:SELECT COL1,COL2 FROM T1;
在可能的情況下儘量限制儘量結果集行數如:SELECT TOP 300 COL1,COL2,COL3 FROM T1,因爲某些情況下用戶是不需要那麼多的數據的。
不要在應用中使用數據庫遊標,遊標是非常有用的工具,但比使用常規的、面向集的SQL語句需要更大的開銷;
按照特定順序提取數據的查找。

 

2、避免使用不兼容的數據類型。例如float和int、char和varchar、binary和varbinary是不兼容的。
數據類型的不兼容可能使優化器無法執行一些本來可以進行的優化操作。例如:
SELECT name FROM employee WHERE salary > 60000
在這條語句中,如salary字段是money型的,則優化器很難對其進行優化,因爲60000是個整型數。
我們應當在編程時將整型轉化成爲錢幣型,而不要等到運行時轉化。

 

3、儘量避免在WHERE子句中對字段進行函數或表達式操作,這將導致引擎放棄使用索引而進行全表掃描。如:
SELECT * FROM T1 WHERE F1/2=100
應改爲:
SELECT * FROM T1 WHERE F1=100*2

SELECT * FROM RECORD WHERE SUBSTRING(CARD_NO,1,4)=’5378’
應改爲:
SELECT * FROM RECORD WHERE CARD_NO LIKE ‘5378%’

SELECT member_number, first_name, last_name   FROM members
WHERE DATEDIFF(yy,datofbirth,GETDATE()) > 21
應改爲:
SELECT member_number, first_name, last_name   FROM members
WHERE dateofbirth < DATEADD(yy,-21,GETDATE())
即:任何對列的操作都將導致表掃描,它包括數據庫函數、計算表達式等等,查詢時要儘可能將操作移至等號右邊。

 

4、避免使用!=或<>、IS NULL或IS NOT NULL、IN ,NOT IN等這樣的操作符,
因爲這會使系統無法使用索引,而只能直接搜索表中的數據。例如:
SELECT id FROM employee WHERE id != 'B%'
優化器將無法通過索引來確定將要命中的行數,因此需要搜索該表的所有行。

 

5、儘量使用數字型字段,一部分開發人員和數據庫管理人員喜歡把包含數值信息的字段設計爲字符型,
這會降低查詢和連接的性能,並會增加存儲開銷。
這是因爲引擎在處理查詢和連接回逐個比較字符串中每一個字符,而對於數字型而言只需要比較一次就夠了。

 

6、合理使用EXISTS,NOT EXISTS子句。如下所示:
1.SELECT SUM(T1.C1)FROM T1 WHERE(
(SELECT COUNT(*)FROM T2 WHERE T2.C2=T1.C2>0)
2.SELECT SUM(T1.C1) FROM T1WHERE EXISTS(
   SELECT * FROM T2 WHERE T2.C2=T1.C2)
兩者產生相同的結果,但是後者的效率顯然要高於前者。因爲後者不會產生大量鎖定的表掃描或是索引掃描。
如果你想校驗表裏是否存在某條紀錄,不要用count(*)那樣效率很低,而且浪費服務器資源。可以用EXISTS代替。如:
IF (SELECT COUNT(*) FROM table_name WHERE column_name = 'xxx')
可以寫成:
IF EXISTS (SELECT * FROM table_name WHERE column_name = 'xxx')

經常需要寫一個T_SQL語句比較一個父結果集和子結果集,從而找到是否存在在父結果集中有而在子結果集中沒有的記錄,如:
1.SELECT a.hdr_key   FROM hdr_tbl a---- tbl a 表示tbl用別名a代替
WHERE NOT EXISTS (SELECT * FROM dtl_tbl b WHERE a.hdr_key = b.hdr_key)

2.SELECT a.hdr_key   FROM hdr_tbl a
LEFT JOIN dtl_tbl b ON a.hdr_key = b.hdr_key   WHERE b.hdr_key IS NULL

3.SELECT hdr_key   FROM hdr_tbl
WHERE hdr_key NOT IN (SELECT hdr_key FROM dtl_tbl)
三種寫法都可以得到同樣正確的結果,但是效率依次降低。

 

7、儘量避免在索引過的字符數據中,使用非打頭字母搜索。這也使得引擎無法利用索引。 
見如下例子:
SELECT * FROM T1 WHERE NAME LIKE ‘%L%’
SELECT * FROM T1 WHERE SUBSTING(NAME,2,1)=’L’
SELECT * FROM T1 WHERE NAME LIKE ‘L%’
即使NAME字段建有索引,前兩個查詢依然無法利用索引完成加快操作,引擎不得不對全表所有數據逐條操作來完成任務。
而第三個查詢能夠使用索引來加快操作。

 

8、充分利用連接條件,在某種情況下,兩個表之間可能不只一個的連接條件,
這時在   WHERE 子句中將連接條件完整的寫上,有可能大大提高查詢速度。例:
SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO
SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO   AND A.ACCOUNT_NO=B.ACCOUNT_NO
第二句將比第一句執行快得多。

 

9、消除對大型錶行數據的順序存取,儘管在所有的檢查列上都有索引,但某些形式的WHERE子句強迫優化器使用順序存取。如:
SELECT * FROM orders WHERE (customer_num=104   AND order_num>1001) OR order_num=1008
解決辦法可以使用並集來避免順序存取:
SELECT * FROM orders WHERE customer_num=104 AND order_num>1001
UNION
SELECT * FROM orders WHERE order_num=1008
這樣就能利用索引路徑處理查詢。

 

10、避免困難的正規表達式。LIKE關鍵字支持通配符匹配技術

附加項:

1.索引優化  
  建索引的選擇必須結合SQL查詢、修改、刪除語句的需要,一般的說法是在WHERE裏經常出現的字段建索引。如果在WHERE經常是幾個字段一起出現而且是用AND連接的,那就應該建這幾個字段一起的聯合索引,而且次序也需要考慮,一般是最常出現的放前面,重複率低的放前面。    
  SQL   Server提供了一種簡化並自動維護數據庫的工具。這個稱之爲數據庫維護計劃嚮導(Database   Maintenance   Plan   Wizard   ,DMPW)的工具也包括了對索引的優化。如果你運行這個嚮導,你會看到關於數據庫中關於索引的統計量,這些統計量作爲日誌工作並定時更新,這樣就減輕了手工重建索引或者DBCC   INDEXDEFRAG所帶來的工作量。如果你不想自動定期刷新索引統計量,你還可以在DMPW中選擇重新組織數據和數據頁,這將停止舊有索引並按特定的填充因子重建索引。  
  2.  
  改善硬件(雙CPU,Raid   5,增加內存)  
  tempdb這個臨時數據庫,它對性能的影響較大。tempdb和其他數據庫一樣可以增大,可以縮小。當數據文件需要增長的時候,通常不能保持剩餘部分的連續性。這時文件就會產生碎片,這種碎片會造成性能下降。這種碎片屬於外來性碎片。要阻止在tempdb中產生外來性碎片,必須保證有足夠的硬盤空間。一般將tempdb的容量放到平均使用容量。而你也應該允許tempdb自動增長,比如你有個一個超大的join操作,它建立了一個超過tempdb容量的時候,該查詢將失敗。你還要設置一個合理的單位增長量。因爲如果你設得太小,將會產生許多外來性碎片,反而會佔用更多資源。sqlserver調優最有效的做法之一,就是把爭奪資源的操作獨立出去。tempdb就是一個需要獨立出去的部分而tempdb和其他系統庫一樣是公用的,是存取最可能頻繁的庫,所有處理臨時表、子查詢、GROUP   BY、排序、DISTINCT、連接等等。它最適合放到一個具有快速讀寫能力的設備上。比如RAID0卷或RAID0+1捲上。  
  查詢語句一定要使用存儲過程;  
  3、查詢儘量使用TOP子句  
  4.將表按一定的約束分成子表,(如按分類)創建約束,在用Like   時,先用分類   and   like   ,   應該可能解決問題.   而且效果立稈見影!(你要確定SQL會認識你建的分區視圖).我一個表有上百萬的記錄(700兆),用分區視圖後,查詢速度基本跟10萬行一樣. 


發佈了58 篇原創文章 · 獲贊 22 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章