Function vs Join
I have a dashboard query from a developer that joins 7 tables and gets data from 5. I have rewritten the query using 5 functions and select data from the main table. Explain plan shows the second query as less costly but sometimes seems longer. Is there a good document that explains the difference and when it is best to use a join and when to use functions?
Also, I use the functions in the select clause not the where clause but have done some testing there as well. Are functions better in the select or where?
thanks
Joins are almost always going to be faster/cheaper. To the best of my knowledge the optimizer cannot see the cost of a pl/sql function and does not include it in it's consideration of explain plans. I'd go back to a join-based approach and then look for places in the explain plan where the cardinality of a step does not match the actual value you know to be true. Jonathan P. Lewis' book on the optimizer is invaluable here. Good luck.
Similar Messages
-
User Defined Function VS join - Performance....
Hi All,
while linking the mulitple table and getting the values ....which one is the best ?
Joining or User defined function.....
single row function
select a.name , get_salary(empid) from emp a;
Note : get_salary function will return the salary from salary tables.
Using joins
select a.name ,b.salary from emp a, salary b
where a.empid=b.empid;
which is the performancewise best ?
also if you give any related document also fine.
Thanks in advance.
Edited by: BASKAR NATARAJAN on Jan 6, 2011 10:09 PMDon't use such functions for joins. The function itself has to query the salary table. It will run the query against the salary table separately for each row that it reads from the emp table. You will end up with multiple recursive calls and possibly inconsistency in the output. (Imagine what would happen if the salary table were updated and commited while this query was running -- some rows would have been read with the pre-update values and others with the updated values).
Specifying the join in the query ensures that a single SQL call is executed and provides read consistency across all the rows it reads. And it is much faster, being one single parse and execute.
Hemant K Chitale
http://hemantoracledba.blogspot.com -
Aggregation Function With Joining
Hi all,
I've the following SQL Query and I want to add a join with it:
SELECT Collected_Goods.ProductId, SUM(Collected_Goods.Amount)
FROM Collected_Goods
GROUP BY Collected_Goods.ProductIdand I want to replace or add (but replace is better) the Collected_Goods.ProductId with a Products.Name where the product name appears in another table called products. Also I want the aggregation function SUM to work on Collected_Goods.ProductId
The FK in Collected_Goods to Products is Collected_Goods.ProductId and Products.Id
Thanks in advance
Edited by: ZiKaS on Dec 30, 2008 2:05 AMThe output for the above one is like this
Collected_Goods.ProductId | SUM(Amount)
1 | 60
2 | 32
. | .
. | .
. | .
I want it to be something link this
Products.Name | SUM(Amount)
Milk | 60
Butter | 32
. | .
. | .
. | . -
Can function in join reduce the performace.
hi,
i have a function fn_oneortworow it accepts one parameter.
i have used it in left join as follows
1)
select * from T
left join fn_oneortworow(@a) a on a.id=t.id
my fear is that it may execute as many times as many rows are there in table "T"
so i have made the query as follows
2)
select * into #temp from join fn_oneortworow(@a)
select * from T
left join #temp a on a.id=t.id
Q1)please tel me that is it correct that in first query function will called as many times as many records are ther in table T?
Q2)and is second formulation is good or should i use the first one. (to imporve the performance)
yours sincerelyIt probably will call the function only once. Since you are always calling it with the same parameter value, SQL knows the the function will always return the same result. It is easy to check by looking at the estimated execution plan, that will
tell you how many times SQL believes it will be called.
Nevertheless, even if it is only called once, I would still do the temp table and load the table with a function call. Then you know for sure the function is only called once.
In addition, if the function can return a lot of rows and id can be a primary key to to #temp table, I would explicitly declare the #temp table with id as a primary key. That will make the join much faster if #temp has many rows. And if id is
not a suitable primary key, but #temp has lots of rows, I would create an index on id to speed up the join.
But the only way to know for sure is to run the possible choices with a realistic set of data and see which method is best.
Tom -
I have three Tables(Emptimesheet,comexpensetable,perexpensestable).I want to show otput something like below,
EmpID,EmpName,StartDate,EndDate,Total,Chotel,CAirfare,Cfuel,WeeklCompanyExpenses,Percompanyexpenses
rightnow in the below query I don't have hotel,airfare,fuel.
select distinct(e.EmpID) ,e.EmpName, e.StartDate,e.EndDate,e.Total,c.WeeklyComtotalExpenses,p.WeeklyPerTotalExpenses
from EmpTimeSheet e left JOIN ComExpensesTable c on c.CExpID=e.EmpID left join PerExpensesTable p ON p.PExpID=e.EmpID
Output for Above query .
EmpID name sd ED Total companEx PerExpense 1 tom 2014-02-02 00:00:00.000 2014-02-08 00:00:00.000 28:30:0 213.00 199.00
3 nick 2014-03-02 00:00:00.000 2014-03-08 00:00:00.000 15:20:0 16.00 NULL
4 john 2014-03-23 00:00:00.000 2014-03-29 00:00:00.000 42:0:0 NULL NULL
5 test 2014-03-09 00:00:00.000 2014-03-15 00:00:00.000 34:15:0 NULL NULL
6 ema 2014-04-13 00:00:00.000 2014-04-19 00:00:00.000 39:0:0 16.00 NULL
Output Emptimesheet
id empname startdate enddate .. total 1 tom 2014-02-02 00:00:00.000 2014-02-08 00:00:00.000 Thurs 2014-02-06 00:00:00.000 Travel Time 28:30:0
3 nick 2014-03-02 00:00:00.000 2014-03-08 00:00:00.000 Mon 2014-03-03 00:00:00.000 Onsite/WalkTesting 40:0:0
4 john 2014-03-23 00:00:00.000 2014-03-29 00:00:00.000 Mon 2014-03-24 00:00:00.000 Onsite/WalkTesting 42:0:0
5 test 2014-03-09 00:00:00.000 2014-03-15 00:00:00.000 Mon 2014-03-10 00:00:00.000 Travel Time , 34:15:0
6 ema 2014-04-13 00:00:00.000 2014-04-19 00:00:00.000 Mon 2014-04-14 00:00:00.000 Equipment Testing 39:0:0
output for ComExpenseTable
CExpID airfare hotel weeklycomexpensetable 1 45.00 34.00 213.00
3 5.00 3.00 16.00
6 5.00 3.00 16.00
output for Perexpensetable
PExpID PerExpenseTable1 Sun 2014-02-02 00:00:00.000 199.00
2 Sun 2014-02-23 00:00:00.000 199.00
below query for sum of indivial expense in company table
select sum(CHotel) as Hotel ,sum(CTransport) as Airfare,sum(CMeals) as Meals,sum(CFuel) as Gas,sum(CTolls),Sum(CParking) as Parking,Sum(CMisc) as Misc ,sum(CMileage) as Mileage from ComExpensesTable where CExpID=1
Now I want to add sum of hotel,transport .. to the below query .I don't know how to do this.Any suggestions please?
select distinct(e.EmpID) ,e.EmpName, e.StartDate,e.EndDate,e.Total,c.WeeklyComtotalExpenses,p.WeeklyPerTotalExpenses
from EmpTimeSheet e left JOIN ComExpensesTable c on c.CExpID=e.EmpID left join PerExpensesTable p ON p.PExpID=e.EmpIDselect
distinct(e.EmpID) ,
e.EmpName,
e.StartDate,
e.EndDate,
e.Total,
ee.Hotel,
ee.Airfare,
c.WeeklyComtotalExpenses,
p.WeeklyPerTotalExpenses
fromEmpTimeSheet e
left JOIN (select CExpID, sum(CHotel) as Hotel ,sum(CTransport) as Airfare,
sum(CMeals) as Meals,sum(CFuel) as Gas,sum(CTolls),
Sum(CParking) as Parking,Sum(CMisc) as Misc ,
sum(CMileage) as Mileage from ComExpensesTable group by CExpID) cleft join // don't need the "left join" hereon c.CExpID=e.EmpID //error
left join PerExpensesTable p ON p.PExpID=e.EmpID -
Hi,
I have a query where one of the values I want to return is the max(date) for a given event and an account from a table. I wrote a simple function to return this but when I include this in my select statement it's very slow.
However if I don't use a function and just add the criteria to the where clause in the query it's much faster.
Can anybody explain this to me?
Thanks
SeanSean:
The performance difference is due to the context switch between SQL and PL/SQL to execute your function, plus the amount of time required to execute your function.
The function would be executed once for each row in the table, so even if it it only takes 0.01 seconds (which is pretty fast), that means one extra second for every hundred rows in the table compared to a simple select. Additionally, depending on what else is in the WHERE clause, the use of the function may preclude the use of a particular index that would be more efficient.
HTH
John -
Where clause in COUNT function and joining two queries
I have a table that I am trying to count the number of course passed, and also list the modules passed as well.
the first problem I am having is what to put in the where variable , so that its not specific to a customer(I can use the query below for a particular customer and a particular course)but I will like a generic query where the result will be distinct in terms
of user and course like the one below
select FirstName,LastName,CourseTitle,Noofmodules, count (Coursecompleted) as modulescompleted from EStudentsprogress where Coursecompleted = '1'and EmailAddress = '[email protected]'
and CourseTitle = 'Microsoft MOS 2010 EXCEL' Group by FirstName, LastName, CourseTitle, Noofmodules ;
How can i make it list the result as above, whereby i dont specify the email address or course title(trying to get the result for all the clients )
. Also I have a query that list the courses that is passed by the customer, I will like the column with the list of courses passed be added to the result above, but as a column for each course.
select FirstName,LastName,CourseTitle, EmailAddress, CourseModule as coursepassed from EStudentsprogress where coursecompleted =1
cheersDo you mean this?
select FirstName,
LastName,
CourseTitle,
Noofmodules,
count (Coursecompleted) as modulescompleted,
STUFF((SELECT ',' + CourseTitle
FROM EStudentsprogress
WHERE FirstName = e.FirstName
AND LastName = e.LastName
WHERE Coursecompleted = '1'
FOR XML PATH('')),1,1,'') AS CoursesCompleted
from EStudentsprogress e
where Coursecompleted = '1'
Group by FirstName, LastName, CourseTitle, Noofmodules ;
If not please provide some sample data and explain the output you want
Please Mark This As Answer if it solved your issue
Please Mark This As Helpful if it helps to solve your issue
Visakh
My MSDN Page
My Personal Blog
My Facebook Page
I AM HAVING Incorrect syntax near the keyword 'WHERE'.
It was a typo
try this
select FirstName,
LastName,
CourseTitle,
Noofmodules,
count (Coursecompleted) as modulescompleted,
STUFF((SELECT ',' + CourseTitle
FROM EStudentsprogress
WHERE FirstName = e.FirstName
AND LastName = e.LastName
AND Coursecompleted = '1'
FOR XML PATH('')),1,1,'') AS CoursesCompleted
from EStudentsprogress e
where Coursecompleted = '1'
Group by FirstName, LastName, CourseTitle, Noofmodules ;
Please Mark This As Answer if it solved your issue
Please Mark This As Helpful if it helps to solve your issue
Visakh
My MSDN Page
My Personal Blog
My Facebook Page
its populating all the result for a particular customer, so i added another clause to it and it worked
select FirstName,
LastName,
CourseTitle,
Noofmodules,
count (Coursecompleted) as modulescompleted,
STUFF((SELECT ',' + CourseTitle
FROM EStudentsprogress
WHERE FirstName = e.FirstName
AND LastName = e.LastName
AND Coursecompleted = '1'
AND CourseTitle = e.CourseTitle
FOR XML PATH('')),1,1,'') AS CoursesCompleted
from EStudentsprogress e
where Coursecompleted = '1'
Group by FirstName, LastName, CourseTitle, Noofmodules ;
but the result of the column is long , so i tried to used the course module, which is a column with numbers, and i tried modifying the query , but i had Error converting data type varchar to float.( i checked and saw that stuff is for concatinating
strings) is there a way around it.
i used
select FirstName,
LastName,
CourseModule,
CourseTitle,
Noofmodules,
count (Coursecompleted) as modulescompleted,
STUFF((SELECT ',' + CourseModule
FROM EStudentsprogress
WHERE FirstName = e.FirstName
AND LastName = e.LastName
AND Coursecompleted = '1'
AND CourseTitle = e.CourseTitle
FOR XML PATH('')),1,1,'') AS CoursesCompleted
from EStudentsprogress e
where Coursecompleted = '1'
Group by FirstName, LastName,CourseModule, CourseTitle, Noofmodules ; -
Join numeric with join numbers function
Hi ! a small question from a guy that didnt use labview for a while !
i need to use the join number function to join two DBL number A and B to form a new number A.B, just like the join numbers function
in the example i would like the results after the join number function to be 1.5
however i understand that the function merge bytes/words together and the result is far from what i expect .... any ways to
A and B are extracted from modbus READ register command and are unsigned 16 bit
seems easy enough but i need a good refreshment on how those bits, bytes and numeric works together.. doh !
thank for everyone involved, Kudos to all labview champions!
Solved!
Go to Solution.
Attachments:
join numbers.png 108 KB
test comm.png 91 KBHi yan,
it seems you really need a refreshment on all those bits/bytes/numeric representations
Typecasting floats (DBL) to U16 will probably never result in the desired value.
Why do you convert your U16 modbus values to DBL anyway? Stick with U16 and you will have no problems using JOIN or any other bit-banging function...
Best regards,
GerdW
CLAD, using 2009SP1 + LV2011SP1 + LV2014SP1 on WinXP+Win7+cRIO
Kudos are welcome -
How to define in different controls device and channels in a DAQmx function?
Hi,
I need to build a vi that permits the user to change the device of a DAQmx acquisition system, although I don't want that the user modify the input channels. I`d like to know if it is possible to define in different controls device and channels.
[]´s
JulianaHello Juliana,
What you would like to do is possible with some simple string manipulation. First you will need a Device Name constant from the DAQmx >> Advanced >> DAQmx Constants & Property Nodes palette. Right-click on the constant and turn it into a control. Then, use a concatenate strings function to join the device name with the rest of the characters you need to define your input channels. Wire the output of the concatenate strings VI to your DAQmx Create Channel VI.
Let me know if you have any questions on this.
Thanks,
Laura -
No more smooth/corner option when joining endpoints in CS5?
OK, I've looked around for the answer. Where did the smooth/corner dialog box go in CS5? Yes, my points are aligned.
ThanksThere are two updates related to Join functionality in CS5.
1. There is a new functionality to join two anchor points of same or different paths by using Cmd/Ctrl+J. You don't even need to select the anchor points - just select the path in full and press Cmd/Ctrl+J. The closest anchor points are detected and joined. A second press of Cmd/Ctrl+J would join the remaining ends. Example:
To join the anchor points of your choice, just select those anchor points and press Cmd/Ctrl+J. Example:
2. The earlier shortcut to join two overlapping anchor points is different in CS5. It used to be Cmd/Ctrl+J, but now it is Cmd/Ctrl+Shift+Opt/Alt+J. The method remains the same i.e. the two anchor point have to be overlapping and selected.
Hope this helps.
Neeraj -
How to pass parameter into extract function (for XMLTYPE)
I have a table PROBLEMXML with XMLTYPE field xml_column. In this column there are several deffinitions for the problem. There is no max amount of deffinitions and it can be no definition at all. I need to return all definitions for every problem as a string wirh definitions separated by ";".
Query
SELECT extract(prob.Def,'/Definitions/Definition[1]/@var') || ';'|| extract(prob.Def,'/Definitions/Definition[2]/@var')
FROM PROBLEMXML j ,
XMLTABLE (
'/problem'
PASSING j.xml_column
COLUMNS probid VARCHAR (31) PATH '/problem/@id',
Def XMLTYPE PATH '/problem/Definitions') prob
where PROBLEM_ID =1;
returns exactly what I want a;m.
But
declare
my_var varchar2(2000) :=null;
n1 number;
n2 number;
begin
n1:=1;
n2:=2;
SELECT extract(prob.Def,'/Definitions/Definition[n1]/@var') || '|'|| extract(prob.Def,'/Definitions/Definition[n2]/@var') into my_var
FROM ETL_PROBLEMXML_STG_T j ,
XMLTABLE (
'/problem'
PASSING j.xml_column
COLUMNS probid VARCHAR (31) PATH '/problem/@id',
Def XMLTYPE PATH '/problem/Definitions') prob
where PROBLEM_ID =1;
dbms_output.put_line(my_var);
end;
returns NULL.
Is there is a way to pass parameter into extract function?I need to return all definitions for every problem as a string wirh definitions separated by ";".In XQuery, there's the handy function "string-join" for that.
For example :
SQL> WITH etl_problemxml_stg_t AS (
2 SELECT 1 problem_id,
3 xmltype('<problem id="1">
4 <Definitions>
5 <Definition var="var1"></Definition>
6 <Definition var="var2"></Definition>
7 <Definition var="var3"></Definition>
8 </Definitions>
9 </problem>') xml_column
10 FROM dual
11 )
12 SELECT j.problem_id,
13 prob.probid,
14 prob.def
15 FROM etl_problemxml_stg_t j,
16 XMLTable(
17 'for $i in /problem
18 return element r
19 {
20 $i/@id,
21 element d { string-join($i/Definitions/Definition/@var, ";") }
22 }'
23 passing j.xml_column
24 columns
25 probid varchar2(30) path '@id',
26 def varchar2(100) path 'd'
27 ) prob
28 ;
PROBLEM_ID PROBID DEF
1 1 var1;var2;var3 -
How to use object type collection in my function?
Hi,
I want to declare Object type collection with in my function like same a Record type collection. But it is saying error like below
PLS-00540: object not supported in this context.
Can anyone tell me how can i resolve this? I don't want to go with create object type functionality.
ThanksHi below is my full query.
SELECT czci.config_hdr_id,
czci.config_rev_nbr,
asoqla.quantity,
(SELECT
node_desc.LOCALIZED_STR
FROM CZ_LOCALIZED_TEXTS node_desc,
CZ_PS_NODES ps_nodes,
CZ_CONFIG_ITEMS czci1
WHERE czci1.config_hdr_id = asoqld.config_header_id
AND czci1.config_rev_nbr = asoqld.config_revision_num
AND node_desc.INTL_TEXT_ID = ps_nodes.INTL_TEXT_ID
AND NVL(node_desc.LANGUAGE,userenv('LANG')) = userenv('LANG')
AND czci1.PS_NODE_ID = ps_nodes.PERSISTENT_NODE_ID
AND ps_nodes.DEVL_PROJECT_ID = (SELECT MAX(DEVL_PROJECT_ID) FROM CZ_PS_NODES WHERE PERSISTENT_NODE_ID = czci.PS_NODE_ID)
AND czci.PARENT_CONFIG_ITEM_ID IN (SELECT sub_sub.CONFIG_ITEM_ID FROM CZ_CONFIG_ITEMS sub_sub
WHERE sub_sub.CONFIG_HDR_ID = asoqld.config_header_id
AND sub_sub.CONFIG_REV_NBR = asoqld.config_revision_num
AND sub_sub.PS_NODE_NAME = 'fittings')) fitting_material,
(SELECT
node_desc.LOCALIZED_STR
FROM CZ_LOCALIZED_TEXTS node_desc,
CZ_PS_NODES ps_nodes,
CZ_CONFIG_ITEMS czci
WHERE czci.config_hdr_id = asoqld.config_header_id
AND czci.config_rev_nbr = asoqld.config_revision_num
AND node_desc.INTL_TEXT_ID = ps_nodes.INTL_TEXT_ID
AND NVL(node_desc.LANGUAGE,userenv('LANG')) = userenv('LANG')
AND czci.PS_NODE_ID = ps_nodes.PERSISTENT_NODE_ID
AND ps_nodes.DEVL_PROJECT_ID = (SELECT MAX(DEVL_PROJECT_ID) FROM CZ_PS_NODES WHERE PERSISTENT_NODE_ID = czci.PS_NODE_ID)
AND czci.PARENT_CONFIG_ITEM_ID IN (SELECT sub_sub.CONFIG_ITEM_ID FROM CZ_CONFIG_ITEMS sub_sub
WHERE sub_sub.CONFIG_HDR_ID = czci.CONFIG_HDR_ID
AND sub_sub.CONFIG_REV_NBR = czci.CONFIG_REV_NBR
AND sub_sub.PS_NODE_NAME = 'tubing')) tubing_material,
NVL((SELECT czci.item_val
FROM cz_config_items czci
WHERE czci.config_hdr_id = asoqld.config_header_id
AND czci.config_rev_nbr = asoqld.config_revision_num
AND czci.value_type_code <> 4
AND czci.ps_node_name = 'control_circuit_name'),
(SELECT
node_desc.LOCALIZED_STR
FROM CZ_LOCALIZED_TEXTS node_desc,
CZ_PS_NODES ps_nodes,
CZ_CONFIG_ITEMS czci
WHERE czci.config_hdr_id = asoqld.config_header_id
AND czci.config_rev_nbr = asoqld.config_revision_num
AND node_desc.INTL_TEXT_ID = ps_nodes.INTL_TEXT_ID
AND NVL(node_desc.LANGUAGE,userenv('LANG')) = userenv('LANG')
AND czci.PS_NODE_ID = ps_nodes.PERSISTENT_NODE_ID
AND ps_nodes.DEVL_PROJECT_ID = (SELECT MAX(DEVL_PROJECT_ID) FROM CZ_PS_NODES WHERE PERSISTENT_NODE_ID = czci.PS_NODE_ID)
AND czci.PARENT_CONFIG_ITEM_ID IN (SELECT sub_sub.CONFIG_ITEM_ID FROM CZ_CONFIG_ITEMS sub_sub
WHERE sub_sub.CONFIG_HDR_ID = czci.CONFIG_HDR_ID
AND sub_sub.CONFIG_REV_NBR = czci.CONFIG_REV_NBR
AND sub_sub.PS_NODE_NAME = 'pneumatic_schematics'))
) schematic_name
FROM aso_quote_lines_all asoqla,
aso_quote_line_details asoqld,
cz_config_items czci
WHERE asoqla.quote_header_id = 58455
AND asoqla.item_type_code = 'MDL'
AND asoqla.quote_line_id = asoqld.quote_line_id
AND asoqld.config_header_id = czci.config_hdr_id
AND asoqld.config_revision_num = czci.config_rev_nbrBelow is my explain plan
call count cpu elapsed disk query current rows
Parse 1 0.11 0.11 0 0 0 0
Execute 2 0.01 0.01 0 0 0 0
Fetch 3 0.06 0.06 0 3429 0 19
total 6 0.18 0.18 0 3429 0 19That's what i am planning to write each select queries in a pipelined function then join all the functions. If i run one each query it is giving less query fetch
Thanks -
Join, the reverse of split?
Hi,
doing split on a string is easy in express... and you get an array as a result...
but there doesn't seem to be a corresponding join where you can add an array of string with a specific string as separator.
So, I should use concat... probably in combination with dolist
but there doesn't seem to be a good join functionality, the join tjat I can call adds spaces and cant be varied it seems
how would you recommend to emulate the normal join in xpress?Replying to my own post then....
Got it to work, finally :-D
given an array, derived from the users view and some properties on each account...
pwsafeNames
<List>
<String>Lighthouse</String>
<String>AD</String>
<String>AD|2</String>
</List>it builds a nice regular expression for my selectall checkbox :D
<String>^resourceAccounts\\..+\\[(Lighthouse|AD|AD\\|2)]\\.selected$</String>with the following code...
<concat>
<s>^resourceAccounts\\..+</s>
<cond>
<gt>
<length>
<ref>pwsafeNames</ref>
</length>
<i>0</i>
</gt>
<block>
<set name='fixed'>
<dolist name='pwname'>
<ref>pwsafeNames</ref>
<cond>
<contains>
<ref>pwname</ref>
<s>|</s>
</contains>
<block>
<concat>
<get>
<split>
<ref>pwname</ref>
<s>|</s>
</split>
<i>0</i>
</get>
<s>\\|</s>
<get>
<split>
<ref>pwname</ref>
<s>|</s>
</split>
<i>1</i>
</get>
</concat>
</block>
<ref>pwname</ref>
</cond>
</dolist>
</set>
<set name='pwarrsize'>
<length>
<ref>fixed</ref>
</length>
</set>
<cond>
<gt>
<ref>pwarrsize</ref>
<i>0</i>
</gt>
<block>
<set name='str'>
<concat>
<s>\\[(</s>
<get>
<ref>fixed</ref>
<i>0</i>
</get>
</concat>
</set>
<set name='counter'>
<i>1</i>
</set>
<while>
<gt>
<ref>pwarrsize</ref>
<ref>counter</ref>
</gt>
<block>
<set name='str'>
<concat>
<ref>str</ref>
<s>|</s>
<get>
<ref>fixed</ref>
<ref>counter</ref>
</get>
</concat>
</set>
<set name='counter'>
<add>
<ref>counter</ref>
<i>1</i>
</add>
</set>
</block>
</while>
<set name='str'>
<concat>
<ref>str</ref>
<s>)]</s>
</concat>
</set>
</block>
<set name='str'>
<concat>
<s></s>
</concat>
</set>
</cond>
<ref>str</ref>
</block>
</cond>
<s>\\.selected$</s>
</concat>To bad this forums code tag cant handle <s> and <i> tags, need to replace all < with &lt;
Edited by: Dhurgan on Nov 13, 2012 11:09 AM -
PipeLine Function Taking time to return Table record
Hi,
I want to use a function in join clause. so i go for pipelined function(using for loop to get record & 1 more loop to fetch in table type variable). i achieved what i required. but problem is it takes much time to fetch data. is there any other approach which returns table records without pipelined function.
please suggest me a better approach as soon as possible.Hi,
Thanks all for the quick response.
I am using oracle 10g
this is the table details & the entire function.
Create object & table type to use in the function
CREATE OR REPLACE TYPE SYSADM.STR_TYPE AS OBJECT(COLUMNVALUE VARCHAR2(8),FromNo Int,ToNo Int)
CREATE OR REPLACE TYPE SYSADM.STR_ARRAY AS TABLE OF STR_TYPE
table involved
View : VesselType
column : Code varchar2(5)
Table : T065_SHIP
column : SKIPS_KODE varchar2(4)
CODE_SHIPTYPE varchar2(5)
Table : SelsKap
column : SELSKAPSKODE varchar2(4)
Table : t041_shiptypeusers
column : Code_ShipType varchar2(5)
USERID varchar2(8)
View : PositionBook
column : VesselCode varchar2(8)
VoyageNo integer
Company varchar2(4)
Table : T62_BRUKER_SELSKAP
column : SELSKAPSKODE varchar2(4)
BRUKER varchar2(8)
Pipelined function
CREATE OR REPLACE FUNCTION SYSADM.TF_ShiporShipTypeByUser
In_UserName IN VARCHAR2,
In_Type IN VARCHAR2,
In_VesselCode IN VARCHAR2,
In_CompanyHistory IN NUMBER DEFAULT 0
RETURN str_array PIPELINED AS
l_ShipTypeUser NUMBER(10,0);
l_CompanyUser NUMBER(10,0);
l_UseCompanyHistory NUMBER(1,0);
l_Snicsacct NUMBER(1,0);
BEGIN
BEGIN
SELECT shiptype_user,
company_user
INTO l_ShipTypeUser,
l_CompanyUser
FROM User_Segregation;
EXCEPTION
WHEN OTHERS THEN
l_ShipTypeUser := NULL;
l_CompanyUser := NULL;
END;
BEGIN
SELECT 1 INTO l_Snicsacct
FROM DUAL
WHERE NOT EXISTS ( SELECT 1 FROM sn_user_cfg WHERE UserID='SNICS' and CfgID='ACCTSYS');
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
IF In_CompanyHistory = 1
THEN
BEGIN
SELECT CfgData
INTO l_UseCompanyHistory
FROM SN_User_Cfg
WHERE CfgID = 'USE COMPANY HISTORY'
AND UserID = 'SNICS';
EXCEPTION
WHEN OTHERS THEN
l_UseCompanyHistory := 0;
END;
END IF;
IF In_UserName = 'SYSADM' OR (l_CompanyUser = 0 AND l_ShipTypeUser = 0)
OR (l_CompanyUser = 1 and l_Snicsacct =1 ) or (In_CompanyHistory = 0 and l_CompanyUser = 1 and In_Type ='ShipType')
OR (l_ShipTypeUser = 1 and In_Type = 'Company')
THEN
BEGIN
IF In_Type = 'ShipType'
THEN
BEGIN
FOR cur IN (SELECT Code ShipCode
, 1 VoyageFrom
, 999999999 VoyageTo
FROM VesselType )
LOOP
PIPE ROW(str_type(cur.ShipCode,cur.VoyageFrom,cur.VoyageTo));
END LOOP;
RETURN;
END;
ELSIF In_Type = 'Ship'
THEN
BEGIN
FOR cur IN (SELECT SKIPS_KODE ShipCode
, 1 VoyageFrom
, 999999999 VoyageTo
FROM T065_SHIP
WHERE SKIPS_KODE = NVL(In_VesselCode,SKIPS_KODE ))
LOOP
PIPE ROW(str_type(cur.ShipCode,cur.VoyageFrom,cur.VoyageTo));
END LOOP;
RETURN;
END;
ELSIF In_Type = 'Company'
THEN
BEGIN
FOR cur IN (SELECT SELSKAPSKODE ShipCode
, NULL VoyageFrom
, NULL VoyageTo
FROM SelsKap)
LOOP
PIPE ROW(str_type(cur.ShipCode,cur.VoyageFrom,cur.VoyageTo));
END LOOP;
RETURN;
END;
END IF;
END;
ELSE
IF In_Type = 'Ship'
THEN
BEGIN
IF l_ShipTypeUser =1
THEN
BEGIN
FOR cur IN (SELECT S.SKIPS_KODE ShipCode
, 1 FromVoyage
, 999999999 ToVoyage
FROM T065_SHIP S
JOIN t041_shiptypeusers U
ON S.CODE_SHIPTYPE = U.Code_ShipType
AND USERID = In_UserName
WHERE S.SKIPS_KODE = NVL(In_VesselCode, S.SKIPS_KODE)
GROUP BY S.SKIPS_KODE)
LOOP
PIPE ROW(str_type(cur.ShipCode,cur.FromVoyage,cur.ToVoyage));
END LOOP;
RETURN;
END;
ELSIF l_CompanyUser = 1
THEN
BEGIN
IF l_UseCompanyHistory = 1 AND In_CompanyHistory = 1
THEN
FOR cur IN (SELECT a.VesselCode ShipCode
, a.VoyageNo VoyageFrom
, a.VoyageNo VoyageTo
FROM PositionBook a
JOIN T62_BRUKER_SELSKAP b
ON a.Company = b.SELSKAPSKODE
AND b.BRUKER = In_UserName
WHERE a.VesselCode = NVL(In_VesselCode, a.VesselCode)
UNION
SELECT a.VesselCode ShipCode
, a.VoyageNo VoyageFrom
, a.VoyageNo VoyageTo
FROM PositionBook a
LEFT JOIN T62_BRUKER_SELSKAP b
ON a.company = b.SELSKAPSKODE
WHERE a.VesselCode = NVL(In_VesselCode, a.VesselCode)
AND b.SELSKAPSKODE IS NULL
GROUP BY a.VesselCode,
a.VoyageNo,
a.VoyageNo)
LOOP
PIPE ROW(str_type(cur.ShipCode,cur.VoyageFrom,cur.VoyageTo));
END LOOP;
RETURN;
ELSE
FOR cur IN (SELECT a.SKIPS_KODE ShipCode
, 1 VoyageFrom
, 999999999 VoyageTo
FROM T065_SHIP a
JOIN T62_BRUKER_SELSKAP b
ON a.Company = b.SELSKAPSKODE
AND b.BRUKER = In_UserName
WHERE a.SKIPS_KODE = NVL(In_VesselCode, a.SKIPS_KODE)
AND NVL(l_UseCompanyHistory,0) = 0
UNION
SELECT a.SKIPS_KODE ShipCode
, 1 VoyageFrom
, 999999999 VoyageTo
FROM T065_SHIP a
LEFT JOIN T62_BRUKER_SELSKAP b
ON a.company = b.SELSKAPSKODE
WHERE a.SKIPS_KODE = NVL(In_VesselCode, a.SKIPS_KODE)
AND b.SELSKAPSKODE IS NULL
GROUP BY a.SKIPS_KODE)
LOOP
PIPE ROW(str_type(cur.ShipCode,cur.VoyageFrom,cur.VoyageTo));
END LOOP;
RETURN;
END IF;
END;
END IF;
END;
ELSIF In_Type = 'ShipType'
THEN
IF l_ShipTypeUser = 1
THEN
BEGIN
FOR cur IN (SELECT S.CODE_SHIPTYPE ShipCode
, 1 VoyageFrom
, 999999999 VoyageTo
FROM T065_SHIP S
JOIN t041_shiptypeusers U
ON S.CODE_SHIPTYPE = U.Code_ShipType
AND USERID = In_UserName
WHERE S.SKIPS_KODE = NVL(In_VesselCode, S.SKIPS_KODE)
GROUP BY S.CODE_SHIPTYPE)
LOOP
PIPE ROW(str_type(cur.ShipCode,cur.VoyageFrom,cur.VoyageTo));
END LOOP;
RETURN;
END;
ELSIF l_CompanyUser = 1
THEN
IF l_UseCompanyHistory = 1 AND In_CompanyHistory = 1
THEN
BEGIN
FOR cur IN (SELECT a.VesselType ShipCode
, a.VoyageNo VoyageFrom
, a.VoyageNo VoyageTo
FROM PositionBook a
JOIN T62_BRUKER_SELSKAP b
ON a.COMPANY = b.SELSKAPSKODE
AND b.BRUKER = In_UserName
WHERE a.VesselCode = NVL(In_VesselCode,a.VesselCode)
UNION
SELECT a.VesselType ShipCode
, a.VoyageNo VoyageFrom
, a.VoyageNo VoyageTo
FROM PositionBook a
LEFT JOIN T62_BRUKER_SELSKAP b
ON a.company = b.SELSKAPSKODE
WHERE a.VesselCode = NVL(In_VesselCode, a.VesselCode)
AND b.SELSKAPSKODE IS NULL
GROUP BY a.VesselType,
a.VoyageNo,
a.VoyageNo)
LOOP
PIPE ROW(str_type(cur.ShipCode,cur.VoyageFrom,cur.VoyageTo));
END LOOP;
RETURN;
END;
ELSE
BEGIN
FOR cur IN (SELECT S.CODE_SHIPTYPE ShipCode
, 1 VoyageFrom
, 999999999 VoyageTo
FROM T065_SHIP S
JOIN T62_BRUKER_SELSKAP b
ON S.company = b.SELSKAPSKODE
AND B.BRUKER = In_UserName
WHERE S.SKIPS_KODE = NVL(In_VesselCode, S.SKIPS_KODE)
AND NVL(l_UseCompanyHistory,0) = 0
UNION
SELECT S.CODE_SHIPTYPE ShipCode
, 1 VoyageFrom
, 999999999 VoyageTo
FROM T065_SHIP S
LEFT JOIN T62_BRUKER_SELSKAP b
ON S.company = b.SELSKAPSKODE
WHERE S.SKIPS_KODE = NVL(In_VesselCode, S.SKIPS_KODE)
AND b.SELSKAPSKODE IS NULL)
LOOP
PIPE ROW(str_type(cur.ShipCode,cur.VoyageFrom,cur.VoyageTo));
END LOOP;
RETURN;
END;
END IF;
END IF;
ELSIF In_Type = 'Company'
THEN
BEGIN
FOR cur IN (SELECT a.SELSKAPSKODE ShipCode
, NULL VoyageFrom
, NULL VoyageTo
FROM Selskap a
JOIN T62_BRUKER_SELSKAP b
ON a.SELSKAPSKODE = b.SELSKAPSKODE
WHERE b.BRUKER = In_UserName
Union All
Select a.SELSKAPSKODE ShipCode
, NULL VoyageFrom
, NULL VoyageTo
From Selskap a
LEFT JOIN T62_BRUKER_SELSKAP b
ON a.SELSKAPSKODE = b.SELSKAPSKODE
Where b.SELSKAPSKODE IS NULL
GROUP BY a.SELSKAPSKODE)
LOOP
PIPE ROW(str_type(cur.ShipCode,cur.VoyageFrom,cur.VoyageTo));
END LOOP;
RETURN;
END;
END IF;
END IF;
END;
select statement which i call the function it takes minimum 6 seconds to execute. It gives 8339 records
WITH deftbl AS ( SELECT /*+ CACHE(deftbl) */
/*+ result_cache */
a.VesselCode,
a.VoyageNo,
CASE a.BallastLeg When 0
THEN MIN(a.ArrivalDate)
ELSE NVL(( SELECT MAX(DepartureDate)
FROM PositionBook b
WHERE b.VesselCode = a.VesselCode
AND b.VoyageNo = (Select MAX(VoyageNo) From PositionBook c Where c.VesselCode = a.VesselCode and c.VoyageNo<a.VoyageNo)
),MIN(a.ArrivalDate))
END AS StartOfVoyage,
MAX(DepartureDate) EndOfVoyage
FROM PositionBook a
JOIN TABLE(*TF_ShiporShipTypeByUser*('BKA', 'Ship', NULL, 1)) D /*Calling the function*/
ON D.ColumnValue = a.VesselCode
AND a.VoyageNo BETWEEN D.FromVoyageNo AND D.ToVoyageNo
GROUP BY VesselCode,VoyageNo,a.BallastLeg )
SELECT /*+ result_cache */
ROW_NUMBER() OVER(PARTITION BY a.VesselCode ORDER BY a.VoyageNo DESC) as "Row"
,a.VesselCode
,v.Name AS VesselName
,a.VoyageNo
,c.StartOfVoyage AS FromPort
,c.EndOfVoyage AS ToPort
/*,a.FROMPORT
,a.TOPORT*/
, CASE
WHEN ( SELECT PortName
FROM PositionBook b
WHERE b.VesselCode = a.VesselCode
AND b.VoyageNo = a.VoyageNo
AND SYSDATE BETWEEN ArrivalDate AND DepartureDate ) IS NOT NULL
THEN ( SELECT FIRST_VALUE(PortName) OVER(PARTITION BY b.vesselcode,b.VoyageNo ORDER BY b.vesselcode,b.VoyageNo,b.ArrivalDate,b.secondarytime)
FROM PositionBook b
WHERE b.VesselCode = a.VesselCode
AND b.VoyageNo = a.VoyageNo
AND SYSDATE BETWEEN ArrivalDate AND DepartureDate
AND ROWNUM=1
WHEN SYSDATE BETWEEN c.StartOfVoyage AND c.EndOfVoyage
THEN ( SELECT 'Steam From '||FIRST_VALUE(UPPER(PortName)) OVER(PARTITION BY b.vesselcode,b.VoyageNo ORDER BY b.vesselcode,b.VoyageNo,b.ArrivalDate desc,b.secondarytime desc)
FROM POSITIONBOOK b
WHERE b.VesselCode = a.VesselCode AND b.VoyageNo = a.VoyageNo
AND b.ArrivalDate<SYSDATE
AND ROWNUM=1
WHEN (c.StartOfVoyage-SYSDATE)>0
THEN 'Voyage Not Started'
WHEN (c.EndOfVoyage-SYSDATE)<0
THEN 'Voyage Completed'
ELSE Null
END "Location"
,( SELECT MIN(b.PortName) KEEP(DENSE_RANK FIRST ORDER BY b.ArrivalDate,b.secondarytime) OVER(PARTITION BY b.VesselCode,b.VoyageNo)
FROM POSITIONBOOK b
WHERE b.VesselCode = a.VesselCode AND b.VoyageNo = a.VoyageNo
AND b.ArrivalDate>SYSDATE
AND ROWNUM=1
) AS NextPort
, ( SELECT MIN(b.ArrivalDate) KEEP(DENSE_RANK FIRST ORDER BY b.ArrivalDate,b.secondarytime) OVER(PARTITION BY b.VesselCode,b.VoyageNo)
FROM POSITIONBOOK b
where b.VesselCode = a.VesselCode AND b.VoyageNo = a.VoyageNo
AND b.ArrivalDate>SYSDATE
AND ROWNUM=1
) AS NextETA
,a.STATUS VoyageStatus
,a.Trade
,UFN_MyVoyConcatinate_Values('FIXNOTE', a.VesselCode, a.VoyageNo) FixNote
,UFN_MyVoyConcatinate_Values('CHARTERER', a.VesselCode, a.VoyageNo) Charterer
,CASE WHEN st.CurrentStatus=0
THEN 1
WHEN st.CurrentStatus=1
THEN 0
ELSE st.CurrentStatus
END AS CurrentStatus
FROM Positionbook a
JOIN deftbl c
ON a.VesselCode = c.VesselCode
AND a.VoyageNo = c.VoyageNo
JOIN Vessel v
ON v.Code = c.VesselCode
LEFT JOIN GTT_VOYAGESTATUS st
ON st.VesselCode = c.Vesselcode
AND st.VoyageNo = c.VoyageNo
GROUP BY a.VesselCode
, v.Name
, a.VoyageNo
, c.StartOfVoyage
, c.EndOfVoyage
/*, a.FROMPORT
, a.TOPORT*/
, a.Status
, a.Trade
, st.CurrentStatus;
Note:
i changed the function without pipelined also. but it doesnt show much difference
non pipelined function
CREATE OR REPLACE FUNCTION TF_ShiporShipTypeByUser_nonp
In_UserName IN VARCHAR2,
In_Type IN VARCHAR2,
In_VesselCode IN VARCHAR2,
In_CompanyHistory IN NUMBER DEFAULT 0
RETURN str_array AS
l_ShipTypeUser NUMBER(10,0);
l_CompanyUser NUMBER(10,0);
l_UseCompanyHistory NUMBER(1,0);
l_Snicsacct NUMBER(1,0);
l_str_array str_array:=str_array();
BEGIN
BEGIN
SELECT shiptype_user,
company_user
INTO l_ShipTypeUser,
l_CompanyUser
FROM User_Segregation;
EXCEPTION
WHEN OTHERS THEN
l_ShipTypeUser := NULL;
l_CompanyUser := NULL;
END;
BEGIN
SELECT 1 INTO l_Snicsacct
FROM DUAL
WHERE NOT EXISTS ( SELECT 1 FROM sn_user_cfg WHERE UserID='SNICS' and CfgID='ACCTSYS');
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
IF In_CompanyHistory = 1
THEN
BEGIN
SELECT CfgData
INTO l_UseCompanyHistory
FROM SN_User_Cfg
WHERE CfgID = 'USE COMPANY HISTORY'
AND UserID = 'SNICS';
EXCEPTION
WHEN OTHERS THEN
l_UseCompanyHistory := 0;
END;
END IF;
IF In_UserName = 'SYSADM' OR (l_CompanyUser = 0 AND l_ShipTypeUser = 0)
OR (l_CompanyUser = 1 and l_Snicsacct =1 ) or (In_CompanyHistory = 0 and l_CompanyUser = 1 and In_Type ='ShipType')
OR (l_ShipTypeUser = 1 and In_Type = 'Company')
THEN
BEGIN
IF In_Type = 'ShipType'
THEN
BEGIN
SELECT STR_TYPE(Code,1,999999999)
BULK COLLECT INTO l_str_array
FROM VesselType;
RETURN l_str_array;
END;
ELSIF In_Type = 'Ship'
THEN
BEGIN
SELECT STR_TYPE(SKIPS_KODE,1,999999999)
BULK COLLECT INTO l_str_array
FROM T065_SHIP
WHERE SKIPS_KODE = NVL(In_VesselCode,SKIPS_KODE);
RETURN l_str_array;
END;
ELSIF In_Type = 'Company'
THEN
BEGIN
SELECT STR_TYPE(SELSKAPSKODE,NULL,NULL)
BULK COLLECT INTO l_str_array
FROM SelsKap;
RETURN l_str_array;
END;
END IF;
END;
ELSE
IF In_Type = 'Ship'
THEN
BEGIN
IF l_ShipTypeUser =1
THEN
BEGIN
SELECT STR_TYPE(S.SKIPS_KODE,1,999999999)
BULK COLLECT INTO l_str_array
FROM T065_SHIP S
JOIN t041_shiptypeusers U
ON S.CODE_SHIPTYPE = U.Code_ShipType
AND USERID = In_UserName
WHERE S.SKIPS_KODE = NVL(In_VesselCode, S.SKIPS_KODE)
GROUP BY S.SKIPS_KODE;
RETURN l_str_array;
END;
ELSIF l_CompanyUser = 1
THEN
BEGIN
IF l_UseCompanyHistory = 1 AND In_CompanyHistory = 1
THEN
SELECT STR_TYPE(ShipCode,VoyageFrom,VoyageTo)
BULK COLLECT INTO l_str_array
FROM ( SELECT a.VesselCode ShipCode
, a.VoyageNo VoyageFrom
, a.VoyageNo VoyageTo
FROM PositionBook a
JOIN T62_BRUKER_SELSKAP b
ON a.Company = b.SELSKAPSKODE
AND b.BRUKER = In_UserName
WHERE a.VesselCode = NVL(In_VesselCode, a.VesselCode)
UNION
SELECT a.VesselCode ShipCode
, a.VoyageNo VoyageFrom
, a.VoyageNo VoyageTo
FROM PositionBook a
LEFT JOIN T62_BRUKER_SELSKAP b
ON a.company = b.SELSKAPSKODE
WHERE a.VesselCode = NVL(In_VesselCode, a.VesselCode)
AND b.SELSKAPSKODE IS NULL
GROUP BY a.VesselCode,
a.VoyageNo,
a.VoyageNo);
RETURN l_str_array;
ELSE
SELECT STR_TYPE(ShipCode,VoyageFrom,VoyageTo)
BULK COLLECT INTO l_str_array
FROM (SELECT a.SKIPS_KODE ShipCode
, 1 VoyageFrom
, 999999999 VoyageTo
FROM T065_SHIP a
JOIN T62_BRUKER_SELSKAP b
ON a.Company = b.SELSKAPSKODE
AND b.BRUKER = In_UserName
WHERE a.SKIPS_KODE = NVL(In_VesselCode, a.SKIPS_KODE)
AND NVL(l_UseCompanyHistory,0) = 0
UNION
SELECT a.SKIPS_KODE ShipCode
, 1 VoyageFrom
, 999999999 VoyageTo
FROM T065_SHIP a
LEFT JOIN T62_BRUKER_SELSKAP b
ON a.company = b.SELSKAPSKODE
WHERE a.SKIPS_KODE = NVL(In_VesselCode, a.SKIPS_KODE)
AND b.SELSKAPSKODE IS NULL
GROUP BY a.SKIPS_KODE);
RETURN l_str_array;
END IF;
END;
END IF;
END;
ELSIF In_Type = 'ShipType'
THEN
IF l_ShipTypeUser = 1
THEN
BEGIN
SELECT STR_TYPE(ShipCode,VoyageFrom,VoyageTo)
BULK COLLECT INTO l_str_array
FROM (SELECT S.CODE_SHIPTYPE ShipCode
, 1 VoyageFrom
, 999999999 VoyageTo
FROM T065_SHIP S
JOIN t041_shiptypeusers U
ON S.CODE_SHIPTYPE = U.Code_ShipType
AND USERID = In_UserName
WHERE S.SKIPS_KODE = NVL(In_VesselCode, S.SKIPS_KODE)
GROUP BY S.CODE_SHIPTYPE);
RETURN l_str_array;
END;
ELSIF l_CompanyUser = 1
THEN
IF l_UseCompanyHistory = 1 AND In_CompanyHistory = 1
THEN
BEGIN
SELECT STR_TYPE(ShipCode,VoyageFrom,VoyageTo)
BULK COLLECT INTO l_str_array
FROM ( SELECT a.VesselType ShipCode
, a.VoyageNo VoyageFrom
, a.VoyageNo VoyageTo
FROM PositionBook a
JOIN T62_BRUKER_SELSKAP b
ON a.COMPANY = b.SELSKAPSKODE
AND b.BRUKER = In_UserName
WHERE a.VesselCode = NVL(In_VesselCode,a.VesselCode)
UNION
SELECT a.VesselType ShipCode
, a.VoyageNo VoyageFrom
, a.VoyageNo VoyageTo
FROM PositionBook a
LEFT JOIN T62_BRUKER_SELSKAP b
ON a.company = b.SELSKAPSKODE
WHERE a.VesselCode = NVL(In_VesselCode, a.VesselCode)
AND b.SELSKAPSKODE IS NULL
GROUP BY a.VesselType,
a.VoyageNo,
a.VoyageNo);
RETURN l_str_array;
END;
ELSE
BEGIN
SELECT STR_TYPE(ShipCode,VoyageFrom,VoyageTo)
BULK COLLECT INTO l_str_array
FROM ( SELECT S.CODE_SHIPTYPE ShipCode
, 1 VoyageFrom
, 999999999 VoyageTo
FROM T065_SHIP S
JOIN T62_BRUKER_SELSKAP b
ON S.company = b.SELSKAPSKODE
AND B.BRUKER = In_UserName
WHERE S.SKIPS_KODE = NVL(In_VesselCode, S.SKIPS_KODE)
AND NVL(l_UseCompanyHistory,0) = 0
UNION
SELECT S.CODE_SHIPTYPE ShipCode
, 1 VoyageFrom
, 999999999 VoyageTo
FROM T065_SHIP S
LEFT JOIN T62_BRUKER_SELSKAP b
ON S.company = b.SELSKAPSKODE
WHERE S.SKIPS_KODE = NVL(In_VesselCode, S.SKIPS_KODE)
AND b.SELSKAPSKODE IS NULL);
RETURN l_str_array;
END;
END IF;
END IF;
ELSIF In_Type = 'Company'
THEN
BEGIN
SELECT STR_TYPE(ShipCode,VoyageFrom,VoyageTo)
BULK COLLECT INTO l_str_array
FROM ( SELECT a.SELSKAPSKODE ShipCode
, NULL VoyageFrom
, NULL VoyageTo
FROM Selskap a
JOIN T62_BRUKER_SELSKAP b
ON a.SELSKAPSKODE = b.SELSKAPSKODE
WHERE b.BRUKER = In_UserName
Union All
Select a.SELSKAPSKODE ShipCode
, NULL VoyageFrom
, NULL VoyageTo
From Selskap a
LEFT JOIN T62_BRUKER_SELSKAP b
ON a.SELSKAPSKODE = b.SELSKAPSKODE
Where b.SELSKAPSKODE IS NULL
GROUP BY a.SELSKAPSKODE);
RETURN l_str_array;
END;
END IF;
END IF;
END;please kindly provide me your valuable suggestions
Edited by: ganex27lin on Mar 16, 2011 1:54 AM -
Performance ... normal selects and the same selects in functions
Hi there,
hope you guys can help me a little.
We use a bunch of dictionary tables to map certain values to IDs. In the "real" data tables we save the IDs instead of the values themselves.
Those tables are usually pretty small.
Normally we would join these tables into our selects, such as this:
select ...
from data_table d,
lookup_table l
where d.l_id=l.id
But we also got some functions we use to lookup these values to have simple selects:
select ..., my_function(l_id)
from data_table
Or for reverse lookup:
select ...
from data_table
where l_id=my_function(l_id)
Do you know, if smaller selects capsuled in functions are more or less performant then simply joining these tables into the big selects?
Sometimes we also use small statements on large tables (4.000.000 records) ... sometimes we use them in functions as well ...
select bla
from large_table
where id=...
Thanks for your hints,
SteffHow you did your tests?
A short conclusion of test below:
I've created 2 tables one base table and one lookup table.
Then created function to get lookup value from lookup table.
then run select to get all lookup values from base table using join and using function.
Join needed 0.01 sec, function needed at least 2.08 secs.
Then I've created an anonymous script to loop through all base values and get aproprite lookup values using function and using join and compared results using runstats.
As a result join performed at more than 2 times faster and required more than 2 times less latches.
and here is the listing
SQL> create table lookup_table (
2 lkp_id number not null,
3 lkp_val varchar2(10) not null);
Table created.
Elapsed: 00:00:00.00
SQL> alter table lookup_table add constraint lkp_pk primary key (lkp_id);
Table altered.
Elapsed: 00:00:00.00
SQL>
SQL> insert into lookup_table select rownum, substr(object_name, 1, 10) from dba_objects;
42221 rows created.
Elapsed: 00:00:00.05
SQL> create or replace function get_lkp_value (in_id number) return varchar2
2 is
3 ret lookup_table.lkp_val%TYPE;
4 begin
5 select lkp_val into ret from lookup_table where lkp_id = in_id;
6 return ret;
7 end;
8 /
Function created.
Elapsed: 00:00:00.01
SQL> create table base_table (
2 bas_id number not null,
3 bas_lkp_id number not null,
4 bas_data varchar2(1000) not null);
Table created.
Elapsed: 00:00:00.00
SQL>
SQL> insert into base_table select rownum, rownum, object_name
2 from dba_objects where rownum <= 42221;
42221 rows created.
Elapsed: 00:00:00.05
SQL> alter table base_table add constraint bas_pk primary key (bas_id);
Table altered.
Elapsed: 00:00:00.02
SQL> alter table base_table add constraint bas_lkp_fk foreign key (bas_lkp_id)
2 references lookup_table (lkp_id);
Table altered.
Elapsed: 00:00:00.01
SQL> create index bas_lkp_idx on base_table (bas_lkp_id);
Index created.
Elapsed: 00:00:00.02
SQL> exec dbms_stats.gather_table_stats(user, 'lookup_table');
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.01
SQL> exec dbms_stats.gather_table_stats(user, 'base_table');
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.02
SQL> select count(distinct lkp_val) from (
2 select bas_id, bas_data, get_lkp_value(bas_lkp_id) lkp_val
3 from base_table);
COUNT(DISTINCTLKP_VAL)
13622
Elapsed: 00:00:03.01
SQL> /
COUNT(DISTINCTLKP_VAL)
13622
Elapsed: 00:00:02.08
SQL> /
COUNT(DISTINCTLKP_VAL)
13622
Elapsed: 00:00:03.01
SQL> select count(distinct lkp_val) from (
2 select bas_id, bas_data, lkp_val
3 from base_table, lookup_table
4 where bas_lkp_id = lkp_id);
COUNT(DISTINCTLKP_VAL)
13622
Elapsed: 00:00:00.01
SQL> /
COUNT(DISTINCTLKP_VAL)
13622
Elapsed: 00:00:00.01
SQL> ed
Wrote file afiedt.buf
1 declare
2 cursor c1 (in_id in number) is
3 select bas_id, bas_data, lkp_val
4 from base_table, lookup_table
5 where bas_lkp_id = lkp_id
6 and bas_id = in_id;
7 val1 c1%ROWTYPE;
8 cursor c2 (in_id in number) is
9 select bas_id, bas_data, get_lkp_value(bas_lkp_id)
10 from base_table
11 where bas_id = in_id;
12 val2 c2%ROWTYPE;
13 begin
14 runstats_pkg.rs_start;
15 for i in 1..42220 loop
16 open c1(i);
17 fetch c1 into val1;
18 close c1;
19 end loop;
20 runstats_pkg.rs_middle;
21 for i in 1..42220 loop
22 open c2(i);
23 fetch c2 into val1;
24 close c2;
25 end loop;
26 runstats_pkg.rs_stop;
27* end;
SQL> /
Run1 ran in 390 hsecs
Run2 ran in 910 hsecs
run 1 ran in 42,86% of the time
Name Run1 Run2 Diff
LATCH.kwqit: protect wakeup ti 0 1 1
LATCH.spilled msgs queues list 0 1 1
STAT...change write time 0 1 1
LATCH.active checkpoint queue 1 3 2
LATCH.cache buffer handles 24 26 2
LATCH.process allocation 0 2 2
STAT...cleanout - number of kt 3 5 2
STAT...consistent gets - exami 253,323 253,325 2
STAT...consistent gets 253,323 253,325 2
STAT...calls to kcmgcs 3 5 2
STAT...active txn count during 3 5 2
LATCH.session timer 1 3 2
LATCH.event group latch 0 2 2
LATCH.channel handle pool latc 0 4 4
LATCH.transaction allocation 0 4 4
STAT...db block gets 520 524 4
LATCH.list of block allocation 0 4 4
LATCH.process group creation 0 4 4
LATCH.dummy allocation 0 4 4
LATCH.post/wait queue 11 16 5
LATCH.Consistent RBA 18 24 6
LATCH.mostly latch-free SCN 18 24 6
STAT...consistent changes 510 516 6
STAT...session logical reads 253,843 253,849 6
STAT...db block changes 1,020 1,026 6
LATCH.lgwr LWN SCN 18 24 6
LATCH.channel operations paren 4 12 8
LATCH.user lock 0 8 8
LATCH.simulator lru latch 13 2 -11
LATCH.sequence cache 56 71 15
LATCH.redo writing 59 82 23
LATCH.enqueues 30 60 30
STAT...hot buffers moved to he 31 0 -31
LATCH.messages 100 149 49
LATCH.cache buffers lru chain 91 33 -58
LATCH.session idle bit 230 290 60
LATCH.SQL memory manager worka 136 223 87
STAT...free buffer requested 91 4 -87
STAT...shared hash latch upgra 87 0 -87
STAT...physical reads 87 0 -87
LATCH.checkpoint queue latch 69 181 112
LATCH.session allocation 44 178 134
LATCH.redo allocation 622 819 197
LATCH.undo global data 61 263 202
LATCH.dml lock allocation 92 312 220
LATCH.row cache enqueue latch 356 580 224
LATCH.simulator hash latch 12,430 12,204 -226
LATCH.row cache objects 360 626 266
LATCH.enqueue hash chains 141 477 336
STAT...recursive cpu usage 259 596 337
STAT...Elapsed Time 392 913 521
LATCH.library cache pin alloca 402 1,100 698
LATCH.cache buffers chains 257,991 260,038 2,047
STAT...calls to get snapshot s 42,221 84,441 42,220
STAT...execute count 42,221 84,441 42,220
STAT...recursive calls 126,662 168,882 42,220
STAT...session pga memory 0 65,536 65,536
LATCH.shared pool 44,133 213,801 169,668
LATCH.library cache pin 86,473 256,185 169,712
LATCH.library cache 87,511 342,530 255,019
Run1 latches total versus runs -- difference and pct
Run1 Run2 Diff Pct
491,506 1,090,381 598,875 45.08%
PL/SQL procedure successfully completed.
Elapsed: 00:00:13.06Gints Plivna
http://www.gplivna.eu
Maybe you are looking for
-
How do i change apple id without password . I have tried to change it but the email gets sent to a generic address. Can anyone please help ? Thank you ! <Email Edited by Host>
-
Hello I Have need one clarifcation when we create a Service PO with Item categoryD then in Item detail screen in Delivery Tab the Unlimted check box is flaged automaticaly why, what is use of it? in standard Po it will not flaged this check box why?
-
Well, this has been going on for a long time and I've had my absolute fill of it tonight. I have purchased a large collection of movies from iTunes that for mainly the reason that I have a new computer, my old films no longer exist as downloaded iTun
-
What is the role of a SRM functional consultant during SP15 upgradation?
Hi, We are currently on SRM server 5.5, support pack 11 and planning to upgrade to SP15. As a functional consultant, what are the checks need to be performed? Got OSS note's side effect report from SAP which consists of apprx 60 notes that need to be
-
The next code works fine with Flash Player 6 and Action Script 1 but I'm trying to get it work on Flash Player 8 and Action Script 2. Any help, thanks in advance. onClipEvent (load) { accel1 = 0.8; rate1 = 0.1; trace(_x); _root.xkoord1 = 0; onClipEve