摘 要
在針對數據庫操作的應用程序設計中,SQL語句的編寫也會影響到程序響應速度和用戶的體驗度,尤其是數據量較大的應用。本文通過對SQL語句的執行順序進行分析,探討和分析提高SQL語句效率的方法以及SQL語句的優化方式。
【關鍵詞】SQL語句 執行效率 方法
隨著計算機技術的發展,各種各樣的應用軟件進入到我們的生活中。大多數軟件在與用戶交互時都會進行數據的查詢、存儲等操作。科學合理的數據庫查詢語句可以提高數據庫的查詢性能,隨之將會提高軟件的響應速度和用戶體驗度,在數據庫應用系統中起著關鍵的作用。
1 SQL語句
SQL語句是STRUCTURED QUERY LAN -GUAGE的縮寫,即結構化查詢語言。在1986年10月通過了美國國家標準局的數據庫語言美國標準,經過多年的擴展和標準化,在各種不同的數據庫中已經基本達到通用。可以獨立于數據庫和計算機軟硬件。
我們這里討論的是結構化查詢語言的一部分,叫做數據查詢語句(Data Query Language)。數據查詢語句也稱為數據檢索語句,用以從數據庫表中獲得需要的數據,返回給應用程序。數據查詢語句中最常用的保留字是SELECT,其他的還有WHERE,ORDER BY,GROUP BY和HAVING。這些DQL保留字與其他類型的SQL語句一起使用。比如:
SELECT id,name,age,address FROM students WHERE name=rose ORDER BY age
這條查詢語句的意思是:從students學生表中查詢出所有名叫rose的的學生,并且返回的結果集按照age年齡字段順序排列。
2 SQL語句的效率
SQL作為查詢語言有靈活的編寫方式,語句的寫法完全取決于編寫者。當數據庫收到一個查詢語句時,首先完成語法解釋,然后再進行編譯,生成可以執行的“執行計劃(execution plan)”。在語句編譯過程中,數據庫會根據指令內容和估算可能的執行計劃,再根據每個計劃的運行成本選擇一個數據庫認為成本最低的計劃執行。數據庫會把這些執行計劃緩存在內存中,被稱作執行緩存(plan cache)。以后遇到同樣的語句時,數據庫就可以使用同樣的執行計劃,而不用再次編譯。
程序員在編寫SQL語句時往往會陷入一種誤區,那就是關注與SQL語句的執行結果而忽略了不同實現方法之間存在的性能的差異。對于相同的數據庫結構來說,執行計劃的成本消耗,完全取決于SQL語句的編寫方式。這種實現方式的差異在大行或復雜的數據庫中表現的更為明顯。
經過實踐發現,執行成本較高的SQL語句除了數據庫設計不合理以外,不恰當的連接語句和不可優化的條件語句也是其中的主要原因。比如一條包含子查詢的語句:
SELECT dd FROM A WHERE aa IN (SELECT aa FROM B)
在連接子查詢中,效率的高低與使用IN還是用EXISTS有關。EXISTS會針對子查詢表使用索引功能,IN會針對主表動用索引功能。可以確定,當主表數據量大時采用IN效率高,當子查詢數據量大是采用EXISTS效率高。因此,SQL語句的執行效率和編寫方法有直接關系。
下面簡單說一下SQL語句的執行順序:
FROM子句標識了需要查詢的表,如果指定了表操作,會從左到右的處理,每一個基于一個或者兩個表的表操作都會返回一個輸出表。左邊表的輸出結果會作為下一個表操作的輸入結果。
對于外連接(LEFT,RIGHT, or FULL),可以標記一個或者兩個表作為保留表。作為保留表意味著這個表里面的所有列都被返回,即使它里面的數據不滿足ON子句的過濾條件。 LEFT OUTER JOIN 把左邊的表標記為保留表,RIGHT OUTER JOIN把右邊的表作為保留表,FULL OUTER JOIN把兩個表都標記為保留表。
WHERE過濾被應用到前一步生成的臨時表中,根據WHERE過濾條件生成臨時表。關于ON 和 WHERE 的區別需要在這里說明一下,ON 和WHERE 的主要區別在于 ON 是在添加外部列之前進行過濾,WHERE 是在之后,如果你不需要添加外部列,那么這兩個過濾是相同的。
3 提高SQL語句效率的方法
為了提升SQL語句的執行效率,可以采用以下辦法實現:
(1)在表中建立索引,在數據庫中使用索引能夠大大提高檢索性能,這一點是非常明顯的。用的索引越多,從數據庫系統中得到數據的速度就越快。盡量在查詢中明確需要的字段,減少使用類似于“SELECT name FROM TABLE1”這種查詢語句。
(2)同時還需要注意一點就是要有效使用索引,并不是越多越好。索引固然可以提高查詢的效率,但同時也降低了插入和更新語句的效率,因為在數據插入或更新時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。
(3)在WHERE子句中盡量避免使用“!=、<、>”等操作符號,否則數據庫會進行全表檢索。因為SQL只有在運行時才會解析局部變量,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然而,如果在編譯時建立訪問計劃,變量的值還是未知的,因而無法作為索引選擇的輸入項。比如:
SELECT name FROM TABLE1 WHERE ID=‘1
可以改為強制使用索引方式
SELECT name FROM TABLE1 WITH(INDEX(索引名)) WHERE ID=‘1
(4)如果有NOT IN、NOT EXISTS的子查詢可以用LEFT JOIN代替。使用前者時,數據庫會逐條對比,對比數量等于笛卡爾積,而使用LEFT JOIN會大大減少數據庫的工作量。endprint
(5)在數據庫檢索時,盡量使用數字型字段作為條件,這將大大提高查詢和連接的性能,減少存儲開銷。這是因為引擎在處理查詢和連接時會逐個比較字符串中每一個字符,而對于數字型而言只需要比較一次就夠了。
(6)盡量不要對索引字段進行運算或格式化等操作,比如:
SELECT ID FROM TWHERE NUM/2=100
應該改為
SELECT ID FROM TWHERE NUM=100*2
(7)在使用IN的時候,后面值的列表中,將出現最頻繁的值放在最前面,出現得最少的放在最后面,這樣可以減少判斷的次數。
(8)HAVING、WHERE和ON這三個都可以加在條件子句中,在使用的時候需要注意一下它們的執行順序,ON是在查詢中最先執行的語句,接著是WHERE,HAVING最后被執行。在正常情況下,這三個條件的先后順序不會影響到最終的查詢結果。但從效率方面考慮,ON應該是最快的,ON是先把不符合條件的記錄過濾后才進行統計,它就可以減少中間運算要處理的數據。接著是WHERE,它會比HAVING快點的,因為它過濾數據后才進行求和運算,HAVING相比之下是最慢的。
單表查詢統計的情況下,如果查詢條件中沒有涉及到需要計算字段,那么HAVING和WHERE的查詢結果是一樣的。但是如果查詢結果涉及到計算的字段以后,那就表明在還沒有計算之前,這個字段的值是不能確定的,而HAVING正是在計算后才起作用,主要是用來彌補WHERE在分組數據判斷時的不足[3]。比如:
SELECT class,SUM(studentNO) FROM students GROUP BY class HAVING SUM(studentNO)>60
這條語句是查詢出人數大于60人的班級,在這里我們就不能用WHERE來替換HAVING,因為WHERE的作用時間是在計算之前就完成的,而計算之前的表中就不存在符合條件的記錄,那么就只能用HAVING來進行篩選。
在多表聯接查詢時ON比WHERE更早起作用,這是因為系統首先根據各個表之間的聯接條件,把多個表合成一個臨時表后,再由WHERE進行過濾,然后再計算,計算完后再由HAVING進行過濾。由此可見,要想過濾條件起到正確的作用,首先要明白這個條件應該在什么時候起作用,然后再決定放在那里。
4 結語
總之,通過對數據庫編譯順序的學習可以了解相似的保留字編譯成執行代碼的差異,用以指導SQL語句的實現方式,提高語句執行效率。但是對于大型數據庫來說,要實現良好的性能還需要在設計和實現上使用更多的技巧和優化。
參考文獻
[1]錢文波,謝金寶.SQL Server數據庫性能優化技術[J].微型機與應用,1999.
[2]吳險峰.SQLServer環境下的SQL優化方法探討[J].電腦知識與技術,2008.
[3]李海翔.數據庫查詢優化器的藝術:原理解析與SQL性能優化[M].北京:機械工業出版社,2014.
作者簡介
董非(1981-),男,湖北省十堰市人。碩士學位。現供職于陜西瑞珂工程咨詢有限責任公司。中級職稱。研究方向為計算機技術。
作者單位
陜西瑞珂工程咨詢有限責任公司 陜西省西安市 710065endprint