天天看點

[SQL SERVER系列]讀書筆記之SQL注入漏洞和SQL調優

對付 SQL 注入漏洞有兩種方式:過濾敏感字元和使用參數化 SQL。SQL 調優的基本原則:“二八原理”是一個普遍的真理,特别是在計算機的世界中表現的更加明顯,那就是 20%的代碼的資源消耗占用了 80%的總資源消耗。SQL 語句也是一種代碼,是以它也符合這個原理。在進行 SQL 調優的時候應該把主要精力放到這 20%的最消耗系統資源的 SQL 語句中,不要想把所有的 SQL 語句都調整到最優狀态。

  最近讀了程式員的SQL金典這本書,覺得裡面的SQL注入漏洞和SQL調優總結得不錯,下面簡單讨論下SQL注入漏洞和SQL調優。

1. 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 注入漏洞攻擊。

2. SQL 調優 

  在使用 DBMS 時經常對系統的性能有非常高的要求:不能占用過多的系統記憶體和CPU 資源、要盡可能快的完成的資料庫操作、要有盡可能高的系統吞吐量。如果系統開發出來不能滿足要求的所有性能名額,則必須對系統進行調整,這個工作被稱為調優。

  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"不能被有效的評估比對的數量。 

  

  如果您有什麼問題,歡迎在下面評論,我們一起讨論,謝謝~

  如果您覺得還不錯,不妨點下右下方的推薦,有您的鼓勵我會繼續努力的~