Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programming PL SQL.doc
Скачиваний:
3
Добавлен:
01.07.2025
Размер:
5.06 Mб
Скачать

19.7.1.3 Defer execution until needed

Just because you have a declaration section positioned "before" your execution section does not mean that you should declare all your program's variables there. It is quite possible that some actions taken in that section (the declarations themselves or the defaulting code) are not always needed and should not always be run on startup of the block.

Consider the following block of code:

PROCEDURE always_do_everything (criteria_in IN BOOLEAN)

IS

big_string VARCHAR2(32767) := ten_minute_lookup (...);

big_list

list_types.big_strings_tt := two_minute_number_cruncher (...);

BEGIN

IF NOT criteria_in

THEN

use_big_string (big_string);

process_big_list (big_list);

ELSE

/* Nothing big going on here */

...

END IF;

END;

In this code, I declare a big string and call a function that takes ten minutes of elapsed time and lots of CPU time to assign the default value to that string. I also declare and populate a collection (via a package-declared table TYPE), again relying on a CPU-intensive function to populate that list. I take both of these steps because I know that I need to use the big_string and big_list data structures in my programs.

Then I write my execution section, run some initial tests, and everything seems OK—except that it runs too slowly. I decide to walk through my code to get a better understanding of its flow. I discover something very interesting: my program always declares and populates the big_string and big_list structures, but it doesn't use them unless criteria_in is FALSE, which is usually not the case!

Once I have this more thorough understanding of my program's logical flow, I can take advantage ofnested blocks (an anonymous block defined within another block of code) to defer the penalty of initializing my data structures until I am sure I need them. Here is a reworking of my inefficient program:

PROCEDURE only_as_needed (criteria_in IN BOOLEAN)

IS

PROCEDURE heavy_duty_processing

IS

big_string VARCHAR2 (32767)

:= ten_minute_lookup (...);

big_list list_types.big_strings_tt

:= two_minute_number_cruncher (...);

BEGIN

use_big_string (big_string);

process_big_list (big_list);

END;

BEGIN

IF NOT criteria_in

THEN

heavy_duty_processing;

ELSE

/* Nothing big going on here */

...

END IF;

END;

One other advantage of this approach is that when the nested block terminates, the memory associated with its data structures is released. This behavior would come in handy in the above example if I needed to perform more operations in my program after I am done with my "big" variables. With the former approach, memory would not have been released until the entire program was done.

19.7.2 Be a Good Listener

Are you a good listener? When people speak, do you expend more effort figuring out how you will respond than attempting to truly understand what they mean? Being a good listener is, I believe, a sign of respect for others and a skill we should all cultivate. (I know that I need to make more of an effort in this area myself.)

Being a good listener is also a critical skill when a programmer uncovers requirements from users and translates them into code. All too often, we hear what our users say but we do not really listen. The consequence is that we often end up writing code that does not meet their requirements or does so in an inefficient manner. Consider the following example:

CREATE OR REPLACE PROCEDURE remove_dept (

deptno_in IN emp.deptno%TYPE,

new_deptno_in IN emp.deptno%TYPE)

IS

emp_count NUMBER;

BEGIN

SELECT COUNT(*) INTO emp_count

FROM emp WHERE deptno = deptno_in;

IF emp_count > 0

THEN

UPDATE emp

SET deptno = new_deptno_in

WHERE deptno = deptno_in;

END IF;

DELETE FROM dept WHERE deptno = deptno_in;

END drop_dept;

This procedure drops a department from the department table, but first reassigns any employees in that department to another. The logic of the program is as follows: If I have any employees in that department, perform the update effecting the transfer. Then delete that row from the department table.

Can you see what is wrong here? Actually, this program is objectionable at two different levels. Most fundamentally, a good part of the code is unnecessary. If an UPDATE statement does not identify any rows to change, it does not raise an error; it simply doesn't do anything. So the remove_dept procedure could be reduced to nothing more than:

CREATE OR REPLACE PROCEDURE remove_dept (

deptno_in IN emp.deptno%TYPE,

new_deptno_in IN emp.deptno%TYPE)

IS

emp_count NUMBER;

BEGIN

UPDATE emp

SET deptno = new_deptno_in

WHERE deptno = deptno_in;

DELETE FROM dept WHERE deptno = deptno_in;

END drop_dept;

Suppose, however, that it really is necessary to perform the check for existing employees. Let's take a closer look at what really is going on here. The question I need to answer is "Is there at least one employee?", yet if you look closely at my code, the question I really answer is "How many employees do I have?" I can transform the answer to that question into the answer to my first question with a Boolean expression (emp_count > 0), but in the process I may have gone overboard in my processing.

There are, in fact, a number of ways to answer the question "Do I have at least one of X?" The path you take may have a serious impact on performance. For a comparison of these different approaches, try out the atleastone.sql script available from the O'Reilly site.

The beginning of the atleastone.sql script creates a rather large copy of the employee table; this code is commented out to avoid the overhead of this step when the table is already in place. You will want to uncomment this section the first time you try the script.

Here's my conclusion from running this script: using a straightforward explicit cursor to fetch a single time and determine that there is at least one item is a very efficient (though not quite the most efficient) and very readable approach. Most importantly, it is also responsive to the question being asked—that is, the user requirements.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]