1. 程式人生 > >java面試總結(八)—— SQL優化、SQL軍規、隱式轉換

java面試總結(八)—— SQL優化、SQL軍規、隱式轉換

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.

    exists與in的選擇
    - IN查詢在內部表和外部表上都可以使用到索引;
    - Exists查詢僅在內部表上可以使用到索引;
    - 當子查詢結果集很大,而外部表較小的時候,Exists的Block Nested Loop(Block 巢狀迴圈)的作用開始顯現,並彌補外部表無法用到索引的缺陷,查詢效率會優於IN。
    - 當子查詢結果集較小,而外部表很大的時候,Exists的Block巢狀迴圈優化效果不明顯,IN 的外表索引優勢佔主要作用,此時IN的查詢效率會優於Exists。
    - 網上的說法不準確,即表的規模不是看內部表和外部表,而是外部表和子查詢結果集。

    注:在對不同資料集情況下的exists語句分析發現,資料集越大,消耗的時間反而變小。如:
    where tp.proptry_id > 3650 耗時0.13s
    where tp.proptry_id > 293650 耗時0.46s
    可能原因:條件值大,查詢越靠後,需要遍歷的記錄越多,造成最終消耗越多的時間。

  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資料型別

資料庫軍規

注:軍規主要適用於那些大企業,有著併發量大、資料量大的網際網路業務。這類業務架構設計的重點往往是吞吐量,效能優先,對資料庫效能影響較大的資料庫特性較少使用。這類場景的架構方向是“解放資料庫CPU,把複雜邏輯計算放到服務層”,服務層具備更好的擴充套件性,容易實現“增機器就擴充效能”,資料庫擅長儲存與索引,勿讓資料庫揹負過重的任務。

  1. 必須使用UTF8字符集,新庫預設使用utf8mb4字符集。utf8mb4是utf8的超集,emoji表情以及部分不常見漢字在utf8下會表現為亂碼,故需要升級至utf8mb4。預設使用這個字符集的原因是:“標準,萬國碼,無需轉碼,無亂碼風險”,並不“節省空間”。

  2. 資料表、資料欄位必須加入中文註釋

  3. 禁止使用外來鍵,如果有外來鍵完整性約束,需要應用程式控制:外來鍵會導致表與表之間耦合,update與delete操作都會涉及相關聯的表,十分影響sql 的效能,甚至會造成死鎖。高併發情況下容易造成資料庫效能,大資料高併發業務場景資料庫使用以效能優先

  4. 禁止大表使用JOIN查詢,禁止大表使用子查詢

  5. 只允許使用內網域名,而不是ip連線資料庫。不只是資料庫,快取(memcache、redis)的連線,服務(service)的連線都必須使用內網域名,機器遷移/平滑升級/運維管理…太多太多的好處,如果朋友你還是採用ip直連的,趕緊升級到內網域名吧。

  6. 禁止使用小數儲存貨幣,建議使用整數儲存,小數容易獲取導致錢對不上

  7. 禁止使用負向查詢NOT、!=、<>、!<、!>、NOT IN、NOT LIKE等,以及%開頭的模糊查詢,會導致全表掃描。
    一般來說,WHERE過濾條件不會只帶這麼一個“負向查詢條件”,還會有其他過濾條件,舉個例子:查詢沈劍已完成訂單之外的訂單(好拗口):
    SELECT oid FROM t_order WHERE uid=123 AND status != 1;
    訂單表5000w資料,但uid=123就會迅速的將資料量過濾到很少的級別(uid建立了索引),此時再接上一個負向的查詢條件就無所謂了,掃描的行數本身就會很少。
    但如果要查詢所有已完成訂單之外的訂單:
    SELECT oid FROM t_order WHERE status != 1;
    這就掛了,立馬CPU100%,status索引會失效,負向查詢導致全表掃描。

  8. 禁止使用應用程式配置檔案內的帳號手工訪問線上資料庫

  9. 禁止非DBA對線上資料庫進行寫操作,修改線上資料需要提交工單,由DBA執行,提交的SQL語句必須經過測試

  10. 分配非DBA以只讀帳號,必須通過VPN+跳板機訪問授權的從庫

  11. 開發、測試、線上環境隔離

  12. 必須使用InnoDB儲存引擎:支援事務、行級鎖、併發效能更好、CPU及記憶體快取頁優化使得資源利用率更高

  13. 禁止儲存大檔案或者大照片:為何要讓資料庫做它不擅長的事情?大檔案和照片儲存在檔案系統,資料庫裡存URI多好

  14. 線上環境、開發環境、測試環境資料庫內網域名遵循命名規範(自己的命名規範)

  15. 庫名、表名、欄位名:小寫,下劃線風格,不超過32個字元,必須見名知意,禁止拼音英文混用

  16. 表名t_xxx,非唯一索引名idx_xxx,唯一索引名uniq_xxx

  17. 單例項表數目必須小於500

  18. 單表列數目必須小於30(這個數目看業務,不過一般不會太多)

  19. 表必須有主鍵,例如自增主鍵

  20. 必須把欄位定義為NOT NULL並且提供預設值

  21. 禁止使用TEXT、BLOB型別

  22. 必須使用varchar(20)儲存手機號

  23. 禁止使用ENUM,可使用TINYINT代替:增加新的ENUM值要做DDL操作;ENUM的內部實際儲存就是整數,你以為自己定義的是字串?

  24. 單表索引建議控制在5個以內

  25. 單索引欄位數不允許超過5個

  26. 禁止在更新十分頻繁、區分度不高的屬性上建立索引

  27. 建立組合索引,必須把區分度高的欄位放在前面:能夠更加有效的過濾資料

  28. 禁止使用SELECT *,只獲取必要的欄位,需要顯示說明列屬性

  29. 禁止使用INSERT INTO t_xxx VALUES(xxx),必須顯示指定插入的列屬性:容易在增加或者刪除欄位後出現程式BUG

  30. 禁止使用屬性隱式轉換:SELECT uid FROM t_user WHERE phone=13812345678 會導致全表掃描,而不能命中phone索引

  31. 禁止在WHERE條件的屬性上使用函式或者表示式

  32. 應用程式必須捕獲SQL異常,並有相應處理

  33. 禁止使用OR條件,必須改為IN查詢,in的個數建議控制在200以內:舊版本Mysql的OR查詢是不能命中索引的,即使能命中索引,為何要讓資料庫耗費更多的CPU幫助實施查詢優化呢?

  34. 不在資料庫做運算:cpu計算務必移至業務層

  35. 控制單表資料量:單表記錄控制在1000w

  36. 平衡正規化與冗餘:為提高效率犧牲正規化設計,冗餘資料

  37. 拒絕3B:拒絕大sql,大事物,大批量

  38. 字元轉化為數字

  39. sql語句儘可能簡單:一條sql只能在一個cpu運算;大語句拆小語句,減少鎖時間;一條大sql可以堵死整個庫

  40. 簡單的事務:事務時間儘可能短

  41. limit高效分頁:limit越大,效率越低

  42. 少用連線join

  43. 使用load data導資料:load data比insert快約20倍;

  44. 打散批量更新

隱式型別轉換

所謂隱式轉換就是說我們在寫SQL語句時,對兩個資料的比較、計算等如果資料型別不一致,且沒有明確的轉換資料型別時,資料庫為了計算、比較會對某一個數據的資料型別進行隱式的轉換。

當我們某一個查詢導致某個列的資料發生型別隱式轉換時,索引就不能再用了,所以建議大家在條件設定時,請明確的轉換好型別在比較。比如:varchar型的f_qq1_id,轉換成浮點型比較時,等於 12345 的情況有無數種如12345a、12345.b等待,MySQL優化器無法確定索引是否更有效,所以選擇了其它方案。

注:下方的隱式轉換都是我從網上總結的,有錯誤的歡迎指正

mysql

比較(<、> 、=、>=、<=) 計算(+、- 、* 、/)

  1. 兩個引數至少有一個是 NULL 時,比較的結果也是 NULL,例外:使用 <=> 對兩個 NULL 做比較時會返回 1,這兩種情況都不需要做型別轉換
  2. 兩個引數型別相同時進行比較
  3. 十六進位制的值和非數字做比較時,會被當做二進位制串
  4. 有一個引數是 TIMESTAMP 或 DATETIME,並且另外一個引數是常量,常量會被轉換為 timestamp,比較和計算都符合
  5. 有一個引數是 decimal 型別,如果另外一個引數是 decimal 或者整數,會將整數轉換為 decimal 後進行比較,如果另外一個引數是浮點數,則會把 decimal 轉換為浮點數進行比較
  6. 所有其他情況下比較(兩個型別不一致),兩個引數都會被轉換為浮點數再進行比較
  7. 所有資料型別在計算時都會轉換成浮點數在計算,就算兩個字串計算也是一樣。

注:
1.當一個字串和數值型資料進行計算、比較時,如果字串是以數字開頭,比如:'55ab'其會隱式轉換為開頭的數字, 前面的就是55,但是如果字串是以字母開頭,則統一會轉換成0。所以會有下面的查詢情況:

select '55abv' + 55  結果為 110
select 'abv55' + 55 結果為 55
select '56abv' > 55 結果為 1
select '55abv' = 55 結果為 1 
select 'abv55' = 55 結果為 0
select '55abv' > 55 結果為 0
//code欄位為字串欄位,其有三條資料: GB245 、245GB 、GBSER
select * from test where code = 0 結果匹配為:GB245 、GBSER //因為在比較時,這兩個資料都會被隱式的轉換為0
select * from test where code = 0 + '245' 結果為 245GB  //因為後面的加法計算已經將後面的資料轉換成了浮點數245,與字串欄位比較,其他的會轉換成浮點數0,245GB  會轉換成浮點數 245 所以匹配成功

orcale

1.當比較字元型和數值型的值時,oracle會把字元型的值隱式轉換為數值型,這種處理可能發生在條件值上,也可能發生在列上。

  • Oracle發現型別的不匹配之後,如果資料表列是數字型別,而輸入值是一個字串,Oracle會對字串進行to_number函式處理。這種情況是正向的,不會影響到索引列的使用。

  • 我們看到了不同,如果列是一個字串型別,輸入一個數字型別條件值,就會讓Oracle在列上面新增to_number函式。也就是說,會對字串物件進行處理。此種情況下將不會走索引

2.對於INSERT和UPDATE操作,oracle會把插入值或者更新值隱式轉換為欄位的資料型別。

3.當比較字元型和日期型的資料時,oracle會把字元型轉換為日期型。

4.隱式轉換髮正在欄位列上時將使索引失效

隱式轉換的缺點:

  1. 使用顯示型別轉換會讓我們的SQL更加容易被理解,也就是可讀性更強,但是隱式型別轉換卻沒有這個優點。

  2. 隱式型別轉換往往對效能產生不好的影響,特別是左值的型別被隱式轉為了右值的型別。這種方式很可能使我們本來可以使用索引的而沒有用上索引,也有可能會導致結
    果出錯。

  3. 隱式型別轉換可能依賴於發生轉換時的上下文環境,比如1中的to_date(sysdate,fmt),一旦上下文環境改變,很可能我們的程式就不能執行。

  4. 隱式型別轉換的演算法或規則,以後Oracle可能改變,這是很危險的,意味著舊的程式碼很可能在新的Oracle版本中執行出現問題(效能、錯誤等),顯示型別轉換總是有最高
    的優先順序,所以顯示型別轉換沒有這種版本更替可能帶來的問題。

  5. 隱式型別轉換是要消耗時間的,當然同等的顯式型別轉換時間也差不多,最好的方法就是避免類似的轉換,在顯示型別轉換上我們會看到,最好不要將左值進行型別轉換,到
    時候有索引也用不上索引,還要建函式索引,索引儲存和管理開銷增大。

總結:

Oracle使用資料型別的優先順序來決定隱式型別轉換,原則是將優先順序低的轉換為優先順序高的(資料型別優先順序為:Number>字元型別>日期型別)。隱式轉換髮生在欄位列上時將使索引失效。