If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

 
Go Back  dBforums > Database Server Software > DB2 > slow UDF calls (db2v9)

Reply
 
LinkBack Thread Tools Search this Thread Display Modes
  #1 (permalink)  
Old 02-22-10, 07:21
jerzy.burzek jerzy.burzek is offline
Registered User
 
Join Date: Feb 2010
Posts: 4
slow UDF calls (db2v9)

Hello,

i have a little performance problem with SQL UDF:

i've created 2 UDFs:
EAN_128(EanCodeReq VARCHAR(4), Id bigint) returns VARCHAR(32)
and
UDF EAN_128_CHECKSUM(EanCode VARCHAR(32)) RETURNS CHAR(1)

EAN_128 is simple select into table (few hundreds lines) and then addition of checksum to this value. checksum is calculated by calling UDF EAN_128_CHECKSUM (simple while loop, some multiplications and additions)

My problem: EAN_128 is toooooo sloooow, or better said, calling EAN_128 by "select EAN_128(....)" is slow. I've found out, that function itself tooks < 0.05 sec, but calling is expensive, it takes more than 1.5 sec, and it's really annoying.

So my question: How to speed up calling of SQL UDF (precompiling or somthinge like this kind of stuff?)

Thaks in advance
Boris
Reply With Quote
  #2 (permalink)  
Old 02-22-10, 07:49
stolze stolze is offline
Registered User
 
Join Date: Jan 2007
Location: Jena, Germany
Posts: 2,662
Can you show us the code?

The call/invocation of the UDF is not a problem, especially if it is defined as LANGUAGE SQL. The function is compiled into your SQL statement. So if you use procedural logic (BEGIN ... END) instead of set-orientation, you prevent the DB2 optimizer from optimizing your statement overall and force it to a procedural approach.
__________________
Knut Stolze
IBM DB2 Analytics Accelerator
IBM Germany Research & Development
Reply With Quote
  #3 (permalink)  
Old 02-22-10, 08:33
jerzy.burzek jerzy.burzek is offline
Registered User
 
Join Date: Feb 2010
Posts: 4
hello, here's code

hello, code is here:
function FILL_TO_LEN is missing, but it simply use REPEAT to fill-up varchar to desired length...
Code:
CREATE FUNCTION ESO.EAN_128_CHECKSUM(EanCode VARCHAR(32))
	RETURNS CHAR(1)
	LANGUAGE SQL
	DETERMINISTIC

BEGIN ATOMIC
	DECLARE iter_ int;
	DECLARE checkSum_ int;
	DECLARE multi_ int;
	
	IF (EanCode is null) THEN
		signal sqlstate '75004' set message_text = 'EanCode is null';
	END IF;
	
	SET checkSum_ = 0;
	SET multi_ = 3;
	SET iter_ = length(EanCode);
	while iter_ != 0 do
		SET checkSum_ = checkSum_ + (multi_ * + int(substr(EanCode, iter_, 1)));
		IF (multi_ = 3) THEN
			SET multi_ = 1;	
		ELSE
			SET multi_ = 3;
		END IF;
		
		SET iter_ = iter_ - 1;
	end while;
	
	
	SET checkSum_ = MOD(checkSum_, 10);
	IF (checkSum_ = 0) THEN
		SET checkSum_ = 10;
	END IF;
	RETURN CHAR(10 - checkSum_);
	
END@


CREATE FUNCTION ESO.EAN_128(EanCodeReq VARCHAR(4), Id bigint)
	RETURNS VARCHAR(32)
	LANGUAGE SQL
	NOT DETERMINISTIC
	NO EXTERNAL ACTION
	READS SQL DATA
BEGIN ATOMIC

	DECLARE ret_ varchar(32);
	DECLARE strData_ varchar(18);
	DECLARE rowCount_ int;
	DECLARE pocetMiest_ int;
	

	IF Id is null or EanCodeReq is null THEN
		signal sqlstate '75004' set message_text = 'Id/EanCodeReq is null';
	END IF;
	
	SET rowCount_ = (select count(ESO_ID) from NETTOSKO where eso_id=Id);
	
	IF (EanCodeReq = '00') THEN
		SET strData_ = (select ltrim(rtrim(char(Id))) from dummy);
		SET ret_ = '(00)' || ESO_FILL_TO_LEN(strData_, 17, '0', 'L') || EAN_128_CHECKSUM(strData_);
	ELSEIF (EanCodeReq = '01') THEN
		IF (rowCount_ != 1) THEN
			signal sqlstate '75004' set message_text = 'NETTOSKO, must exists exactly 1 row with given id';
		END IF;
		SET strData_ = (select ltrim(rtrim(ZBOZI_OCV)) from nettosko where eso_id=Id);
		SET ret_ = '(01)' || ESO_FILL_TO_LEN(strData_, 13, '0', 'L') || EAN_128_CHECKSUM(strData_);
	END IF;
	
	
	RETURN ret_;

END@
Reply With Quote
  #4 (permalink)  
Old 02-22-10, 09:33
tonkuma tonkuma is online now
Registered User
 
Join Date: Feb 2008
Location: Japan
Posts: 2,194
1) What is your platform?

2)
Quote:
... function itself tooks < 0.05 sec, ...
How did you found that?

3) One possibility may be that "select count(ESO_ID) from NETTOSKO where eso_id=Id" took time.
Do you have an index on eso_id of NETTOSKO?
Reply With Quote
  #5 (permalink)  
Old 02-22-10, 09:45
jerzy.burzek jerzy.burzek is offline
Registered User
 
Join Date: Feb 2010
Posts: 4
1) DB2/LINUXX8664 9.1.0
2) DB2 monitor
3) NETTOSKO is not problem (i am pretty sure, number of lines is < 100 and ESO_ID is PK)

by Db2Monitor it seems, that preparation of UDF is problem, here is line for first run:
select ean_128('00', 1233) from dummy
exec time 0,0094s, execs 1, preps 1

if i re-run select with same values, it fast as hell (cache? pre-compiled?)
select ean_128('00', 1233) from dummy
exec time 0,0065s, execs 1, preps 0

(see preps count)

so clear exec time is always like 0.00xx s, but overall call time is significantly different for 1st call and next calls with same input values (>1.5s vs <0.3s)
Reply With Quote
  #6 (permalink)  
Old 02-22-10, 14:01
stolze stolze is offline
Registered User
 
Join Date: Jan 2007
Location: Jena, Germany
Posts: 2,662
So you have a rather complex, procedural function and that is used in set-oriented context. If you can, you should write it as non-procedural function. (And I have yet to see a function where this is not possible.) This may give you better performance because DB2 can optimize the overall statement instead of feeding every single row through the procedural steps.

p.s: If I take your 0.05s and multiple this by 100 rows, I already have 5s total. So your 1.5s isn't that bad...
__________________
Knut Stolze
IBM DB2 Analytics Accelerator
IBM Germany Research & Development
Reply With Quote
  #7 (permalink)  
Old 02-22-10, 14:50
tonkuma tonkuma is online now
Registered User
 
Join Date: Feb 2008
Location: Japan
Posts: 2,194
Another possibility is buffer hit ratio of NETTOSKO.
If pages of table and/or index were not in buffer at the first access, it would take time to read them.
Second and later, almost pages would be found in buffer.
Reply With Quote
  #8 (permalink)  
Old 02-22-10, 15:05
jerzy.burzek jerzy.burzek is offline
Registered User
 
Join Date: Feb 2010
Posts: 4
really thanks very much for all answers

but i'm not sure if we undertstand each other ;-)

To clarify the background:
This "main" function (EAN_128) is called from our ERP (java/j2ee) each time employee in warehouse scans palette.
After scan, label with barcode is printed, and this print (in fact, some java stuff+ean_128 generation) takes too long time.
After some tests we found out, calling of EAN_128 is problem.

Im java developer, so sorry for my primer, but it seems to me like DB2 "compiles" this function each time it's called. And i've also find out, that more lines with call of another UDF is put into EAN_128, the more time first call takes.

IE:
if i put only this line into EAN_128:
Code:
SET ret_ = '(00)' || ESO_FILL_TO_LEN(strData_, 17, '0', 'L') || EAN_128_CHECKSUM(strData_);
call takes 0.25s

Code:
if (...) then
  SET ret_ = '(00)' || ESO_FILL_TO_LEN(strData_, 17, '0', 'L') || EAN_128_CHECKSUM(strData_);
else if (...)
 SET ret_ = '(00)' || ESO_FILL_TO_LEN(strData_, 17, '0', 'L') ||   EAN_128_CHECKSUM(strData_);
else if (...)
 SET ret_ = '(00)' || ESO_FILL_TO_LEN(strData_, 17, '0', 'L') ||   EAN_128_CHECKSUM(strData_);
end if;
takes 0.7s etc etc.

To sum up:
-EAN_128 is called only once per cca 20-30 seconds, after scan from java code.
-select from nettosko is called only once per call just for data check, and search is indexed
-from my point of view it seems calling UDF within another UDF significantly slows down UDF call

So, this is my problem and i've not found any solution yet
Reply With Quote
  #9 (permalink)  
Old 02-23-10, 17:15
stolze stolze is offline
Registered User
 
Join Date: Jan 2007
Location: Jena, Germany
Posts: 2,662
As I mentioned, a UDF is compiled into the statement in which the function is used. That is done once when the so-called section is being created. You can by-pass this with dynamic SQL, but you don't have that here. What you do have is a bit more complex procedural function. That's the issue you have to address, i.e. optimize the function and what it is doing.

p.s: If you call the function 3 times, the internal logic has to be processed 3 times. Thus, it is not surprising to see the execution time to be about 3x as long compared to a single execution.
__________________
Knut Stolze
IBM DB2 Analytics Accelerator
IBM Germany Research & Development
Reply With Quote
  #10 (permalink)  
Old 02-26-10, 14:33
tonkuma tonkuma is online now
Registered User
 
Join Date: Feb 2008
Location: Japan
Posts: 2,194
Here is a simplified EAN_128_CHECKSUM function.
(from my curiosity.)

Code:
------------------------------ Commands Entered ------------------------------
CREATE FUNCTION ESO.EAN_128_CHECKSUM_simplified(EanCode VARCHAR(32))
	RETURNS CHAR(1)
	LANGUAGE SQL
	DETERMINISTIC
RETURN
SELECT CASE
       WHEN EanCode is NOT null THEN
            CHAR(9 - 
                 MOD( SUM( MOD(3 + 2 * (iter_ + LENGTH(EanCode) ), 4)
                         * INT( SUBSTR(EanCode, iter_, 1) )
                         ) + 9
                    , 10 )
                )
       ELSE
            RAISE_ERROR('75004', 'EanCode is null')
       END
  FROM
       (VALUES      1,  2,  3,  4,  5,  6,  7,  8,  9
             , 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
             , 20, 21, 22, 23, 24, 25, 26, 27, 28, 29
             , 30, 31, 32
       ) p(iter_)
 WHERE iter_ <= LENGTH(EanCode)
;
------------------------------------------------------------------------------
DB20000I  The SQL command completed successfully.
Simple test:
Code:
------------------------------ Commands Entered ------------------------------
SELECT EanCode
     , ESO.EAN_128_CHECKSUM(EanCode) EAN_CHECKSUM
     , ESO.EAN_128_CHECKSUM_simplified(EanCode) simplified
  FROM
       (VALUES '0', '1', '12', '123', '1234', '12345', '123456', '1234567', '12345678', '123456789'
             , '1234567890', '12345678901', '123456789012', '1234567890123', '12345678901234'
             , '123456789012345', '1234567890123456', '12345678901234567', '123456789012345678'
             , '012345', '0012345', '123450', '1234500'
             , '987', '98765', '987654', '987654321'
             , '9876543210', '98765432109', '987654321098'
             , CAST(NULL AS VARCHAR(32) )
       ) q(EanCode)
;
------------------------------------------------------------------------------

EANCODE                          EAN_CHECKSUM SIMPLIFIED
-------------------------------- ------------ ----------
0                                0            0         
1                                7            7         
12                               3            3         
123                              6            6         
1234                             8            8         
12345                            7            7         
123456                           5            5         
1234567                          0            0         
12345678                         4            4         
123456789                        5            5         
1234567890                       5            5         
12345678901                      2            2         
123456789012                     8            8         
1234567890123                    1            1         
12345678901234                   3            3         
123456789012345                  2            2         
1234567890123456                 0            0         
12345678901234567                5            5         
123456789012345678               9            9         
012345                           7            7         
0012345                          7            7         
123450                           3            3         
1234500                          7            7         
987                              4            4         
98765                            3            3         
987654                           5            5         
987654321                        5            5         
9876543210                       5            5         
98765432109                      8            8         
987654321098                     2            2         
SQL0438N  Application raised error or warning with diagnostic text: "EanCode 
is null".  SQLSTATE=75004

SQL0438N  Application raised error or warning with diagnostic text: "EanCode is null                                                       ".
Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On