1. Trang chủ
  2. » Công Nghệ Thông Tin

Oracle Built−in Packages- P45 potx

5 159 0

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 5
Dung lượng 78,55 KB

Nội dung

4.1.2.5.3 Example The following SQL*Plus script displays a screen message and pauses for ten seconds before continuing: prompt ************************************** prompt * This is a very important message prompt * ************************************ BEGIN DBMS_LOCK.SLEEP(10); END; / Applications using resources to which concurrent access is restricted may need to try again later if the resource is busy. The SLEEP procedure provides a mechanism for including low−overhead wait times into PL/SQL programs. After waiting, an application can retry the operation that failed to acquire the busy resource. 4.1.3 Tips on Using DBMS_LOCK In this section I've pulled together a number of best practices for using the DBMS_LOCK package. 4.1.3.1 Named locks or lock ids? Oracle provides two methods of identifying and manipulating user locks: integer lock identifiers and handles for named locks. Using names and lockhandles to identify locks is considered safer than using integer identifiers directly because naming standards can be adopted to virtually guarantee that different applications will not use the same lock for different purposes. Therefore, best practices for using DBMS_LOCK include the use of named locks and lockhandles. 4.1.3.2 Issues with named locks There are a couple of drawbacks to using named locks that are worth pointing out. In particular: • Named locks are recorded in the catalog, and thus may be slower. • The DBMS_LOCK.ALLOCATE_UNIQUE procedure issues a COMMIT. • Applications need to keep track of lockhandles for each named lock used. It is worth investigating these drawbacks and developing techniques to minimize their impact, thus further encouraging the use of named locks. 4.1.3.3 Performance of named locks We can investigate the performance penalty for using named locks, and quantify that penalty in a relatively straightforward manner. Consider the following PL/SQL script: /* Filename on companion disk: lock1.sql */* set timing on set serveroutput on size 100000 DECLARE [Appendix A] What's on the Companion Disk? 4.1.2 The DBMS_LOCK Interface 211 lockname VARCHAR2(30) := 'OPBIP_TEST_LOCK_10'; lockhandle VARCHAR2(128); lockid INTEGER := 99999; call_status INTEGER; timer NUMBER; BEGIN /* || timed test using lockhandles */ timer := DBMS_UTILITY.GET_TIME; DBMS_LOCK.ALLOCATE_UNIQUE(lockname,lockhandle); FOR i IN 1 10000 LOOP call_status := DBMS_LOCK.REQUEST(lockhandle,timeout=>0); call_status := DBMS_LOCK.RELEASE(lockhandle); END LOOP; DBMS_OUTPUT.PUT_LINE('Using lockhandles: '|| TO_CHAR(ROUND((DBMS_UTILITY.GET_TIME−timer)/100,2)) ||' secs'); /* || timed test using lockids */ timer := DBMS_UTILITY.GET_TIME; FOR i IN 1 10000 LOOP call_status := DBMS_LOCK.REQUEST(lockid,timeout=>0); call_status := DBMS_LOCK.RELEASE(lockid); END LOOP; DBMS_OUTPUT.PUT_LINE('Using lockids: '|| TO_CHAR(ROUND((DBMS_UTILITY.GET_TIME−timer)/100,2)) ||' secs'); END; The PL/SQL block reports on the elapsed times to request and release a lock 10,000 times using either a lockhandle or an integer lock identifier. The test yielded the following results on a Personal Oracle7 database with no other activity: SQL> @l2 Using lockhandles: 9.57 secs Using lockids: 3.02 secs PL/SQL procedure successfully completed. real: 12740 SQL> spool off These results confirm that use of lockhandles is significantly slower than use of lock identifiers. However, the results also indicate that the overhead of named locks was less than one−thousandth of a second per usage. Thus, the performance impact of using named locks is negligible and is probably not a legitimate concern for most applications. 4.1.3.4 ALLOCATE_UNIQUE drawbacks The other issues mentioned with named locks are usage related. The ALLOCATE_UNIQUE procedure needs to be called to identify a lockhandle for each named lock. This procedure issues a COMMIT, which presents some usability issues. For one, the procedure cannot be called from a database trigger, so using named locks from a database trigger requires that the lockhandle be acquired outside of the trigger and saved for use in the trigger. Another problem is the COMMIT itself: an application may want to utilize a named lock but not necessarily COMMIT the current transaction. Thus, it is desirable when using named locks to limit the number of calls to ALLOCATE_UNIQUE to exactly one call per named lock used. [Appendix A] What's on the Companion Disk? 4.1.3 Tips on Using DBMS_LOCK 212 4.1.3.5 Optimizing named locks One way to achieve the objective of minimizing calls to ALLOCATE_UNIQUE is to use private package global variables to store lockhandles for each named lock. A function that will return the lockhandle can then be written, calling ALLOCATE_UNIQUE only if the lockhandle has not been previously identified. This technique is illustrated as follows: PACKAGE BODY print_pkg IS /* private globals for lock identification */ printer_lockname VARCHAR2(128) := 'printer_lock'; printer_lockhandle VARCHAR2(128); FUNCTION get_printer_lockhandle RETURN VARCHAR2 IS BEGIN IF printer_lockhandle IS NULL THEN DBMS_LOCK.ALLOCATE_UNIQUE (lockname => printer_lockname ,lockhandle => printer_lockhandle); END IF; RETURN printer_lockhandle; END get_printer_lockhandle; END print_pkg; Using this technique ensures that the ALLOCATE_UNIQUE procedure is called only once per session requiring use of the printer lock. The lock can even be used in a database trigger if the function get_printer_lockhandle has been called prior to the triggering event. One drawback to this technique is code redundancy: each named lock used by an application requires adding a specific package global variable for the lockhandle and an associated function to return it. Referencing a new named lock in an application involves adding a nontrivial amount of code before it can be used. 4.1.3.6 REQUEST or CONVERT? Another usability issue with DBMS_LOCK (not specific to named locks): applications using multiple lock modes need to have intelligence about whether to call the REQUEST function or the CONVERT function. If the user has requested and received a lock in a specific mode, then that mode can only be changed by calling CONVERT. On the other hand, a lock conversion can only take place if it is preceded by a successful call to REQUEST. Getting it right can mean developing code that checks and tracks return codes from the calls to these two procedures. 4.1.4 DBMS_LOCK Examples In response to the usability issues described in the previous section, I have developed a utility package called dblock to simplify, and consequently encourage, the use of named locks in PL/SQL applications. 4.1.4.1 The dblock package The dblock package specification follows: /* Filename on on companion disk: dblock.sql */* CREATE OR REPLACE PACKAGE dblock /* || Adds value to DBMS_LOCK by allowing easier manipulation [Appendix A] What's on the Companion Disk? 4.1.3 Tips on Using DBMS_LOCK 213 || of named locks. Calling programs use lock names only, || corresponding lockhandles are automatically identified, || used and saved for subsequent use. || || || Author: John Beresniewicz, Savant Corp || || 10/26/97: added expiration_secs_IN to lockhandle || 10/21/97: added release || 10/21/97: added dump_lockhandle_tbl || 10/17/97: created || || Compilation Requirements: || || EXECUTE on DBMS_LOCK || EXECUTE on DBMS_SESSION || || Execution Requirements: || */ AS /* variables to anchor other variables */ lockname_var VARCHAR2(128); lockhandle_var VARCHAR2(128); /* || returns TRUE if a COMMIT has taken place between || subsequent calls to the function || NOTE: returns TRUE on first call in session */ FUNCTION committed_TF RETURN BOOLEAN; /* || returns lockhandle for given lockname, only calls || DBMS_LOCK.ALLOCATE_UNIQUE if lockhandle has not been || previously determined */ FUNCTION lockhandle (lockname_IN IN lockname_var%TYPE ,expiration_secs_IN IN INTEGER := 864000) RETURN lockhandle_var%TYPE; /* || returns TRUE if named lock is acquired in mode || specified */ FUNCTION get_lock_TF (lockname_IN IN lockname_var%TYPE ,mode_IN IN INTEGER := DBMS_LOCK.x_mode ,timeout_IN IN INTEGER := 1 ,release_on_commit_TF IN BOOLEAN := FALSE) RETURN BOOLEAN; /* releases named lock */ PROCEDURE release (lockname_IN IN lockname_var%TYPE); /* print contents of lockhandle_tbl for debugging */ PROCEDURE dump_lockhandle_tbl; END dblock; The dblock programs allow the user to identify and acquire locks by name only. Lockhandles for each named lock are managed within the package, transparent to the application. The package associates locknames with lockhandles by using a private global PL/SQL table called lockhandle_tbl. The table is defined as follows: /* rectype to pair handles with names */ [Appendix A] What's on the Companion Disk? 4.1.3 Tips on Using DBMS_LOCK 214 TYPE handle_rectype IS RECORD (name lockname_var%TYPE ,handle lockhandle_var%TYPE ); /* table to store lockhandles by name */ TYPE handle_tbltype IS TABLE OF handle_rectype INDEX BY BINARY_INTEGER; lockhandle_tbl handle_tbltype; 4.1.4.1.1 The lockhandle function The lockhandle function takes a lockname as an IN parameter and returns the associated lockhandle. If the lockhandle has already been identified and stored in the lockhandle_tbl table, it is returned directly. Otherwise, DBMS_LOCK.ALLOCATE_UNIQUE is called to determine the lockhandle, which is then stored in lockhandle_tbl and is also returned to the caller. Here is the body of lockhandle: /* Filename on companion disk: dblock.sql */* FUNCTION lockhandle (lockname_IN IN lockname_var%TYPE ,expiration_secs_IN IN INTEGER := 864000) RETURN lockhandle_var%TYPE IS call_status INTEGER; temp_lockhandle lockhandle_var%TYPE; temp_index BINARY_INTEGER; BEGIN /* || if lockhandle_tbl empty must call ALLOCATE_UNIQUE */ IF lockhandle_tbl.COUNT = 0 THEN DBMS_LOCK.ALLOCATE_UNIQUE (lockname => lockname_IN ,lockhandle => temp_lockhandle ,expiration_secs => expiration_secs_IN); lockhandle_tbl(1).handle := temp_lockhandle; lockhandle_tbl(1).name := lockname_IN; /* || check lockhandle_tbl for matching lockname */ ELSE FOR i IN lockhandle_tbl.FIRST lockhandle_tbl.LAST LOOP IF lockhandle_tbl(i).name = lockname_IN THEN temp_lockhandle := lockhandle_tbl(i).handle; END IF; END LOOP; END IF; /* || if temp_lockhandle still null, call ALLOCATE_UNIQUE || and load entry into lockhandle_tbl */ IF temp_lockhandle IS NULL THEN DBMS_LOCK.ALLOCATE_UNIQUE (lockname => lockname_IN [Appendix A] What's on the Companion Disk? 4.1.4 DBMS_LOCK Examples 215 . together a number of best practices for using the DBMS_LOCK package. 4.1.3.1 Named locks or lock ids? Oracle provides two methods of identifying and manipulating user locks: integer lock identifiers. a lockhandle or an integer lock identifier. The test yielded the following results on a Personal Oracle7 database with no other activity: SQL> @l2 Using lockhandles: 9.57 secs Using lockids:

Ngày đăng: 07/07/2014, 00:20