Dear Oracle technologists,
Sorry about the delay in
getting out this newsletter. I've
been a bit busy. We held the first-ever PL/SQL-exclusive conference,
Oracle PL/SQL Programming 2005, in early November and I've been
recovering/catching up ever since. This newsletter will be a bit
briefer than usual, but I hope still very useful.
Upcoming
training
opportunities
In case you are wondering
how you can get your next live fix
of "PL/SQL by Feuerstein" education, please check out the following:
November
17, NYC: the NYOUG is sponsoring
a day-long "21st Century PL/SQL"
seminar.
November
30, December 1, December 6, ONLINE!
Quest is offering a series of on-line webinars. These "Focus On"
programs offer in-depth instructions on collections, native dynamic
SQL, and exception handling. It will be a great way to strengthen your
knowledge of PL/SQL without even having to leave your cubicle!
OPP2005 - first PL/SQL
conference a big success!
On November 2nd and 3rd,
over 170 Oracle technologists
gathered at the Wyndham O'Hare for the first ever Oracle PL/SQL
Programming conference: OPP2005. Participants attended sessions on
In-Depth PL/SQL, the View from Redwood Shores, and Multimedia
Programming with PL/SQL. We ended the conference with a fascinating
presentation by Bryn Llewellyn, Oracle PL/SQL Product Manager, giving
us a glimpse of future directions for the PL/SQL language.
This conference also
served as a birthday party for Oracle
PL/SQL
Programming the Book, and you
can't have a party without a cake!
Links to all conference
presentations are available at http://oracleplsqlprogramming.com/opp2005_agenda.php.
Evaluations are still
rolling in, but attendees made very
clear that they would like to see another PL/SQL conference in 2006.
That was very gratifying to me, as I have never before organized a
conference, from beginning to end (and couldn't have done it without
the professional help of Your Conference
Connection).
Oracle PL/SQL for DBAs
O'Reilly Media just
released my latest book on PL/SQL: Oracle
PL/SQL
for DBAs. Actually, the main
author is Arup
Nanda. I am the secondary
co-author, seeing as I am not even a
DBA! Although primarily a tool for developers, PL/SQL has also become
an
essential tool for database administration, as DBAs take increasing
responsibility for site performance and as the lines between developers
and DBAs blur. Until now, there has not been a book focused squarely on
the language topics of special concern to DBAs Oracle
PL/SQL for
DBAs
fills the gap. Covering the latest Oracle version, Oracle Database 10g
Release 2 and packed with code and usage examples, it contains:
-
Extensive coverage of
security topics for DBAs: Encryption
(including both traditional methods and Oracle's new Transparent Data
Encryption, TDE); Row-Level Security (RLS), Fine-Grained Auditing
(FGA); and random value generation
I expect this book to be
very handy even for developers. Some
of the content of this book appears in the fourth edition of Oracle
PL/SQL
Programming, but in abbreviated
form. If you truly need to get a
handle on security issues, encryption or job scheduling, this book will
take you a long way.
Tip of the Month: Index
collections by strings
If you are running
Oracle9i Database Release 2 or above, you
can advantage of a very, very cool feature: associative arrays that are
indexed by strings, rather than integer. I have found this technique
handy in a number of situations, most recently when I wanted to cache
the contents of a relational table in a collection and access rows by a
GUID (globally unique identifier) primary key value. These GUIDs are
strings, not integers, so the typical INDEX BY BINARY_INTEGER won't
help me out much. String-based indexing is also very helpful when you
need to index information by more than one value, as is the case with a
concatenated index.
In the package definition
below, I am loading the contents of
my books table (code to define this table is available in this
newsletter's download) into a
series of associative arrays that
emulate the primary key and unique indexes on the table. The unique
index arrays rely on string-based indexes. By caching the table
contents in collections, I can greatly speed up the performance of
querying against this static copy of the table. Very handy when running
batch processes against large tables!
For some additional
background on this technique, check out my Brave
New World seminar.
CREATE OR REPLACE PACKAGE summer_reading IS SUBTYPE author_title_t IS VARCHAR2 (32767);
-- Guarantee uniqueness of concatenated values -- from the index with a delimiter. FUNCTION author_title ( author_in books.author%TYPE ,title_in books.title%TYPE ,delim_in IN VARCHAR2 := '^' ) RETURN author_title_t;
FUNCTION onebook ( book_id_in IN books.book_id%TYPE ) RETURN books%ROWTYPE;
FUNCTION onebook ( isbn_in IN books.isbn%TYPE ) RETURN books%ROWTYPE;
FUNCTION onebook ( author_in books.author%TYPE ,title_in books.title%TYPE ) RETURN books%ROWTYPE;
-- Only call if you want to RE-load the data. -- This is invoked automatically in the initialization section. PROCEDURE load_arrays;
PROCEDURE set_reload_interval ( interval_in IN NUMBER );
PROCEDURE set_reload_interval ( interval_in IN INTERVAL DAY TO SECOND ); END summer_reading; /
CREATE OR REPLACE PACKAGE BODY summer_reading IS g_last_load DATE; -- Auto reload turned off g_reload_interval INTERVAL DAY TO SECOND := NULL;
TYPE book_id_aat IS TABLE OF books%ROWTYPE INDEX BY PLS_INTEGER;
TYPE isbn_aat IS TABLE OF books.book_id%TYPE INDEX BY books.isbn%TYPE;
TYPE author_title_aat IS TABLE OF books.book_id%TYPE INDEX BY author_title_t;
books_aa book_id_aat; by_isbn_aa isbn_aat; by_author_title_aa author_title_aat;
FUNCTION author_title ( author_in books.author%TYPE ,title_in books.title%TYPE ,delim_in IN VARCHAR2 := '^' ) RETURN author_title_t IS BEGIN RETURN UPPER (author_in) || delim_in || UPPER (title_in); END;
PROCEDURE load_arrays IS BEGIN DBMS_OUTPUT.put_line ( 'Reloading books arrays at ' || TO_CHAR (SYSDATE, 'HH24:MI:SS') );
FOR rec IN (SELECT * FROM books) LOOP books_aa (rec.book_id) := rec; by_isbn_aa (rec.isbn) := rec.book_id; by_author_title_aa ( author_title (rec.author, rec.title)) := rec.book_id; END LOOP;
g_last_load := SYSDATE; END load_arrays;
PROCEDURE set_reload_interval ( interval_in IN INTERVAL DAY TO SECOND ) IS BEGIN g_reload_interval := interval_in; END;
PROCEDURE set_reload_interval ( interval_in IN NUMBER ) IS BEGIN g_reload_interval := NUMTODSINTERVAL (interval_in, 'SECOND'); END;
FUNCTION reload_needed RETURN BOOLEAN IS retval BOOLEAN := g_reload_interval IS NOT NULL; l_date DATE := SYSDATE; BEGIN IF retval THEN retval := NUMTODSINTERVAL (l_date - g_last_load, 'DAY') > g_reload_interval; END IF;
RETURN retval; END;
FUNCTION onebook ( book_id_in IN books.book_id%TYPE ) RETURN books%ROWTYPE IS BEGIN IF reload_needed THEN load_arrays; END IF;
RETURN books_aa (book_id_in); END;
FUNCTION onebook ( isbn_in IN books.isbn%TYPE ) RETURN books%ROWTYPE IS l_book_id books.book_id%TYPE := by_isbn_aa (isbn_in); BEGIN RETURN onebook (l_book_id); END;
FUNCTION onebook ( author_in books.author%TYPE ,title_in books.title%TYPE ) RETURN books%ROWTYPE IS BEGIN RETURN onebook ( by_author_title_aa ( author_title (author_in, title_in))); END; BEGIN load_arrays; END summer_reading; /
Useful Code of the
Month: Emulate primary key and unique indexes
The summer reading
package shown above demonstrates a very
powerful technique: emulation of primary key and unique indexes in
collections, relying on string-based indexes for concatenated indexes
and string values in the key or index definition. Unfortunately, you
have to write a whole bunch of code to take advantage of this technique
-- or do
you?
Ah the suspense...the
answer is: no, you do not
have to write all that code
yourself! Instead, you can download, install and run the genaa.sql
script. It will create the genaa
procedure, which has the following
header:
PROCEDURE genaa ( -- name of table against which to generate the emulation code tab_in IN VARCHAR2 -- owner of table, default to USER , sch_in IN VARCHAR2 := NULL -- delimiter to use with concatenated indexes , delim_in IN VARCHAR2 := '^' -- name of package generated, default is [table_name]_cache , pkg_name_in IN VARCHAR2 := NULL -- enter TRUE to display a trace of processing , trace_in IN BOOLEAN := FALSE -- enter TRUE to send package def to file, otherwise to screen , to_file_in IN BOOLEAN := TRUE -- name of file, default is [table_name]_cache.pkg , file_in IN VARCHAR2 := NULL -- directory to which the file will be written , dir_in IN VARCHAR2 := 'DEMO' )
In other words: give the
genaa procedure the name of the
table, and it will generate all the code you need to emulate the
primary key and unique indexes. It will automatically figure out the
correct kind of indexing datatype to use. It even includes logic to
automatically refresh your cache after a specified amount of time!
|