程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> Oracle數據庫 >> Oracle數據庫基礎 >> PL/SQL最差實踐

PL/SQL最差實踐

編輯:Oracle數據庫基礎

1.超長的PL/SQL代碼

影響:可維護性,性能

症狀:

在復雜的企業應用中,存在動辄成百上千行的存儲過程或上萬行的包。

為什麼是最差:

太長的PL/SQL代碼不利於閱讀,第三方工具在調試時也會出現代碼行混亂等問題。PL/SQL存儲對象(存儲過程、包、函數、觸發器等)行數上限約為6000000行,但實際工作中,當包大小超過5000行就會出現調試問題。

解決之道:

PL/SQL代碼在執行前會被加載到shared pool中,shared pool以字節為單位,UNIX下為64K,桌面環境下為32K,可以通過查詢數據字典USER_OBJECT_SIZE的PARSED_SIZE字段查看對象大小。對於較大的包,應采用拆包策略,抽取復用部分,減少重復代碼;對於較大的存儲過程,應將存儲過程組織到包中,易於管理;對於較大的匿名塊,應將匿名塊重新定義成子過程保存在數據庫中。

2.脫離控制的全局變量

影響:可維護性

症狀:在包中使用了全局變量,在多個位置對全局變量進行操作。

create OR REPLACE PACKAGE BODY PKG_TEST IS
GN_全局變量 NUMBER(12, 2);
PROCEDURE 過程A IS
BEGIN
GN_全局變量:=1;
END;
PROCEDURE 過程B IS
BEGIN
GN_全局變量:=2; -- 這裡對全局變量進行了另外的操作
END;

為什麼是最差:

全局變量可以在整個包范圍內被訪問到,因此對全局變量的跟蹤和調試會比較困難。如果變量是在package中定義的,變量還可以被其他包訪問,這將會更為危險。

解決之道:

減少或取締全局變量的使用,對於要在過程間交互的變量,通過參數傳遞來實現。如果必須使用全局變量,應對全局變量進行get/set函數封裝,規范對全局變量的訪問。

3.PL/SQL中嵌入復雜SQL語句

影響:可維護性

症狀:

在PL/SQL代碼中嵌入SQL語句,如:

...
PROCEDURE 過程A IS
BEGIN
update T_A SET COL1 = 10;
END;
PROCEDURE 過程B IS
BEGIN
delete FROM T_A where COL1=10;
END;
...

為什麼是最差:

PL/SQL代碼中嵌入SQL語句使得代碼含義變得難於閱讀和理解

在多個位置對表進行訪問,不利於SQL優化

解決之道:

將分散SQL語句進行封裝,例如上例中的刪除語句,可以封裝為“prc_刪除T_A()”過程參數為T_A的type類型,對T_A的刪除操作都委托此過程處理,當T_A表增加或刪除字段時,主要的變化都集中在這些過程中,對其他邏輯影響較少

對SQL的優化集中在封裝的過程中

4.“異常”的異常處理

影響:可維護性,健壯性

症狀:我們來看下面的代碼:

PROCEDURE 過程A(錯誤代碼 out varchar2,錯誤信息 out varchar2) IS
BEGIN
...
update T_A SET COL1 = 10;
select ...FROM T_A where ...;
delete FROM T_A where COL1 = 20;
...
EXCEPTION
WHEN OTHERS THEN
...
END;

為什麼是最差:

整個過程只有一個WHEN OTHERS 的異常段,示例中的三個語句發生的異常只能被最外層捕捉,無法區分發生異常的種類和位置。

解決之道:

不使用WHEN OTHERS捕捉所有異常,例如不應該捕捉NO_DATA_FOUND異常,使用專用的Exception來捕捉特定的異常。

聲明自己的異常處理機制,處理與業務相關的異常,將業務異常與系統運行期異常分開處理。

自定義完整的異常信息,異常信息中包含異常發生時的場景。

5.固定的變量長度和變量類型

影響:可維護性

症狀:當聲明基於字段類型的變量時,尤其是varchar2類型,直接使用固定長度聲明。

為什麼是最差:

這種硬編碼的變量大小很可能與數據庫中實際大小不符

如果字段的類型、大小等發生變化,還需要到PL/SQL中調整變量

解決之道:

使用%Type聲明與字段類型相關的變量。

6.不做單元測試

影響:健壯性

症狀:PL/SQL代碼中蘊含大量的業務邏輯,這些邏輯編寫完畢後,沒有提供合適的單元測試用例用於驗證。

為什麼是最差: 不做單元測試的危害這裡就不再廢話了。

解決之道:

PL/SQL並沒有提供諸如JUnit之類易用的單元測試工具。現在有一些開源工具可以使用。使用utPLSQL(http://utplsql.sourceforge.Net/)工具進行單元測試,或DBUnit進行二次開發,滿足不同應用的需要。

7.使用代碼值而不使用代碼名稱

影響:可維護性

症狀:我們看下面的代碼:

方法1:

V_sex:=’1’; -- 男

方法2:

CONST_MALE CONSTANT VARchar2(1) := ’1’; -- 定義常量 男

V_sex:=CONST_MALE;

為什麼是最差:

從例子中可以看出,同樣是使用性別,方法1是直接使用代碼值,方法2是使用常量,看上去似乎方法2要比方法1麻煩一些,但方法2比方法1更為直觀,代碼的可讀性也更好,代碼的閱讀者不需要關注“1”代表什麼含義。

當其他項目男性性別定義修改為“2”時,采用方法1編碼的程序需要仔細查找每一段代碼,容易產生錯誤,而采用方法2編碼的程序只修改常量定義即可。

解決之道:

將常量定義放入到公共的代碼包中,供其他程序共享,所有涉及到代碼值的比較、引用等都必須使用常量名,而不能直接書寫代碼值。對於一些復雜的代碼值間的關系可以進一步封裝,以函數的方式提供調用。

8.不對PL/SQL對象進行配置管理

影響:可維護性

症狀:PL/SQL對象(package、package body、trigger、procedure、type、type body、函數等)的代碼沒有使用配置管理工具進行維護和更新。

為什麼是最差:

因為Oracle內部結構的差異,對象的管理具有一定的難度,尤其是在並行開發的情況下。

對象職責劃分不清,造成多人同時修改一個對象,在編譯時,如果後來者沒有獲取最新的代碼,會造成前一個開發人員修改的代碼被覆蓋。

Oracle對象不能追溯既往,數據庫中只能保存最新

解決之道:

規范開發過程,以配置管理工具上的PL/SQL代碼為最新。

使用第三方插件減少同步工作量,如PL/SQL Developer下的VCS版本控制插件。

9.IF … ELSE …的壞味道

影響:可維護性

症狀:大量使用IF … ELSE

為什麼是最差:

大量存在IF/ELSE,造成代碼邏輯混亂、不易修改。無論是PL/SQL還是其他編程語言,這種代碼都已經飄著“bad smell”了。

解決之道:

使用Oracle數據庫的繼承特性,通過type實現對象的繼承,利用策略模式封裝差異,對外提供統一的調用接口

將頻繁使用的IF/ELSE代碼重構為單獨的過程或函數,供其他代碼復用

10.在非自治事務中控制事務

影響:數據一致性

症狀:

在PL/SQL非自治事務代碼中控制事務,例如:

PROCEDURE 過程A(錯誤代碼 out varchar2,錯誤信息 out varchar2) IS
BEGIN
...
SAVEPOINT A;
update T_A SET COL1 = 10;
COMMIT;
delete FROM T_A where COL1 = 20;
ROLLBACK TO A;
...
EXCEPTION
WHEN OTHERS THEN
...
END;

為什麼是最差:

這種行為是我認為最差實踐中危害最大的一種。隨處可見的事務控制代碼會造成數據不一致,引發的問題難於跟蹤和調試。

解決之道:

由調用者決定何時提交或回滾事務。

對於需要特殊事務管理的過程如記載日志,使用自治事務。

11.不使用綁定變量

影響:性能

症狀:直接使用值而不使用綁定變量進行查詢。尤其是在拼寫sql的程序中,這種情況更突出。

為什麼是最差:

這是一個常見問題,當代碼中大量充斥固定的代碼值時,數據庫引擎每次都需要重新解析,不能使用既有的執行計劃。

解決之道:對於這種經常執行的語句,使用綁定變量而非實際參數值執行。

12.慎用ROWNUM=1

影響:可維護性、數據一致性

症狀:在讀取數據時,有時只需要取一行,這時where條件中就會用到ROWNUM=1。

為什麼是最差:

之所以將這個實踐評成最差,是因為筆者在實際工作中曾經遇到過這類問題,跟蹤和調試都很困難。ROWNUM本身的處理順序是在ORDER BY 之前,所以當ROWNUM=1時產生的結果很可能是隨機的。

解決之道:了解要查詢數據的含義,使用其他條件限制結果集。

13.靈活的動態SQL

影響:可維護性、性能

症狀:execute IMMEDIATE ‘select A FROM TAB1’ INTO v_a;

為什麼是最差:動態SQL失去了編譯期檢查能力,將發生問題的可能性推遲到運行期。動態SQL也不利於優化,因為只有在運行期才能得到完整的SQL語句。

解決之道:盡量避免使用動態SQL,對於易變的業務邏輯可以抽取到中間層實現。

14.對ROWID進行訪問

影響:數據一致性

症狀:使用ROWID作為數據更新、刪除的where條件

為什麼是最差:

ROWID屬於Oracle底層存儲結構,會隨著數據的遷移、導入、導出發生變化,而業務邏輯則不應依賴底層存儲結構。

解決之道:使用主鍵進行數據操作。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved