最近讀了程序員的SQL金典這本書,以爲裏面的SQL注入漏洞和SQL調優總結得不錯,下面簡單討論下SQL注入漏洞和SQL調優。程序員
因爲「'1'='1'」這個表達式永遠返回 true,而 true 與任何布爾值的 or 運算的結果都是 true,那麼不管正確密碼是什麼「Password='1' or '1'='1'」的計算值永遠是 true,這樣惡意攻擊者就可使用任何賬戶登陸系統了。這樣的漏洞就被稱做「SQL 注入漏洞(SQL Injection)」。數據庫
對付 SQL 注入漏洞有兩種方式:過濾敏感字符和使用參數化 SQL。 服務器
1).過濾敏感字符網絡
過濾敏感字符的思路很是簡單,因爲惡意攻擊者通常須要在輸入框中輸入的文本通常含有 or、and、select、delete 之類的字符串片斷,因此在拼接 SQL 以前檢查用戶提交的文本中是否含有這些敏感字符串,若是含有則終止操做。函數
2).使用參數化SQL性能
爲運行時才能肯定的用戶名和密碼設置了佔位符,而後在運行時再設定佔位符的值,在執行時 Java、C#會直接將參數化 SQL 以及對應的參數值傳遞給 DBMS,在 DBMS 中會將參數值當成一個普通的值來處理而不是將它們拼接到參數化 SQL 中,所以從根本上避免了 SQL 注入漏洞攻擊。優化
在使用 DBMS 時常常對系統的性能有很是高的要求:不能佔用過多的系統內存和CPU 資源、要儘量快的完成的數據庫操做、要有儘量高的系統吞吐量。若是系統開發出來不能知足要求的全部性能指標,則必須對系統進行調整,這個工做被稱爲調優。spa
SQL 調優的基本原則 排序
「二八原理」是一個廣泛的真理,特別是在計算機的世界中表現的更加明顯,那就是 20%的代碼的資源消耗佔用了 80%的總資源消耗。SQL 語句也是一種代碼,所以它也符合這個原理。在進行 SQL 調優的時候應該把主要精力放到這 20%的最消耗系統資源的 SQL 語句中,不要想把全部的 SQL 語句都調整到最優狀態。 索引
索引是數據庫調優的最根本的優化方法。
經常使用的SQL調優方法:
1) 建立必要的索引
2) 使用預編譯查詢
程序中一般是根據用戶的輸入來動態執行 SQL 語句,這時應該儘可能使用參數化SQL,這樣不只能夠避免 SQL 注入漏洞攻擊,最重要數據庫會對這些參數化 SQL 執行預編譯。
3) 調整 WHERE 子句中的鏈接順序
DBMS 通常採用自下而上的順序解析 WHERE 子句,根據這個原理,錶鏈接最好寫在其餘 WHERE 條件以前,那些能夠過濾掉最大數量記錄。
好比下面的 SQL 語句性能較差: SELECT * FROM T_Person WHERE FSalary > 50000 AND FPosition= ‘MANAGER’ AND 25 < (SELECT COUNT(*) FROM T_Manager WHERE FManagerId=2);
咱們將子查詢的條件放到最前面,下面的 SQL 語句性能比較好: SELECT * FROM T_Person WHERE 25 < (SELECT COUNT(*) FROM T_Manager WHERE FManagerId=2) AND FSalary > 50000 AND FPosition= ‘MANAGER’ ;
4) SELECT 語句中避免使用'*'
SELECT *比較簡單,可是除非確實須要檢索全部的列,不然將會檢索出不須要的列,這回增長網絡的負載和服務器的資源消耗;即便確實須要檢索全部列,也不要使用SELECT *,由於這是一個很是低效的方法,DBMS 在解析的過程當中,會將*依次轉換成全部的列名,這意味着將耗費更多的時間。
5) 儘可能將多條 SQL 語句壓縮到一句 SQL 中
每次執行 SQL 的時候都要創建網絡鏈接、進行權限校驗、進行 SQL 語句的查詢優化、發送執行結果,這個過程是很是耗時的,所以應該儘可能避免過多的執行 SQL 語句,可以壓縮到一句 SQL 執行的語句就不要用多條來執行。
6) 用 Where 子句替換 HAVING 子句
避免使用 HAVING 子句,由於 HAVING 只會在檢索出全部記錄以後纔對結果集進行過濾。若是能經過 WHERE 子句限制記錄的數目,那就能減小這方面的開銷。HAVING 中的條件通常用於聚合函數的過濾,除此而外,應該將條件寫在 WHERE 子句中。
7) 使用表的別名
當在 SQL 語句中鏈接多個表時,請使用表的別名並把別名前綴於每一個列名上。這樣就能夠減小解析的時間並減小那些由列名歧義引發的語法錯誤。
8) 用 EXISTS 替代 IN
在查詢中,爲了知足一個條件,每每須要對另外一個表進行聯接,在這種狀況下,使用 EXISTS 而不是 IN 一般將提升查詢的效率,由於 IN 子句將執行一個子查詢內部的排序和合並。
9) 用錶鏈接替換 EXISTS
一般來講,錶鏈接的方式比 EXISTS 更有效率,所以若是可能的話儘可能使用錶鏈接替換 EXISTS。
10) 避免在索引列上使用計算
在 WHERE 子句中,若是索引列是計算或者函數的一部分,DBMS 的優化器將不會使用索引而使用全表掃描。
11) 用 UNION ALL 替換 UNION
當 SQL 語句須要 UNION 兩個查詢結果集合時,即便檢索結果中不會有重複的記錄,若是使用 UNION 這兩個結果集一樣會嘗試進行合併,而後在輸出最終結果前進行排序。 所以,若是檢索結果中不會有重複的記錄的話,應該用 UNION ALL 替代 UNION,這樣效率就會所以獲得提升。
12) 避免隱式類型轉換形成的全表掃描
13) 防止檢索範圍過寬
若是 DBMS 優化器認爲檢索範圍過寬,那麼它將放棄索引查找而使用全表掃描。下面是幾種可能形成檢索範圍過寬的狀況: 使用 IS NOT NULL 或者不等於判斷,可能形成優化器假設匹配的記錄數太多。 使用 LIKE 運算符的時候,"a%"將會使用索引,而"a%c"和"%c"則會使用全表掃描,所以"a%c"和"%c"不能被有效的評估匹配的數量。
若是您有什麼問題,歡迎在下面評論,咱們一塊兒討論,謝謝~
若是您以爲還不錯,不妨點下右下方的推薦,有您的鼓勵我會繼續努力的~