java面試(3)SQL優化

  1. 對查詢進行優化,要儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。任何在Order by語句的非索引項或者有計算表達式都將降低查詢速度

  2. 應儘量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如select id from t where num is null。任何在where子句中使用is null或is not null的語句優化器是不允許使用索引的。

  3. 最好不要給數據庫留NULL,儘可能的使用 NOT NULL填充數據庫.NULL值也是可能會需要佔用空間的,一些定長的數據類型即使數據爲NULL也是會佔用空間的。

  4. 應儘量避免在 where 子句中使用 != 或 <> 操作符,否則將引擎放棄使用索引而進行全表掃描。

  5. 應儘量避免在 where 子句中使用 or 來連接條件,如果一個字段有索引,一個字段沒有索引,將導致引擎放棄使用索引而進行全表掃描,可以使用union/union all 代替

  6. in 和 not in 也要慎用,否則會導致全表掃描。一般情況下,當你IN中的條件太多,或是無法估計時,優化器傾向於全表掃描。當IN的條件少時,如果優化器認爲,INDEX SEEK可以帶來好處時,照樣會走索引的。至於in到底會不會走索引,這個衆說紛紜,網上有一種說法:(1)A IN(值列表)肯定用索引、(2)A in (子查詢) 是用不到索引的,但是如果子查詢的條件是和外層相關的,子查詢本身用到索引。但是第一種有個情況,就是如果一個列的值只有有限的幾種,那麼A IN (值列表)也是不會使用索引的,因爲這種情況,全表掃描比走索引快,優化器會選擇走全表掃描的。至於not in 是一個反向查詢,是不會走索引的。

  7. 慎用like用於模糊查詢,因爲其可能導致全表掃描,使用like語句,僅僅後模糊查詢是可以走索引的(如:like '56%'),但是前模糊查詢會全表掃描(如like '%we' 或 like '%we%')

  8. 如果在 where 子句中使用參數,也會導致全表掃描。因爲SQL只有在運行時纔會解析局部變量,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然 而,如果在編譯時建立訪問計劃,變量的值還是未知的,因而無法作爲索引選擇的輸入項。如下面語句將進行全表掃描:select id from t where num = @num 可以改爲強制查詢使用索引:select id from t with(index(索引名)) where num = @num

  9. 應儘量避免在 where 子句中對字段進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描。如:select id from t where num/2 = 100可以改爲select id from t where num = 100*2

  10. 應儘量避免在where子句中對字段進行函數操作,這將導致引擎放棄使用索引而進行全表掃描。如:select id from t where datediff(day,createdate,’2005-11-30′) = 0

  11. 不要在 where 子句中的“=”左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。

  12. 在使用索引字段作爲條件時,如果該索引是複合索引,那麼必須使用到該索引中的第一個字段作爲條件時才能保證系統使用該索引,否則該索引將不會被使用,並且應儘可能的讓字段順序與索引順序相一致。

  13. Update 語句,如果只更改1、2個字段,不要Update全部字段,否則頻繁調用會引起明顯的性能消耗,同時帶來大量日誌

  14. 對於多張大數據量(這裏幾百條就算大了)的表JOIN,要先分頁再JOIN,否則邏輯讀會很高,性能很差

  15. select count(*) from table;這樣不帶任何條件的count會引起全表掃描,並且沒有任何業務意義,是一定要杜絕的。

  16. 索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因爲 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過5個,若太多則應考慮一些不常使用到的列上建的索引是否有 必要。

  17. 應儘可能的避免更新 clustered 索引數據列,因爲 clustered 索引數據列的順序就是表記錄的物理存儲順序,一旦該列值改變將導致整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新 clustered 索引數據列,那麼需要考慮是否應將該索引建爲 clustered 索引。

  18. 儘量使用數字型字段,若只含數值信息的字段儘量不要設計爲字符型,這會降低查詢和連接的性能,並會增加存儲開銷。這是因爲引擎在處理查詢和連 接時會逐個比較字符串中每一個字符,而對於數字型而言只需要比較一次就夠了。

  19. 儘可能的使用 varchar/nvarchar 代替 char/nchar ,因爲首先變長字段存儲空間小,可以節省存儲空間,其次對於查詢來說,在一個相對較小的字段內搜索效率顯然要高些。

  20. 任何地方都不要使用 select * from t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。

  21. 儘量使用表變量來代替臨時表。如果表變量包含大量數據,請注意索引非常有限(只有主鍵索引)。

  22. 避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。臨時表並不是不可使用,適當地使用它們可以使某些例程更有效,例如,當需要重複引用大型表或常用表中的某個數據集時。但是,對於一次性事件, 最好使用導出表。

  23. 在新建臨時表時,如果一次性插入數據量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數據量不大,爲了緩和系統表的資源,應先create table,然後insert。

  24. 如果使用到了臨時表,在存儲過程的最後務必將所有的臨時表顯式刪除,先 truncate table ,然後 drop table ,這樣可以避免系統表的較長時間鎖定。

  25. 儘量避免使用遊標,因爲遊標的效率較差,如果遊標操作的數據超過1萬行,那麼就應該考慮改寫。

  26. 使用基於遊標的方法或臨時表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。

  27. 與臨時表一樣,遊標並不是不可使用。對小型數據集使用 FAST_FORWARD 遊標通常要優於其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的數據時。在結果集中包括“合計”的例程通常要比使用遊標執行的速度快。如果開發時 間允許,基於遊標的方法和基於集的方法都可以嘗試一下,看哪一種方法的效果更好。

  28. 在所有的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每個語句後向客戶端發送 DONE_IN_PROC 消息。

  29. 儘量避免大事務操作,提高系統併發能力。如果你需要在一個在線的網站上去執行一個大的 DELETE 或 INSERT 查詢,你需要非常小心,要避免你的操作讓你的整個網站停止響應。因爲這兩個操作是會鎖表的,表一鎖住了,別的操作都進不來了。

  30. 儘量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。

  31. 對多條數據的操作,能儘量批量操作的就批量操作,減少sql的數量。每一個sql都是一個數據庫連接

  32. 查詢語句執行順序(只在基於規則的優化器中有效):

    • from子句:執行順序從後向前,從右向左。數據量較少的表儘量放後面
    • where子句:執行順序自下而上、從右向左。將能過濾掉最大數據記錄的條件卸載where子句的最後面
    • group by子句:執行順序從左往右分組,最好在group by 前使用where將不需要的記錄過濾掉
    • having子句:比較消耗資源,儘量少用,HAVING會在檢索出所有記錄後纔對結果集進行過濾,需要排序等操作
    • select 子句 :少用*號,儘量取字段名稱。
    • order by子句:執行順序從左到右
  33. 避免數據類型不一致

  34. 讀取適當的記錄LIMIT M,N

  35. 避免在select子語句中使用子查詢

  36. 對於有聯接的列,即使最後的聯接值爲一個靜態值,優化器是不會使用索引的。如:select * from employss where first_name||”||last_name =’Beill Cliton'

  37. 使用DECODE函數來減少處理時間: 使用DECODE函數可以避免重複掃描相同記錄或重複連接相同的表.

  38. 整合簡單,無關聯的數據庫訪問: 如果你有幾個簡單的數據庫查詢語句,你可以把它們整合到一個查詢中(即使它們之間沒有關係)

  39. 儘量多使用COMMIT: 只要有可能,在程序中儘量多使用COMMIT, 這樣程序的性能得到提高,需求也會因爲COMMIT所釋放的資源而減少:,COMMIT所釋放的資源::

    • 回滾段上用於恢復數據的信息.
    • 被程序語句獲得的鎖
    • redo log buffer 中的空間
    • ORACLE爲管理上述3種資源中的內部花費
  40. 避免使用HAVING子句, HAVING 只會在檢索出所有記錄之後纔對結果集進行過濾. 這個處理需要排序,總計等操作. 如果能通過WHERE子句限制記錄的數目,那就能減少這方面的開銷.

  41. 減少對錶的查詢: 在含有子查詢的SQL語句中,要特別注意減少對錶的查詢.例子: SELECT TAB_NAME FROM TABLES WHERE (TAB_NAME,DB_VER) = ( SELECT TAB_NAME,DB_VER FROM TAB_COLUMNS WHERE VERSION = 604)

  42. 使用表的別名(Alias): 當在SQL語句中連接多個表時, 請使用表的別名並把別名前綴於每個Column上.這樣一來,就可以減少解析的時間並減少那些由Column歧義引起的語法錯誤.

  43. 用EXISTS替代IN、用NOT EXISTS替代NOT IN: 在許多基於基礎表的查詢中,爲了滿足一個條件,往往需要對另一個表進行聯接.在這種情況下, 使用EXISTS(或NOT EXISTS)通常將提高查詢的效率. 在子查詢中,NOT IN子句將執行一個內部的排序和合並. 無論在哪種情況下,NOT IN都是最低效的 (因爲它對子查詢中的表執行了一個全表遍歷). 爲了避免使用NOT IN ,我們可以把它改寫成外連接(Outer Joins)或NOT EXISTS.

  44. 用索引提高效率: 索引是表的一個概念部分,用來提高檢索數據的效率,ORACLE使用了一個複雜的自平衡B-tree結構. 通常,通過索引查詢數據比全表掃描要快. 當ORACLE找出執行查詢和Update語句的最佳路徑時, ORACLE優化器將使用索引. 同樣在聯結多個表時使用索引也可以提高效率. 另一個使用索引的好處是,它提供了主鍵(primary key)的唯一性驗證.。那些LONG或LONG RAW數據類型, 你可以索引幾乎所有的列. 通常, 在大型表中使用索引特別有效. 當然,你也會發現, 在掃描小表時,使用索引同樣能提高效率. 雖然使用索引能得到查詢效率的提高,但是我們也必須注意到它的代價. 索引需要空間來存儲,也需要定期維護, 每當有記錄在表中增減或索引列被修改時, 索引本身也會被修改. 這意味着每條記錄的INSERT , DELETE , UPDATE將爲此多付出4 , 5 次的磁盤I/O . 因爲索引需要額外的存儲空間和處理,那些不必要的索引反而會使查詢反應時間變慢.。定期的重構索引是有必要的.: ALTER INDEX <INDEXNAME> REBUILD <TABLESPACENAME>

  45. 用EXISTS替換DISTINCT: 當提交一個包含一對多表信息(比如部門表和僱員表)的查詢時,避免在SELECT子句中使用DISTINCT. 一般可以考慮用EXIST替換, EXISTS 使查詢更爲迅速,因爲RDBMS核心模塊將在子查詢的條件一旦滿足後,立刻返回結果如:(低效): SELECT DISTINCT DEPT_NO,DEPT_NAME FROM DEPT D , EMP E WHERE D.DEPT_NO = E.DEPT_NO (高效): SELECT DEPT_NO,DEPT_NAME FROM DEPT D WHERE EXISTS ( SELECT ‘X’ FROM EMP E WHERE E.DEPT_NO = D.DEPT_NO);

  46. sql語句用大寫的;因爲oracle總是先解析sql語句,把小寫的字母轉換成大寫的再執行

  47. 避免在索引列上使用計算:如果索引列是函數的一部分,優化器將不使用索引而使用全表掃描.

  48. 避免在索引列上使用NOT:當ORACLE”遇到”NOT,他就會停止使用索引轉而執行全表掃描.

  49. 用>=替代> ;用IN來替換OR ;用UNION替換OR;用UNION-ALL 替換UNION ( 如果有可能的話);用WHERE替代ORDER BY

  50. 總是使用索引的第一個列: 如果索引是建立在多個列上, 只有在它的第一個列(leading column)被where子句引用時,優化器纔會選擇使用該索引. 這也是一條簡單而重要的規則,當僅引用索引的第二個列時,優化器使用了全表掃描而忽略了索引

  51. a如果檢索數據量超過30%的表中記錄數.使用索引將沒有顯著的效率提高.;在特定情況下, 使用索引也許會比全表掃描慢, 但這是同一個數量級上的區別. 而通常情況下,使用索引比全表掃描要塊幾倍乃至幾千倍!

  52. 不要給類似“性別”列創建索引(即整個列的值只有一兩種,十幾種的) ,像這種情況的列,一般不會走索引,即便在列上創建了索引,因爲這種情況全表掃描還要快於利用索引,優化器會選擇性的選擇走全表掃描,比如一個列只有四種值a,b,c,d,你用in(‘a’,’b’),這種就不會走索引。

  53. 避免改變索引列的類型:當比較不同數據類型的數據時, ORACLE自動對列進行簡單的類型轉換. 
    假設 EMPNO是一個數值類型的索引列. 
    SELECT … FROM EMP WHERE EMPNO = ‘123′ 
    實際上,經過ORACLE類型轉換, 語句轉化爲: 
    SELECT … FROM EMP WHERE EMPNO = TO_NUMBER(‘123′) 
    幸運的是,類型轉換沒有發生在索引列上,索引的用途沒有被改變. 
    現在,假設EMP_TYPE是一個字符類型的索引列. 
    SELECT … FROM EMP WHERE EMP_TYPE = 123 
    這個語句被ORACLE轉換爲: 
    SELECT … FROM EMP WHERETO_NUMBER(EMP_TYPE)=123 
    因爲內部發生的類型轉換, 這個索引將不會被用到! 爲了避免ORACLE對你的SQL進行隱式的類型轉換, 最好把類型轉換用顯式表現出來. 注意當字符和數值比較時, ORACLE會優先轉換數值類型到字符類型 .

  54. 使用事務:請使用事務,特別是當查詢比較耗時。如果系統出現問題,這樣做會救你一命的。一般有些經驗的程序員都有體會—–你經常會碰到一些不可預料的情況會導致存儲過程崩潰。

  55. 儘量不要使用TEXT數據類型:除非你使用TEXT處理一個很大的數據,否則不要使用它。因爲它不易於查詢,速度慢,用的不好還會浪費大量的空間。一般的,VARCHAR可以更好的處理你的數據。

  56. 儘量不要使用臨時表:儘量不要使用臨時表,除非你必須這樣做。一般使用子查詢可以代替臨時表。使用臨時表會帶來系統開銷,如果你是用COM+進行編程,它還會給你帶來很大的麻 煩,因爲COM+使用數據庫連接池而臨時表卻自始至終都存在。SQL Server提供了一些替代方案,比如Table數據類型

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章