ORACLE數(shù)據(jù)庫應用開發(fā)的三十個注意事項
引言
筆者及所在團隊從2000年開始的CRM等系統(tǒng)開發(fā),一直主要使用ORACLE數(shù)據(jù)庫作為應用數(shù)據(jù)庫,開發(fā)方式包括使用PLSQL編寫存儲過程/數(shù)據(jù)庫函數(shù)/觸發(fā)器、使用ODBC或OCI和ProC開發(fā)C++應用、使用JDBC開發(fā)Java應用、使用tuxdeo開發(fā)中間件應用等。這些應用開發(fā)筆者所在團隊自己做過,也委托華為、亞信、思特奇等國內(nèi)廠商合作做過,整體來說ORACLE數(shù)據(jù)庫功能強大、性能出眾、系統(tǒng)健壯,確實是OLTP聯(lián)機事務處理的最受歡迎的數(shù)據(jù)庫。
因ORACLE服務費居高不下、加上最近幾年美國的操弄打壓,國產(chǎn)數(shù)據(jù)庫也走出了一條自己的路,因此數(shù)據(jù)庫國產(chǎn)化也越來越被提上日程,也有部分應用走出了成功之路,但眾多傳統(tǒng)應用進行國產(chǎn)數(shù)據(jù)庫的改造需要大量投入,也需要一個逐步試點及改造的過程,因此ORACLE仍然是國內(nèi)眾多單位持續(xù)應用的選擇。
今天老猿結(jié)合二十余年的ORACLE數(shù)據(jù)庫應用開發(fā)和運維的經(jīng)驗教訓,總結(jié)在使用ORACLE數(shù)據(jù)庫環(huán)境中的應用開發(fā)中需要注意的一些注意事項,這些問題不但可以作為ORACLE數(shù)據(jù)庫開發(fā)的注意事項,大多數(shù)也適用于常見的關系型數(shù)據(jù)庫開發(fā)甚至非關系型數(shù)據(jù)開發(fā)。
實際上,在數(shù)據(jù)庫應用開發(fā)上,開發(fā)和維護關聯(lián)度是非常大的,好的開發(fā)設計會給維護帶來極大方便。因此雖然維護關注的角度和開發(fā)有所不同,但在部分內(nèi)容上二者是統(tǒng)一的。
禁忌1:觸發(fā)器代碼忌復雜
數(shù)據(jù)庫觸發(fā)器由于可以基于表級進行所有應用或手工DML操作數(shù)據(jù)增刪改查的前向或后向處理,易于收斂邏輯,使用方便,容易受到眾多開發(fā)人員的喜愛。
但在使用上觸發(fā)器與操作數(shù)據(jù)的事務處于同一個事務,因此比較適合簡單處理邏輯,切忌不能在觸發(fā)器上使用復雜邏輯,一般推薦在10行左右代碼比較適合,否則容易導致事務處理出現(xiàn)問題。
如果一定要通過觸發(fā)器進行復雜邏輯處理,最好的做法是通過觸發(fā)器將需要處理的數(shù)據(jù)寫入到單獨的任務表中,然后使用單獨進程對任務表數(shù)據(jù)進行處理。這樣能使得觸發(fā)器和觸發(fā)源二者的事務解耦,又能收斂相關數(shù)據(jù)處理。
禁忌2:忌使用dblink
dblink提供的機制可以使得在一個數(shù)據(jù)庫的存儲過程、觸發(fā)器、數(shù)據(jù)庫函數(shù)中方便的訪問另一個數(shù)據(jù)庫,可以方便地為應用只需連接一個數(shù)據(jù)庫就可以訪問另一個數(shù)據(jù)庫中的數(shù)據(jù),因此給多數(shù)據(jù)庫環(huán)境使用帶來了很大的便利性。
但dblink在跨數(shù)據(jù)庫事務提交上容易引發(fā)問題,一般可以在不帶事務的DML簡單查詢中使用,如果一定要帶事務必須確保事務提交迅速,否則容易引發(fā)分布式事務鎖。而應用程序中使用時,由于運行的環(huán)境復雜多變,無法百分之百保障事務的完整性和響應快速,很容易引發(fā)分布式事務鎖并有一定幾率觸發(fā)ORACLE的BUG,同時dblink本身會大概率甚至百分之百帶來scn號跳變bug,并引發(fā)scn號跳變在數(shù)據(jù)庫間傳播。導致系統(tǒng)故障甚至數(shù)據(jù)庫癱瘓。因此不要在代碼開發(fā)中使用dblink。平時運維也盡量少用,如果一定要用最好不帶事務,并盡快釋放連接。
禁忌3:忌用大表關聯(lián)統(tǒng)計
在一個系統(tǒng)中,除了實時類交易外,也存在一定要求數(shù)據(jù)實時的統(tǒng)計或查詢需求,針對這種數(shù)據(jù)統(tǒng)計,切忌使用大表關聯(lián)進行統(tǒng)計,因為會導致數(shù)據(jù)庫消耗大量計算資源、占用過多的臨時空間,影響其他實時業(yè)務的響應甚至導致系統(tǒng)無法響應。
對于這種需要跨多個大表的統(tǒng)計,最理想的是不放在OLTP數(shù)據(jù)庫執(zhí)行,如果一定要執(zhí)行,一是要想辦法限制數(shù)據(jù)的范圍(如基于時間限制只能統(tǒng)計當天的),二是對于兩個大表關聯(lián)的SQL進行拆分,拆分成兩個SQL,前一個SQL獲取的數(shù)據(jù)通過游標打開后再逐條去另一個大表使用索引逐條數(shù)據(jù)進行訪問,再用客戶端進行統(tǒng)計運算,或者通過游標獲取數(shù)據(jù)生產(chǎn)臨時表再基于臨時表進行統(tǒng)計。
禁忌4:忌用字典式字段索引
索引只有說數(shù)據(jù)在索引字段比較分散才有效果,如果基于一些字典式字段(如性別、課程等)建索引,起不到很好的效果不說,還浪費存儲空間。這種字典式的字段如果一定要發(fā)揮類似索引的效果,可以按字典值建分區(qū)鍵。
禁忌5:慎用主鍵約束
某個表的主鍵理論上看起來是個很好的機制,但在一般性應用中,由于主鍵不能更新,因此在運維時會帶來很多不便,一般建議慎用,而是可以用非空和唯一性約束方式來替代。
禁忌6:慎用外鍵關聯(lián)
外鍵關聯(lián)可以確保某個表的主鍵被其他表作為非主鍵使用時來保障兩個表數(shù)據(jù)的一致性,但外鍵關聯(lián)給程序開發(fā)、運維都帶來了更多的復雜性,而好的開發(fā)習慣能確保兩個有外鍵關聯(lián)的表滿足數(shù)據(jù)一致性的要求,因此一般情況下慎用外鍵關聯(lián)。這其實是根據(jù)在方便性、數(shù)據(jù)一致性之間應用更傾向于哪方面來決策使用方式。
禁忌7:組合索引使用要注意
- 使用多個字段的混合索引是常見的,但索引使用的字段越多,就意味著開發(fā)時需要關注的字段越多,開發(fā)時部分人員容易忘記索引字段,導致容易寫出用不到索引的語句。因此一般建議復合索引使用字段不超過5個;
- 組合索引中字段的順序是非常重要的,越是唯一的字段越是要靠前;
- 程序代碼使用組合索引時,在使用索引字段作為條件時,如果該索引是復合索引,那么必須使用到該索引中的第一個字段作為條件時才能保證系統(tǒng)使用該索引,并且應盡可能的讓字段順序與索引順序相一致。
禁忌8:慎重考慮表字段調(diào)整
當一個初始設計的表在運行一段時間后,隨著業(yè)務的發(fā)展和系統(tǒng)的持續(xù)運營,對表結(jié)構(gòu)進行調(diào)整是遲早的事,但調(diào)整表結(jié)構(gòu)如增加新字段、字段長度調(diào)整等都需要慎重,特別是針對數(shù)據(jù)量大訪問頻繁的表更要謹慎。
在評估表結(jié)構(gòu)調(diào)整時,一般需要考慮:
- 是否需要停系統(tǒng)調(diào)整,對于高并發(fā)訪問頻繁的表至少要等到業(yè)務閑時進行調(diào)整;
- 如果是調(diào)整字段大小需要評估是否有代碼限制了字段大??;
- 如果是新增字段需要評估是否有代碼采用了select *方式訪問;
- 是否需要初始化歷史數(shù)據(jù)?如果有是否會造成行遷移?是否需要重建表?
- 是否會影響外圍接口或系統(tǒng)數(shù)據(jù)的交互?
為了應對字段增加可能帶來的風險,有2個方法來提取預防:
- 給一些大表預留一定的字段,這樣可以避免停系統(tǒng)、減少行數(shù)據(jù)遷移、并避免系統(tǒng)運行時進行表結(jié)構(gòu)調(diào)整的風險,但要規(guī)劃好預留字段的數(shù)量、并做好啟用管理;
- 盡量不動大表本身,而是設計擴展表來解決。
禁忌9:忌直接使用用戶名和密碼連接數(shù)據(jù)
在信息安全非常重視的今天,數(shù)據(jù)庫的安全性是重中之重,應用系統(tǒng)不應該在程序代碼或配置文件中直接使用用戶名和密碼方式連接訪問業(yè)務數(shù)據(jù)。如果這樣,對開發(fā)人員和維護人員密碼就和沒有密碼一樣,另外如果出現(xiàn)數(shù)據(jù)庫必須修改密碼時,需要到處改密碼相關的代碼或配置文件。
比較好的解決辦法是用最小權(quán)限的用戶登錄,登錄后通過專用加密配置表獲取用戶真正使用的用戶和密碼,這就是二次登錄。
禁忌10:慎用數(shù)據(jù)庫連接
在一個大型系統(tǒng)內(nèi),數(shù)據(jù)庫連接是寶貴的資源,ORACLE的連接數(shù)單實例一般限制在4096個,看起來不少,但如果連接節(jié)點多真正使用起來后會發(fā)現(xiàn)連接數(shù)往往不夠用。為此需要對數(shù)據(jù)庫的訪問進行連接收斂管控,實現(xiàn)連接的復用。
要實現(xiàn)連接的收斂,有如下做法:
- WEB服務器通過連接池管理收斂客戶端的數(shù)據(jù)訪問;
- 后臺進程或中間間通過數(shù)據(jù)訪問代理層來進行連接的復用和收斂;
- 后臺維護限制單機登錄會話數(shù)。
禁忌11:忌用并行
在程序代碼或表的參數(shù)設置里,都可以設置并行參數(shù),并行對于單表或單語句能起到迅速提高執(zhí)行效率的作用,但這種并行是以搶占其他任務的資源為代價,因此在OLTP數(shù)據(jù)庫應用中,最好別使用并行的DML語句或?qū)⒈淼牟⑿袇?shù)打開。臨時執(zhí)行任務考慮到執(zhí)行速度需要使用并行時,一定要與DBA協(xié)商是否可以開啟并行,并在任務執(zhí)行結(jié)束后關閉
表的并行參數(shù)。
前幾年,有個工程割接時為了提升割接速度,當晚一個參與割接的工程師未和任何人商議就將一個重要的訪問頻繁的大表的并行參數(shù)設置調(diào)整多倍,割接后也未關閉,導致第二天業(yè)務起來后數(shù)據(jù)庫出現(xiàn)了鎖、主機CPU全忙,影響業(yè)務超過4個小時。經(jīng)過較長時間定位才發(fā)現(xiàn)是該表并行被打開導致的,問題最終解決但造成了不良影響。而那個導致問題的工程師也在華為年底考核中得到了處罰離職走人。
禁忌12:忌SQL語句不使用綁定變量
在應用開發(fā)中,SQL語句大多數(shù)是動態(tài)SQL,這種動態(tài)SQL又分為兩種,一種是字段取值是變化的,一種是連數(shù)據(jù)對象名都是動態(tài)的。
對于字段取值變化的情況,基本的訪問SQL是固定的,針對變化的字段值就需要用綁定變量方式傳值,這時數(shù)據(jù)庫才不會重新編譯該SQL語句,可以提高執(zhí)行效率,如果不使用綁定變量,直接將該SQL語句用字符串方式拼接,其實就與數(shù)據(jù)對象也是不同變換的方式相同,這樣SQL語句每回都會被編譯,效率會大幅下降。
對于數(shù)據(jù)對象名都是動態(tài)的SQL,不適合通過綁定變量方式傳遞數(shù)據(jù)對象名。
禁忌13:忌索引數(shù)量過多
一個表的索引是需要單獨占用存儲空間的,過多的索引會導致表數(shù)據(jù)發(fā)生變化時索引的調(diào)整占用過多的時間,會引發(fā)數(shù)據(jù)的增刪改性能下降。對于頻繁進行插入、刪除、更新的數(shù)據(jù)表,應控制索引的數(shù)量,提高效率,一般一個表的索引數(shù)控制在5個以內(nèi)。如果一個表要建5個以上索引,一般說明表和應用的設計是存在問題的。
禁忌14:select for update 要帶nowait
select ... for update語句 對于保證事務的完整性很有必要,但在一個并發(fā)環(huán)境中,使用該語句的應用很可能會導致數(shù)據(jù)庫鎖甚至死鎖,正確的做法是select ... for update nowait,并且在獲取鎖失敗時要有重新處理的機制。
禁忌15:批量任務要控制好事務提交的頻度
在后臺進程或存儲過程處理大批量數(shù)據(jù)時,事務提交禁止單條提交或者全部完成后再提交,提交太頻繁會產(chǎn)生過多的數(shù)據(jù)庫日志,一次性提交容易導致回滾段不夠等問題。建議使用100、500或者1000條提交的頻度。
禁忌16:sequence使用注意
對于部分表的內(nèi)部關鍵ID字段如流水號等使用sequence是個非常不錯的主意,可以有效保障并發(fā)環(huán)境下這種序列號分配的高效和唯一性。但在應用中使用sequence時要注意幾點:
- 長度設置要充分考慮業(yè)務發(fā)展的速度,有效序列在初期增長緩慢,但隨著業(yè)務發(fā)展會迅速增長,因此開發(fā)設計時要進行充分的評估,防止出現(xiàn)sequence很快被耗盡;
- 對于長期增長的序列號,最后采用時間戳+序列號的方式來作為字段值,防止序列號翻轉(zhuǎn);
- 序列號分配時,由于序列號在不同數(shù)據(jù)庫實例的緩沖機制,可能會出現(xiàn)后面的數(shù)據(jù)記錄序列號比前面插入記錄序列號還要小的情況,因此序列號字段的值只能作為唯一鍵值使用,而不能作為業(yè)務排序的依據(jù)。
禁忌17:慎用rowid更新數(shù)據(jù)
rowid是數(shù)據(jù)庫記錄的一個內(nèi)部記錄ID,使用rowid訪問數(shù)據(jù)比普通索引還要高效,但如果在一個表的數(shù)據(jù)頻繁插入、刪除時,不要使用rowid來進行數(shù)據(jù)的操作,因為ORACLE的rowid在數(shù)據(jù)有刪除機制時,是有一定幾率出現(xiàn)重復的。
禁忌18:慎用子查詢
通過子查詢方式進行數(shù)據(jù)的嵌套查詢SQL的可讀性比較好,但子查詢很容易導致全表掃描,且容易導致回滾段或臨時表空間使用過高,因此慎用子查詢,特別是子查詢的結(jié)果集也很大時忌用。
禁忌19:忌用SELECT *
在查詢SQL語句中,要盡量減少返回的結(jié)果行,包括行數(shù)和字段列數(shù)。返回的結(jié)果越大,意味著相應的SQL語句的logical reads 就越大,對服務器的性能影響就越甚。
一個特別不好的設計就是使用SELECT * 返回表的所有數(shù)據(jù),除了影響服務器性能外,還可能會由于表結(jié)構(gòu)的調(diào)整在編譯階段無法發(fā)現(xiàn),導致運行時錯誤。
禁忌20:where 子句中慎用!=或<>操作符
使用!=或<>意味著對應字段的訪問不會使用索引,因此只有在其他字段使用了索引的基礎上才使用!=或<>操作。
禁忌21:where 子句中慎用like
如果在where字句中使用字段A like ‘%xxx' 或字段A like ‘%xxx%'方式匹配結(jié)果記錄時,該字段不會使用索引,因此只有在其他字段使用了索引的基礎上才使用字段A like ‘%xxx' 或字段A like ‘%xxx%'方式,即忌用前置百分號匹配。
禁忌22:where 子句中慎用in和not in
如果in后面的結(jié)果數(shù)據(jù)比較多,很可能會導致全表掃描。因此只能和其他能使用索引的條件組合使用時使用。
禁忌23:where字句中慎用字段函數(shù)操作
應盡量避免在where子句中對字段進行函數(shù)操作,這將導致引擎放棄使用索引而進行全表掃描。不要在 where 子句中的“=”左邊進行函數(shù)、算術運算或其他表達式運算,否則系統(tǒng)將可能無法正確使用索引。
禁忌24:忌用select count(*)
使用select count(*)的效率不如使用select count(1)。
禁忌25:索引字段訪問慎用OR
索引字段用OR的字句容易導致全表掃描,一定要判斷多個值可以分解成多個查詢,并且通過UNION 連接多個查詢。
禁忌26:慎重考慮字符集
在一個應用系統(tǒng)中,涉及應用服務器主機字符集、數(shù)據(jù)庫字符集以及客戶端字符集的兼容性問題,要在系統(tǒng)構(gòu)架時統(tǒng)一考慮,確保從前臺到后臺到數(shù)據(jù)庫的字符集都是兼容的。
禁忌27、慎用視圖嵌套
視圖最好建在表上,盡量不要基于視圖嵌套建立視圖,一方面一般視圖嵌套不要超過2個為宜,視圖嵌套層級多訪問效率會下降,并且可維護性變差。
禁忌28: 忌數(shù)據(jù)對象名過長
oracle的表名、字段名等對象命名字節(jié)個數(shù)限制在了30個字節(jié),不能超過30。
禁忌29:謹慎表和索引的inittrans設置
每個塊都有一個塊首部。這個塊首部中有一個事務表。事務表中會建立一些條目來描述哪些事務將塊上的哪些行/元素鎖定。這個事務表的初始大小由對象的INITRANS 設置指定。對于表,這個值默認為2(索引的INITRANS 也默認為2)。事務表會根據(jù)需要動態(tài)擴展,最大達到MAXTRANS 個條目(假設塊上有足夠的自由空間)。所分配的每個事務條目需要占用塊首部中的23~24 字節(jié)的存儲空間。注意,對于Oracle 10g以上版本,MAXTRANS 則會忽略,所有段的MAXTRANS 都是255。
也就是說,如果某個事物鎖定了這個塊的數(shù)據(jù),則會在這個地方記錄事務的標識,當然那個事務要先看一下這個地方是不是已經(jīng)有人占用了,如果有,則去看看那個事務是否為活動狀態(tài)。如果不活動,比如已經(jīng)提交或者回滾,則可以覆蓋這個地方。如果活動,則需要等待(閂的作用)。
所以,如果有大量的并發(fā)訪問使用的這個塊,則參數(shù)不能太小,否則資源競爭將導致系統(tǒng)并發(fā)性能下降。
在創(chuàng)建表和索引時,需要根據(jù)表數(shù)據(jù)的訪問頻度和數(shù)據(jù)量來評估設置的inittrans值,雖然不夠時Oracle會自動增加,但增加的過程需要ORACLE進行評估,且該評估機制是針對所有對象的,需要排隊,如果inittrans值設置過小,就會影響系統(tǒng)的并發(fā)性能。因此系統(tǒng)設計和部署時需要考慮不同表的inittrans的設置。
禁忌30:數(shù)據(jù)模型和數(shù)據(jù)對象的設計必須商DBA確認
一個業(yè)務系統(tǒng),會有大量的數(shù)據(jù)模型,會創(chuàng)建大量數(shù)據(jù)對象,在考慮業(yè)務需求的同時必須考慮系統(tǒng)運維,因此請DBA參與設計是非常必要的。
在做設計時,要考慮:
- 制定數(shù)據(jù)庫對象命名規(guī)范;
- 數(shù)據(jù)庫表空間的使用規(guī)劃(包括業(yè)務數(shù)據(jù)表和索引、字典表、臨時表空間、回滾段等);
- 表和索引的inittrans大?。?/li>
- 各個表的PCTFREE 和 PCTUSED設置;
- 數(shù)據(jù)維護周期
- …
小結(jié):
本文詳細介紹了筆者在二十余年ORACLE應用開發(fā)中遇到的三十條開發(fā)注意事項(本來想寫成三十六忌的,奈何沒湊夠),這些注意事項是實際工作中的經(jīng)驗和教訓總結(jié),好些注意事項是筆者的團隊以及華為等合作廠商一些工作兩三年的人都容易犯的錯,筆者前2年遭遇的一次事件還導致了一個華為工程師的考核離職。
這些注意事項不但可以在和ORACLE有關的應用開發(fā)中遇到,大部分也可以在其他關系型數(shù)據(jù)庫有關的應用開發(fā)中遇到,甚至部分問題可以在非關系型數(shù)據(jù)有關的應用開發(fā)中遇到。
以上就是ORACLE數(shù)據(jù)庫應用開發(fā)的三十個注意事項的詳細內(nèi)容,更多關于ORACLE數(shù)據(jù)庫應用開發(fā)的注意事項的資料請關注腳本之家其它相關文章!
- zabbix agent2 監(jiān)控oracle數(shù)據(jù)庫的方法
- Python查詢oracle數(shù)據(jù)庫速度慢的解決方案
- ORACLE數(shù)據(jù)庫對long類型字段進行模糊匹配的解決思路
- 配置python連接oracle讀取excel數(shù)據(jù)寫入數(shù)據(jù)庫的操作流程
- SpringBoot多數(shù)據(jù)庫連接(mysql+oracle)的實現(xiàn)
- 使用zabbix監(jiān)控oracle數(shù)據(jù)庫的方法詳解
- Oracle數(shù)據(jù)庫下載與安裝的完整步驟
- QT連接Oracle數(shù)據(jù)庫并實現(xiàn)登錄驗證的操作步驟
- oracle取數(shù)據(jù)庫中最新的一條數(shù)據(jù)可能會遇到的bug(兩種情況)
- 使用IDEA對Oracle數(shù)據(jù)庫進行簡單增刪改查操作
- Oracle數(shù)據(jù)庫scott用戶創(chuàng)建view視圖權(quán)限的操作方法
相關文章
PL/SQL編程經(jīng)驗小結(jié)開發(fā)者網(wǎng)絡Oracle
PL/SQL編程經(jīng)驗小結(jié)開發(fā)者網(wǎng)絡Oracle...2007-03-03Oracle數(shù)據(jù)庫中基本的查詢優(yōu)化與子查詢優(yōu)化講解
這篇文章主要介紹了Oracle數(shù)據(jù)庫中基本的查詢優(yōu)化與子查詢優(yōu)化講解,舉了實例來分析子查詢對性能的影響,需要的朋友可以參考下2016-01-01oracle ora-00054:resource busy and acquire with nowait speci
這篇文章主要介紹了oracle ora-00054:resource busy and acquire with nowait specified解決方法,需要的朋友可以參考下2015-12-12誤刪除$ORACLE_HOME/dbs下的參數(shù)文件、密碼文件快速重建的方法
這篇文章主要介紹了誤刪除$ORACLE_HOME/dbs下的參數(shù)文件、密碼文件快速重建的方法,需要的朋友可以參考下2017-04-04Windows系統(tǒng)下Oracle?11g完全卸載教程(推薦!)
安裝軟件是首要,雖然不是特別重要,但是錯誤的安裝也是相當費勁和抓狂的,所以這篇文章主要給大家介紹了關于Windows系統(tǒng)下Oracle?11g完全卸載的相關資料,文中通過圖文介紹的非常詳細,要的朋友可以參考下2024-06-06