What is the difference of performance between standalone procedure and packaged procedure? Which will be good performance wise and why? Is there any difference in execution of both?
Tom says:
Always use a package.
Never use a standalone procedure
except for demos, tests and standalone
utilities (that call nothing and are
called by nothing)
There you can also find a very good discussion about their performance. Just search for "performance" on that page.
If still seriously in doubt, you can always test yourself which one is faster. You'll certainly learn something new by doing so.
My take on your question: while it's true that calling package procedures/functions seems to be slower in certain situations than calling standalone procedures/functions, the advantages offered by the additional features available when using packages far outweigh the performance loss. So, just like Tom puts it, use packages.
The link: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:7452431376537
Test code(20 million calls, runstats_pkg is a package I wrote based on the runstats package by Tom Kyte):
CREATE OR REPLACE PACKAGE testperf AS
FUNCTION pow(i INT) RETURN INT;
END;
/
CREATE OR REPLACE PACKAGE BODY testperf AS
FUNCTION pow(i int) RETURN INT AS
BEGIN
RETURN i * i;
END;
END;
/
CREATE OR REPLACE FUNCTION powperf(i INT) RETURN INT AS
BEGIN
RETURN i * i;
END;
/
DECLARE
I INT;
S INT DEFAULT 0;
BEGIN
runstats_pkg.start1;
FOR I IN 1 .. 20000000 LOOP
s := s + (powperf(i) / i);
END LOOP;
runstats_pkg.stop1;
dbms_output.put_line(s);
s := 0;
runstats_pkg.start2;
FOR I IN 1 .. 20000000 LOOP
s := s + (testperf.pow(i) / i);
END LOOP;
runstats_pkg.stop2;
dbms_output.put_line(s);
runstats_pkg.show;
END;
Results(Oracle XE):
Run1 latches total versus runs -- difference and pct
Run1 Run2 Diff Pct
2,491 2,439 -52 102.13%
Run1 ran in 2304 hsecs
Run2 ran in 2364 hsecs
run 1 ran in 97.46% of the time
Results(Oracle 11g R1, different machine):
Run1 latches total versus runs -- difference and pct
Run1 Run2 Diff Pct
2,990 3,056 66 97.84%
Run1 ran in 2071 hsecs
Run2 ran in 2069 hsecs
run 1 ran in 100.1% of the time
So, there you go. Really not much of a difference.
Want data for something more complex that also involves SQL DML? You gotta test it yourself.
There isn't a performance difference except that packages can have state and standalone procedures and functions not.
The use of package is more about ordening and grouping of code. You could see them as an alternative of namespaces.
The primary reason to use packages is they break the dependency chain. For instance if you have two stand-alone procedures, procedure A which calls procedure B and you recompile procedure B you will also need to recompile procedure A. This gets quite complicated as you increase the number of procedures and functions.
If you move these to two to different packages you will not need to recompile them as long as the specification does not change.
There should be no difference between the two.
A major use of packages is to group a set of similar/associeted functions+procedures
The other answers here are all good (e.g. packages have state, they separate interface from implementation, etc).
Another difference is when procedures or packages are wrapped - it is simple to unwrap a procedure, but not a package body.
Related
I have the following table process_table
table
index
TABLE_001
1
TABLE_002
2
TABLE_003
3
TABLE_004
4
And a macro for create tables that i called type_a tables, using lines from process_table.
So, for example, when input was TABLE_001 will generate TABLE_001_A.
%macro create_table_type_a(table_name);
proc sql;
create table temp.&table_name._A as
select
/*some process*/
from &table_name
quit;
%mend create_table_type_a;
And then I run
data _null_;
set process_table;
call execute('%create_table_type_a('||table||')');
run;
Well, I have two doubts.
1 - Does SAS process the macro sequential, one line after other, or is parallelized? I didn't find the answer on internet.
2 - If It was not parallelized, is it possible do it using the same startegy? The tables to be processed are huge, and i dont know how to parallize the process on SAS.
Thanks.
Good question.
No. The macros are run 'sequential', meaning that it runs %create_table_type_a(TABLE_001) before %create_table_type_a(TABLE_002) and so on. This is because Call Executes merely 'stacks' the macro calls in the data step and executes them after the data step has executed.
It is possible, but probably advanced. Reezas question of 'how huge' is pretty relevant before moving into advanced solutions of running macros in parallel.
You could spawn separate SAS processes for each macro call (within its own program), then wait for both to finish before proceeding.
Example
%MACRO SPAWN(PGM,JOBID) ;
systask command "/path/to/sasexe /path/to/programs/&PGM" status=job_&JOBID taskname="job_&JOBID" ;
%MEND ;
/* Run jobs asynchronously */
%SPAWN(Program1.sas,pgm1) ;
%SPAWN(Program2.sas,pgm2) ;
/* Wait for both to finish */
waitfor _ALL_ job_pgm1 job_pgm2 ;
/* ... continue processing ... */
Good Morning
I have oracle 10g when I compile a package I get this error:
PLS-00123: program too large (Diana nodes).
whereas this package has about 80 lines (spec) and 4500 lines in the body.
I have another package with 25k lines in the body but without any error when I compile it.
when I run user_object_size view and I get this:
TYPE SOURCE_SIZE PARSED_SIZE CODE_SIZE ERROR_SIZE
PACKAGE 4206 8260 4271 0
PACKAGE BODY 161144 0 0 42
Note:
1-when I compile this package in oracle 11g I didn't get any error.
2- I try to solve it by using :
ALTER PACKAGE pakage_name COMPILE;
ALTER PACKAGE pakage_name COMPILE DEBUG;
but also it didn't work.
When a PL/SQL block, subprogram, package, or object type exceeds a size limit, you get an error such as PLS-00123: program too large. Typically, this problem occurs with packages or anonymous blocks. With a package, the best solution is to divide it into smaller packages.
Edit after Justin Cave:
Unfortunately, you cannot estimate the number of DIANA nodes from the parsed size. Two program units with the same parsed size might require 1500 and 2000 DIANA nodes, respectively because, for example, the second unit contains more complex SQL statements.
"In other words, just because one package has more lines of PL/SQL code or has a larger parsed size doesn't mean it will have more DIANA nodes."
Source
Look at the following four programs. Build them with Freepascal under Windows and run, redirecting output to any file, and noticing the time it would take.
My results are: all the programs run approximately the same time (about 6 seconds), although the fourth does 100 times more bytes of output. This means that the fourth program runs much faster per byte of output than the tree others.
For the second program the reason of slowness is obvious: the flush call. For the third program the reason is not so obvious, but it may be reasonable to assume that each call to writeln to stdout flushes the output buffer implicitly.
However, it is not clear why the first program is so slower than the fourth. However, the fact that adding flush(output); (see program 2) does not change the timing much seems to mean that FPC flushes the output buffer even after every write, this would explain all the behaviour. This happens only when output is to stdout, even redirected; if I explicitly output to a particular file using assign/rewrite, then the program without flush runs much faster than the program with flush — as should be expected.
Under Linux the running times are 0.01s, 0.65s, 0.01s, 0.30s (output being 100 times bigger). Here clearly flush() slows program down, so under Linux FPC seems not to flush stdout each time.
I have tried to google whether FPC really flushes stdout buffer on every output (be it write or writeln), but have found no information except the comment in the example program from flush function documentation at http://www.freepascal.org/docs-html/rtl/system/flush.html, the comment mentions that a writeln to 'output' always causes a flush [as opposed to write]. However, the example there does not produce the intended output neither under Windows, neither under Linux. In fact, the output seems to be flushed after every write and writeln under Windows, redirected or not, and under Linux too when the output is not redirected. Under Linux with redirected output it seems there is no implicit flushing at all.
So, my questions are:
Is it true that FPC flushes the output buffer after every output, be it write or writeln, on Windows whether the output is redirected to file or not?
If yes, then is there any way to turn this off (some compiler directive, or a workaround)? I still need to keep the output to stdout, so that if I start the program without any redirections, it will output text to the console. (I understand that I might see it appearing at strange times as a result of buffering, it is not a problem.)
If no, then why the first program runs much slower then the fourth?
My system is Windows XP with FPC 2.6.4 under VirtualBox under Kubuntu 14.04, and Kubuntu 14.04 itself with FPC 2.6.2. I had no chance trying to run it on a real Windows machine, but I have some reasons to believe that the situation is the same there.
The programs:
var i,j:integer;
s:string;
begin
for j:=1 to 1000 do begin
for i:=1 to 10 do
write('!');
end;
end.
var i,j:integer;
s:string;
begin
for j:=1 to 1000 do begin
for i:=1 to 10 do begin
write('!');
flush(output);
end;
end;
end.
var i,j:integer;
s:string;
begin
for j:=1 to 1000 do begin
for i:=1 to 10 do
writeln('!');
end;
end.
var i,j:integer;
s:string;
begin
for j:=1 to 10000 do begin
s:='';
for i:=1 to 100 do
s:=s+'!';
write(s);
end;
end.
To prevent flushing of Stdout, insert the following code snippets into your program:
// Textrec is defined in sysutils
uses
sysutils;
// ...
// disabled flushing after each write(ln) on Output, do this at the start of the program
Textrec(Output).FlushFunc:=nil;
But be aware that this means that writelns might not be completed before the program ends.
You can even accelerate the program further by increasing the output buffer of stdout:
// define buffer
var
buf : array[1..100000] of byte;
// ...
// install buffer, do this at the start of the program
SetTextBuf(Output,buf,sizeof(buf));
I'm working on small project in Pascal for school.
I'm using Lazaruz 1.0.2
I have problem with wirteLn function when writing to file.
After some time it just stops writing to file.
Take for example this program:
var oFile: Text;
i: LongWord;
begin
Assign(oFile, 'test.txt');
ReWrite(oFile);
for i:=1 to 4096 do
WriteLn(oFile, 'ThisIsTest');
CloseFile(oFile);//Added as suggested
end.
This is output:
...
4072 ThisIsTest
4073 ThisIsTest
4074 ThisIsTest
4075 ThisIsTe
As you can see it just stops at the middle of sentence and it is not writing all.
All depends on how long is one WriteLn insturction and how many times it is called.
How to fix it?
I tried to use WinApi function from "Windows" module called WriteFile but I failed to pass last 3 arguments to it.
BIG UPDATE
Thanks. That works (Closing file) in that example. But I have little bit more complex program where I'm passing opened file handle to functions that are writing to it via "var". And even after closing that file at the and does nothing. It is strange.
You should Close(oFile) at the end of your program to be sure the output is flushed.
It's also possible to update a file without closing it by adding (in this example)
Flush(oFile);
after a Writeln
This is useful where you might have a long file and want to make sure it's updated regularly. Of course, you should still close the file when finished.
I have an Oracle project that would be a good fit for using GUIDs as a key. I found the following snippet
SET SERVEROUTPUT ON
BEGIN
FOR indx IN 1 .. 5
LOOP
DBMS_OUTPUT.put_line ( SYS_GUID );
END LOOP;
END;
/
From http://feuerthoughts.blogspot.com/2006/02/watch-out-for-sequential-oracle-guids.html
When I run it against my database (I tried it on versions 10g and version 11) I get output like
64FE4083D6BA7CB4E0400F0A0E0A18B0
64FE4083D6BB7CB4E0400F0A0E0A18B0
64FE4083D6BC7CB4E0400F0A0E0A18B0
64FE4083D6BD7CB4E0400F0A0E0A18B0
64FE4083D6BE7CB4E0400F0A0E0A18B0
I.e. the value never changes! Is there something I have to do to set this up to work as expected?
Edit: I am not very observant - the GUIDs are changing, but it looks like I am suffering from the sequential GUID problem that the link above is talking about.
The value does change....
*
64FE4083D6BA7CB4E0400F0A0E0A18B0
64FE4083D6BB7CB4E0400F0A0E0A18B0
64FE4083D6BC7CB4E0400F0A0E0A18B0
64FE4083D6BD7CB4E0400F0A0E0A18B0
64FE4083D6BE7CB4E0400F0A0E0A18B0
*
Seems OK. From the description:
SYS_GUID generates and returns a
globally unique identifier (RAW value)
made up of 16 bytes. On most
platforms, the generated identifier
consists of a host identifier, a
process or thread identifier of the
process or thread invoking the
function, and a nonrepeating value
(sequence of bytes) for that process
or thread.
From your example:
64FE4083D6BA7CB4E0400F0A0E0A18B0
64FE4083D6BB7CB4E0400F0A0E0A18B0
64FE4083D6BC7CB4E0400F0A0E0A18B0
64FE4083D6BD7CB4E0400F0A0E0A18B0
64FE4083D6BE7CB4E0400F0A0E0A18B0
Nobody mentioned anything about the distribution of these GUID values. They should be nonrepeating and they are. Unless you get exactly the same output every time.