CONNECT BY PRIOR and performance of Query Plan
Anyone,
I have an SQL Statement that is performing rather slow and I am trying to figure out if I could optimize it. Here is the SQL:
SELECT/*+ index(MAXIMO.EQNDX99) */
maximo.equipment.eqnum, maximo.equipment.parent, LEVEL
FROM maximo.equipment@maxi_dblink
WHERE parent = :b1 CONNECT BY PRIOR eqnum = parent
ORDER BY eqnum, LEVELAfter some research in this board I followed some advice found to create an index on the table for both the eqnum, parent and the parent, eqnum. EQNDX99 and EQNDX999 respectivley.
Now the Qery Plan for this query shows the following:
SELECT STATEMENT (REMOTE)
SORT (ORDER BY)
FILTER
CONNECT BY
INDEX (FAST FULL SCAN) EQNDX99 (NON-UNIQUE)
TABLE ACESS (BY USER ROWID) EQUIPMENT
INDEX (RANGE SCAN) EQNDX999 (NON-UNIQUE)Now it appears to be using both indexes but it is operating through a DBLINK. Is there anything else I can do to increase performance??? It appears to be using the HINT through the link as well.
Thanks for any help I can get,
David Miller
how long does it takes to complete the query?
Similar Messages
-
Connect by prior subquery - performance problem
Hello,
I have some data which is organized in a folder tree. The requeriement is to be able to search from any subfolder and down.
/Documents
___Folder A
______Doc A
______Doc B
___Folder B
______Doc C
______Doc D
The folder structure is defined in a table called CORNERS where the records(=folders) has a ID/PARENTID relationsship to describe the folder structure.
Another table, called MASTER, contains the main content. Each item has a CORNERID value which defined in which subfolder the document is located.
MASTER
ID CORNERID TITLE INDEX_URL
100 2 Doc A http://xxx/yy.com
101 2 Doc B http://xxz/yy.com
102 3 Doc C http://xyz/yy.com
103 3 Doc D http://xyz/zz.com
CORNERS
ID PARENTID NAME
1 Documents
2 1 Folder A
3 1 Folder B
MASTER table has ~50000 records
CORNERS has ~900 records.
Analyzed nighly and stats are fresh.
Indexes defined:
CORNERS_ID_PARENT_IDX corners(id,parentid)
CORNERS_PARENT_ID_IDX corners(parentid,id)
MASTER_ID_CORNERID_IDX master(id,cornerid)
MASTER_CORNERID_ID_IDX master(cornerid,id)
Oracle Text index (URL based) on MASTER.INDEX_URL
Foreign key defined:
MASTER.CORNERID references CORNERS.ID
If I do a search without involving the hierarchy, then the search runs pretty fast:
SQL> SELECT COUNT(*) FROM (SELECT a.id, a.cornerid FROM MASTER a WHERE (CONTAINS(title,'$ADS AND {S} AND $PARAMETER',2) > 1 OR CONTAINS(index_url,'$ADS AND {S} AND $PARAMETER',1) > 1) );
COUNT(*)
5125
Elapsed: 00:00:00.14
Execution Plan
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1354 Card=1 Bytes=15
8)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'MASTER' (Cost=1354 Car
d=758 Bytes=119764)
3 2 BITMAP CONVERSION (TO ROWIDS)
4 3 BITMAP OR
5 4 BITMAP CONVERSION (FROM ROWIDS)
6 5 SORT (ORDER BY)
7 6 DOMAIN INDEX OF 'MASTER_TITLE_IDX' (Cost=470)
8 4 BITMAP CONVERSION (FROM ROWIDS)
9 8 SORT (ORDER BY)
10 9 DOMAIN INDEX OF 'MASTER_IDX' (Cost=650)
Statistics
1462 recursive calls
0 db block gets
5507 consistent gets
347 physical reads
0 redo size
380 bytes sent via SQL*Net to client
503 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
1 rows processed
SQL>
BUT, if I add a subquery to limit the search to a certain folder tree (which includes ~200 nodes), then the performance is really badly affected. The subquery itself runs fast - around 0.07 seconds, but together with the rest of the query the preformance is really bad:
SQL> SELECT COUNT(*) FROM (SELECT a.id, a.cornerid FROM MASTER a WHERE (CONTAINS(title,'$ADS AND {S} AND $PARAMETER',2) > 1 OR CONTAINS(index_url,'$ADS AND {S} AND $PARAMETER',1) > 1) AND cornerid IN ( SELECT ID FROM corners START WITH id = 2434 CONNECT BY PRIOR id = parentid) );
COUNT(*)
942
Elapsed: 00:00:01.83
Execution Plan
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=118 Card=1 Bytes=175
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'MASTER' (Cost=19 Card=
1 Bytes=162)
3 2 NESTED LOOPS (Cost=118 Card=8 Bytes=1400)
4 3 VIEW OF 'VW_NSO_1' (Cost=2 Card=6 Bytes=78)
5 4 SORT (UNIQUE)
6 5 CONNECT BY (WITH FILTERING)
7 6 NESTED LOOPS
8 7 INDEX (UNIQUE SCAN) OF 'SYS_C002969' (UNIQUE
) (Cost=1 Card=1 Bytes=4)
9 7 TABLE ACCESS (BY USER ROWID) OF 'CORNERS'
10 6 NESTED LOOPS
11 10 BUFFER (SORT)
12 11 CONNECT BY PUMP
13 10 INDEX (RANGE SCAN) OF 'CORNERS_PARENT_ID_IDX
' (NON-UNIQUE) (Cost=2 Card=6 Bytes=48)
14 3 INDEX (RANGE SCAN) OF 'MASTER_CORNERID_ID_IDX' (NON-
UNIQUE) (Cost=1 Card=38)
Statistics
29267 recursive calls
0 db block gets
55414 consistent gets
140 physical reads
0 redo size
380 bytes sent via SQL*Net to client
503 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
12 sorts (memory)
0 sorts (disk)
1 rows processed
I've tried an alternative syntax, instead of the IN clause like this:
SELECT COUNT(*) FROM (
WITH folders AS (
SELECT ID
FROM CORNERS
START WITH ID=2434
CONNECT BY PRIOR ID= PARENTID
SELECT a.id
FROM MASTER a, folders b
WHERE a.cornerid = b.id
AND CONTAINS(index_url,'$ADS AND {S} AND $PARAMETER',1) > 1);
It does runfaster, but still takes around 1 second.
Any suggestion on how to make this run faster!?
Thanks in advance!
-Matshow long does it takes to complete the query?
-
Help regarding CONNECT BY PRIOR AND LEVEL
Hi
I need to retreive all the employees that are at the least level under a particular employee. Assume basic emp table.
I have been using CONNECT BY PRIOR
select mgr,empno,ename, level from emp
start with empno=7839
connect by prior empno=mgrOUTPUT:
MGR EMPNO ENAME LEVEL
7839 KING 1
7839 7566 JONES 2
7566 7788 SCOTT 3
7788 7876 ADAMS 4
7566 7902 FORD 3
7902 7369 SMITH 4
7839 7698 BLAKE 2
7698 7499 ALLEN 3
7698 7521 WARD 3
7698 7654 MARTIN 3
7698 7844 TURNER 3
7698 7900 JAMES 3
7839 7782 CLARK 2
7782 7934 MILLER 3The Output i require should be
MGR EMPNO ENAME LEVEL
7788 7876 ADAMS 4
7902 7369 SMITH 4
7698 7499 ALLEN 3
7698 7521 WARD 3
7698 7654 MARTIN 3
7698 7844 TURNER 3
7698 7900 JAMES 3
7782 7934 MILLER 3Also if i change the empno then i need to get only the employees under that employee only.
Thanks in Advance,
G.Vamsi Krishnaoracle_for_dude wrote:
can you explain what is this query doing
SQL> select mgr,empno,ename, level
2 from emp
3 where level > 2
4 start with empno = 7566
5 connect by prior empno = mgr;
MGR EMPNO ENAME LEVEL
7788 7876 ADAMS 3
7902 7369 SMITH 37566 in scott.emp table is employee_id of JONES, It's displaying the selected columns for all the employees in the sub-tree starting with Jones, not including Jones (who is at LEVEL=1) and the people who report directly to Jones (LEVEL=2).
>
>
Thanks in advance -
Connect By Prior - poor performance
Hi,
SELECT parent_id, parent_Val_id,child_value,chld_chr_id FROM (
SELECT
mo.parent_id ,
mo.parent_Val_id,
mo.child_value,
mo.chld_chr_id ,
leaf_param
FROM char_Value mo
,char_pairing CP
,Hierarcy_t hier
, ref_v reft
where CP.chr_pair_id =mo.chr_pair_id and CP.hier_id = hier.hier_id
and hier.Hierarcy_typ_ref_id = reft.ref_id
START WITH mo.parent_id = 1888
AND mo.parent_Val_id = 11738095
CONNECT BY NOCYCLE PRIOR mo.chld_chr_id = mo.parent_id
AND PRIOR mo.child_value = mo.parent_Val_id
) where leaf_param='Y';
Rows In the table
char_Value - 62606506
char_pairing - 16225
Hierarcy_t - 106
ref_v - 746
Plan hash value: 4222991804
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | 49 | 2744 | 67966 (1)| 00:00:02 |
|* 1 | VIEW | | 49 | 2744 | 67966 (1)| 00:00:02 |
|* 2 | CONNECT BY WITH FILTERING | | | | | |
| 3 | NESTED LOOPS | | | | | |
| 4 | NESTED LOOPS | | 48 | 3840 | 33830 (1)| 00:00:01 |
|* 5 | HASH JOIN | | 137 | 6987 | 44 (3)| 00:00:01 |
|* 6 | HASH JOIN | | 1 | 42 | 8 (13)| 00:00:01 |
| 7 | NESTED LOOPS | | 6 | 204 | 4 (0)| 00:00:01 |
| 8 | TABLE ACCESS BY INDEX ROWID| REFERENCE_TYP | 1 | 24 | 1 (0)| 00:00:01 |
|* 9 | INDEX UNIQUE SCAN | REFERENCE_TYP_IND | 1 | | 0 (0)| 00:00:01 |
|* 10 | TABLE ACCESS BY INDEX ROWID| REFERNCE | 6 | 60 | 3 (0)| 00:00:01 |
|* 11 | INDEX RANGE SCAN | REF_AK1_IDX | 6 | | 1 (0)| 00:00:01 |
| 12 | TABLE ACCESS STORAGE FULL | Hierarcy | 106 | 848 | 3 (0)| 00:00:01 |
| 13 | TABLE ACCESS STORAGE FULL | char_pairing | 16191 | 142K| 36 (0)| 00:00:01 |
|* 14 | INDEX RANGE SCAN | char_pairing_IND | 4119 | | 9 (0)| 00:00:01 |
|* 15 | TABLE ACCESS BY INDEX ROWID | char_Value | 1 | 29 | 262 (0)| 00:00:01 |
|* 16 | HASH JOIN | | 1 | 106 | 34135 (1)| 00:00:01 |
| 17 | NESTED LOOPS | | 43 | 4171 | 34098 (1)| 00:00:01 |
|* 18 | HASH JOIN | | 43 | 2924 | 33840 (1)| 00:00:01 |
| 19 | TABLE ACCESS STORAGE FULL | Hierarcy | 106 | 848 | 3 (0)| 00:00:01 |
|* 20 | HASH JOIN | | 300 | 18000 | 33836 (1)| 00:00:01 |
| 21 | NESTED LOOPS | | 48 | 2400 | 33831 (1)| 00:00:01 |
| 22 | TABLE ACCESS BY INDEX ROWID| REFERENCE_TYP | 1 | 24 | 1 (0)| 00:00:01 |
|* 23 | INDEX UNIQUE SCAN | REFERENCE_TYP_IND | 1 | | 0 (0)| 00:00:01 |
| 24 | CONNECT BY PUMP | | | | | |
|* 25 | TABLE ACCESS STORAGE FULL | REFERNCE | 739 | 7390 | 5 (0)| 00:00:01 |
|* 26 | TABLE ACCESS BY INDEX ROWID | char_Value | 1 | 29 | 6 (0)| 00:00:01 |
|* 27 | INDEX RANGE SCAN | char_Value_IND | 4 | | 2 (0)| 00:00:01 |
| 28 | TABLE ACCESS STORAGE FULL | char_pairing | 16191 | 142K| 36 (0)| 00:00:01 |
Is there any alternate to modify the query.
Please provide the solution
Regards
Sudhakar P.Please describe your tables and indexes.
In the mean time, I'll take a stab on the information we have so far. I don't know where "leaf_param" comes from.create index cv_connect_indx on char_Value(parent_id, parent_Val_id, chld_chr_id, child_value, chr_pair_id);
SELECT parent_id, parent_Val_id, child_value, chld_chr_id
FROM (SELECT mo.parent_id,
mo.parent_Val_id,
mo.chld_chr_id,
mo.child_value,
mo.chr_pair_id
FROM char_Value mo
START WITH mo.parent_id = 1888
AND mo.parent_Val_id = 11738095
CONNECT BY NOCYCLE PRIOR mo.chld_chr_id = mo.parent_id
AND PRIOR mo.child_value = mo.parent_Val_id
) c,
char_pairing CP, Hierarcy_t hier, ref_v reft
where CP.chr_pair_id = c.chr_pair_id
and CP.hier_id = hier.hier_id
and hier.Hierarcy_typ_ref_id = reft.ref_id
and leaf_param = 'Y';Edited by: Adam Martin on Feb 13, 2012 1:53 PM -
Reading the DAX query plan of a trace against a query on a Tabular model
Hi,
I'm monitoring a Tabular model queried by an Excel workbook. Inside SQL Profiler I've choosen as events the VertiPaq SE Query End, the Query End and the DAX Query Plan. But this last event isn't more readable.
How can I read the info collected in the DAX Query Plan in a simple manner?
ThanksIt is fairly complex to read the DAX Query Plan. I don't think there are currently tools that make it easier to read. (Watch the DAX Studio project on codeplex as they may include tools for this in the future.) I would recommend you review the Tabular
Performance Guide which has a good explanation of the DAX Query Plan:
http://aka.ms/ASTabPerf2012
http://artisconsulting.com/Blogs/GregGalloway -
Hi
I have a table in Oracle which is a recursive (pigs ear) hierarchy. I want to be able to use this in disco and "wander" down the hierarchies using connect by prior and start with. Can this be done?Not sure if you're referring to a specific table.
However, I have create a report in the past that simply pointed to a database view we created that used the connect by idea and all worked well.
So, if you have a database view that returns what you're needing then no problem. -
'CONNECT BY PRIOR..START WITH' clause Usage
Hi All,
Could you please let me know the usage of 'connect by prior...start with' clause.
I only know that it helps for hierarchial retrival,but not aware of details.
Can someone provide the use with example for the same.
On searching on the net,I have seen numerous examples but none of them could explain it properly and everywhere the same SCOTT/TIGER schemas EMP and MGR table's example is given which is not enough explanatory.
Thanks in advance...
Aashish S.suppose u need to get all employees in a company in a hirerchical manner
ie presdent then mgrs
then employeess reporting to them
this can be done using connect by prior and start by
select empname from emp
connect by prior empno=mgrno
start with mgrno is null -
Connect By Prior - Performance and Missing Parent
I have to say right off the top that I'm not a SQL expert by any means so please be gentle. :)
I have a query that runs through a Bill Of Materials that works except for two things:
1. It is horribly slow - 60-90 seconds to return under 300 rows.
2. It doesn't show the parent node.
I'm looking into indexes now, so I'm not sure if there's an issue there or not. As far as #2 goes, there are two tables that are involved: BOM_STRUCTURES_B and BOM_COMPONENTS_B. Every item below the parent node has a BOM_COMPONENTS_B record. If a BOM_COMPONENT is a parent to other components, there is a BOM_STRUCTURES_B record for that. (In other words, everything that is a parent has a BOM_STRUCTURES_B record, and all the children have a BOM_COMPONENTS_B record that point to the parent - BOM_STRUCTURES_B). The only exception to this is the parent node, which only has a BOM_STRUCTURES_B record (it is NOT a child, so there is no BOM_COMPONENTS_B record). I've added a "UNION" to the bottom of the script below, but it changes my sort order completely.
Here's my script:
select bbm.assembly_item_id,
bic.component_item_id Component ,
msi.segment1 Name,
msi.description Description,
bic.component_quantity Quantity,
lpad( ' ', level*2 ) || level MyLevel
from bom_structures_b bbm
,bom_components_b bic
, mtl_system_items msi
where bbm.bill_Sequence_id = bic.bill_sequence_id
and msi.inventory_item_id = bic.component_item_id
and msi.organization_id = bbm.organization_id
start with bbm.assembly_item_id = 271962
and bbm.organization_id = 85
connect by prior bic.component_item_id = bbm.assembly_item_id;
I've hard-coded "start with bbm.assembly_item_id = 271962", as it is the root node of a tree (BOM).
Here's my structure, with extra fields clipped out:
DBMS_METADATA.GET_DDL('TABLE','BOM_STRUCTURES_B','BOM')
CREATE TABLE "BOM"."BOM_STRUCTURES_B"
( "ASSEMBLY_ITEM_ID" NUMBER,
"ORGANIZATION_ID" NUMBER NOT NULL ENABLE,
"COMMON_BILL_SEQUENCE_ID" NUMBER NOT NULL ENABLE,
) PCTFREE 20 PCTUSED 80 INITRANS 10 MAXTRANS 255 NOCOMPRESS LOGGING
STORAGE(INITIAL 131072 NEXT 131072 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 4 FREELIST GROUPS 4 BUFFER_POOL DEFAULT)
TABLESPACE "APPS_TS_TX_DATA"
DBMS_METADATA.GET_DDL('TABLE','BOM_COMPONENTS_B','BOM')
CREATE TABLE "BOM"."BOM_COMPONENTS_B"
("COMPONENT_ITEM_ID" NUMBER,
"BILL_SEQUENCE_ID" NUMBER NOT NULL ENABLE,
"PARENT_BILL_SEQ_ID" NUMBER,
) PCTFREE 35 PCTUSED 50 INITRANS 10 MAXTRANS 255 NOCOMPRESS LOGGING
STORAGE(INITIAL 131072 NEXT 131072 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 4 FREELIST GROUPS 4 BUFFER_POOL DEFAULT)
TABLESPACE "APPS_TS_TX_DATA"
DBMS_METADATA.GET_DDL('TABLE','MTL_SYSTEM_ITEMS_B','INV')
CREATE TABLE "INV"."MTL_SYSTEM_ITEMS_B"
( "INVENTORY_ITEM_ID" NUMBER NOT NULL ENABLE,
"ORGANIZATION_ID" NUMBER NOT NULL ENABLE,
"DESCRIPTION" VARCHAR2(240),
) PCTFREE 10 PCTUSED 70 INITRANS 10 MAXTRANS 255 NOCOMPRESS LOGGING
STORAGE(INITIAL 131072 NEXT 131072 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 4 FREELIST GROUPS 4 BUFFER_POOL DEFAULT)
TABLESPACE "APPS_TS_TX_DATA"
The relationship between the tables is:
A BOM_STRUCTURES_B has many BOM_COMPONENTS_B where BOM_COMPONENTS_B.PARENT_BILL_SEQ_ID = BOM_STRUCTURES_B.BILL_SEQUENCE_ID. Both BOM_STRUCTURES_B.ASSEMBLY_ITEM_ID and BOM_COMPONENTS_B.COMPONENT_ITEM_ID are related to a single MTL_SYSTEM_ITEMS_B.INVENTORY_ITEM_ID.
Thanks to anyone who can help with this horrible problem I've been fighting with for much too long! :)
Thank you!
SteveDue to an error in the otn forums (*), this got posted to the wrong forum, sorry for that, I'll repost in the correct one.
*) For the forum admins: I was browsing the SQL/PLSQL forum, clicked on 'new message', got the login prompt, logged in, and apparently this got me to the application server forum for some reason. -
In our application, we have a lot of 'trees' in our data (parent/child relationships within a table). We rely heavily on 'connect by prior' to search through the trees, to find for example values that are defined in one of the parents ('inheritance').
Lately however, we've been eliminating connect by priors wherever we can lately, because performance is dramatic. No matter what indexes we use, we keep getting full tablescans on large tables because of the connect by priors. Views with 2 connect by priors are deadly for performance.
What is a good way to optimize connect by priors?
As an example of why we use connect by prior, consider this:
table A
ID PARENT_ID NAME LENGTH
1 NULL root 10
2 1 child NULLWe consider record 2 'derived' from record 1, inheriting its length. The alternative for connect by prior is to populate the child length whenever the master length changes, and this is what we do in most situations now, but it's hell to keep track of this. If a record changes, you would still have to go down the tree to change all child lengths etc, so we rather use connect by prior.
Any ideas?Ivo, would you please post the table definition (if different than your example), the actual list of indexes, a sample query, and the explain plan for that query?
I use hierarchical queries extensively on tables with millions of rows. They work very well if all the pieces are in place. Let's see if we can get your queries humming... -
Performance problem: Query explain plan changes in pl/sql vs. literal args
I have a complex query with 5+ table joins on large (million+ row) tables. In it's most simplified form, it's essentially
select * from largeTable large
join anotherLargeTable anothr on (anothr.id_2 = large.pk_id)
join...(other aux tables)
where large.pk_id between 123 and 456;
Its performance was excellent with literal arguments (1 sec per execution).
But, when I used pl/sql bind argument variables instead of 123 and 456 as literals, the explain plan changes drastically, and runs 10+ minutes.
Ex:
CREATE PROCEDURE runQuery(param1 INTEGER, param2 INTEGER){
CURSOR LT_CURSOR IS
select * from largeTable large
join anotherLargeTable anothr on (anothr.id_2 = large.pk_id)
join...(other aux tables)
where large.pk_id between param1 AND param2;
BEGIN
FOR aRecord IN LT_CURSOR
LOOP
(print timestamp...)
END LOOP;
END runQuery;
Rewriting the query 5 different ways was unfruitful. DB hints were also unfruitful in this particular case. LargeTable.pk_id was an indexed field as were all other join fields.
Solution:
Lacking other options, I wrote a literal query that concatenated the variable args. Open a cursor for the literal query.
Upside: It changed the explain plan to the only really fast option and performed at 1 second instead of 10mins.
Downside: Query not cached for future use. Perfectly fine for this query's purpose.
Other suggestions are welcome.AmandaSoosai wrote:
I have a complex query with 5+ table joins on large (million+ row) tables. In it's most simplified form, it's essentially
select * from largeTable large
join anotherLargeTable anothr on (anothr.id_2 = large.pk_id)
join...(other aux tables)
where large.pk_id between 123 and 456;
Its performance was excellent with literal arguments (1 sec per execution).
But, when I used pl/sql bind argument variables instead of 123 and 456 as literals, the explain plan changes drastically, and runs 10+ minutes.
Ex:
CREATE PROCEDURE runQuery(param1 INTEGER, param2 INTEGER){
CURSOR LT_CURSOR IS
select * from largeTable large
join anotherLargeTable anothr on (anothr.id_2 = large.pk_id)
join...(other aux tables)
where large.pk_id between param1 AND param2;
BEGIN
FOR aRecord IN LT_CURSOR
LOOP
(print timestamp...)
END LOOP;
END runQuery;
Rewriting the query 5 different ways was unfruitful. DB hints were also unfruitful in this particular case. LargeTable.pk_id was an indexed field as were all other join fields.
Solution:
Lacking other options, I wrote a literal query that concatenated the variable args. Open a cursor for the literal query.
Upside: It changed the explain plan to the only really fast option and performed at 1 second instead of 10mins.
Downside: Query not cached for future use. Perfectly fine for this query's purpose.
Other suggestions are welcome.Best wild guess based on what you've posted is a bind variable mismatch (your column is declared as a NUMBER data type and your bind variable is declared as a VARCHAR for example). Unless you have histograms on the columns in question ... which, if you're using bind variables is usually a really bad idea.
A basic illustration of my guess
http://blogs.oracle.com/optimizer/entry/how_do_i_get_sql_executed_from_an_application_to_uses_the_same_execution_plan_i_get_from_sqlplus -
Please help. Thank you for your time and expertise.
Prerequisites: sql query needs to be a view. Real view is more than recursion. It computes location path, is used in JOINs and returns this path.
Problem: no matter what I tried, sql server does not produce 'index seek' when using variable but does with literal.
See full reproduction code below.
I expect that query SELECT lcCode FROM dbo.vwLocationCodes l WHERE l.lcID = @lcID will seek UNIQUE index but it does not.
I tried these:
1. Changing UX and/or PK to be CLUSTERED.
2. query OPTION(RECOMPILE)
3. FORCESEEK on view
4. SQL Server 2012/2014
5. Wrap it into function and CROSS APPLY. On large outer number of rows this just dies, no solution
but to no avail. This smells like a bug in SQL Server. I am seeking your confirmation.
I am thinking it is a bug as variable value is high-cardinality, 1, and query is against unique key. This must produce single seek, depending if clustered or nonclustred index is unique
Thanks
Vladimir
use tempdb
BEGIN TRAN
-- setup definition
CREATE TABLE dbo.LocationHierarchy(
lcID int NOT NULL ,
lcHID hierarchyid NOT NULL,
lcCode nvarchar(25) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
lcHIDParent AS lcHID.GetAncestor(1) PERSISTED,
CONSTRAINT PK_LocationHierarchy_lcID PRIMARY KEY NONCLUSTERED (lcID ASC),
CONSTRAINT UX_LocationHierarchy_pltID_lcHID UNIQUE CLUSTERED (lcHID ASC)
-- add some data
INSERT INTO dbo.LocationHierarchy
VALUES
(1, '/', 'A')
,(2, '/1/', 'B')
,(3, '/1/1/', 'C')
,(4, '/1/1/1/', 'D')
--DROP VIEW dbo.vwLocationCodes
GO
CREATE VIEW dbo.vwLocationCodes
AS
WITH ru AS
SELECT
lh.lcID
,lh.lcCode
,lh.lcHID
,CAST('/' + lh.lcCode + '/' as varchar(8000)) as LocationPath
-- to support recursion
,lh.lcHIDParent
FROM dbo.LocationHierarchy lh
UNION ALL
SELECT
ru.lcID
,ru.lcCode
,ru.lcHID
,CAST('/' + lh.lcCode + ru.LocationPath as varchar(8000)) as LocationPath
,lh.lcHIDParent
FROM dbo.LocationHierarchy lh
JOIN ru ON ru.lcHIDParent = lh.lcHID
SELECT
lh.lcID
,lh.lcCode
,lh.LocationPath
,lh.lcHID
FROM ru lh
WHERE lh.lcHIDParent IS NULL
GO
-- get data via view
SELECT
CONCAT(SPACE(l.lcHID.GetLevel() * 4), lcCode) as LocationIndented
FROM dbo.vwLocationCodes l
ORDER BY lcHID
GO
SET SHOWPLAN_XML ON
GO
DECLARE @lcID int = 2
-- I believe this produces bad plan and is defect in SQL Server optimizer.
-- variable value cardinality is 1 and SQL Server should know that. Optiomal plan is to do index seek with key lookup.
-- This does not happen.
SELECT lcCode FROM dbo.vwLocationCodes l WHERE l.lcID = @lcID -- bad plan
-- this is a plan I expect.
SELECT lcCode FROM dbo.vwLocationCodes l WHERE l.lcID = 2 -- good plan
-- I reviewed these but I need a view here, can't be SP
-- http://sqlblogcasts.com/blogs/tonyrogerson/archive/2008/05/17/non-recursive-common-table-expressions-performance-sucks-1-cte-self-join-cte-sub-query-inline-expansion.aspx
-- http://social.msdn.microsoft.com/Forums/sqlserver/en-US/22d2d580-0ff8-4a9b-b0d0-e6a8345062df/issue-with-select-using-a-recursive-cte-and-parameterizing-the-query?forum=transactsql
GO
SET SHOWPLAN_XML OFF
GO
ROLLBACK
Vladimir MoldovanenkoHere is more... note that I am creating table Items and these can be in Locations.
I am trying LEFT JOIN and OUTER APLLY to 'bend' query into NESTED LOOP and SEEK. There has to be nested loop, 2 rows against 4. But SQL Server fails to generate optimal plan with SEEK. Even RECOMPILE does not help
use tempdb
BEGIN TRAN
-- setup definition
CREATE TABLE dbo.LocationHierarchy(
lcID int NOT NULL ,
lcHID hierarchyid NOT NULL,
lcCode nvarchar(25) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
lcHIDParent AS lcHID.GetAncestor(1) PERSISTED,
CONSTRAINT PK_LocationHierarchy_lcID PRIMARY KEY NONCLUSTERED (lcID ASC),
CONSTRAINT UX_LocationHierarchy_pltID_lcHID UNIQUE CLUSTERED (lcHID ASC)
-- add some data
INSERT INTO dbo.LocationHierarchy
VALUES
(1, '/', 'A')
,(2, '/1/', 'B')
,(3, '/1/1/', 'C')
,(4, '/1/1/1/', 'D')
--DROP VIEW dbo.vwLocationCodes
GO
--DECLARE @Count int = 10;
--WITH L0 AS (SELECT N FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N (N))-- 10 rows
--,L1 AS (SELECT n1.N FROM L0 n1 CROSS JOIN L0 n2) -- 100 rows
--,L2 AS (SELECT n1.N FROM L1 n1 CROSS JOIN L1 n2) -- 10,000 rows
--,L3 AS (SELECT n1.N FROM L2 n1 CROSS JOIN L2 n2) -- 100,000,000 rows
--,x AS
-- SELECT TOP (ISNULL(@Count, 0))
-- ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as Number
-- FROM L3 n1
--SELECT Number as itmID, NTILE(4)OVER(ORDER BY Number) as lcID
--INTO dbo.Items
--FROM x
----ORDER BY n1.N
--ALTER TABLE dbo.Items ALTER COLUMN itmID INT NOT NULL
--ALTER TABLE dbo.Items ADD CONSTRAINT PK PRIMARY KEY CLUSTERED (itmID)
CREATE TABLE dbo.Items (itmID int NOT NULL PRIMARY KEY, lcID int NOT NULL)
INSERT INTO dbo.items
VALUES(1, 1)
,(2, 3)
GO
CREATE VIEW dbo.vwLocationCodes
AS
WITH ru AS
SELECT
lh.lcID
,lh.lcCode
,lh.lcHID
,CAST('/' + lh.lcCode + '/' as varchar(8000)) as LocationPath
-- to support recursion
,lh.lcHIDParent
FROM dbo.LocationHierarchy lh
UNION ALL
SELECT
ru.lcID
,ru.lcCode
,ru.lcHID
,CAST('/' + lh.lcCode + ru.LocationPath as varchar(8000)) as LocationPath
,lh.lcHIDParent
FROM dbo.LocationHierarchy lh
JOIN ru ON ru.lcHIDParent = lh.lcHID
SELECT
lh.lcID
,lh.lcCode
,lh.LocationPath
,lh.lcHID
FROM ru lh
WHERE lh.lcHIDParent IS NULL
GO
-- get data via view
SELECT
CONCAT(SPACE(l.lcHID.GetLevel() * 4), lcCode) as LocationIndented
FROM dbo.vwLocationCodes l
ORDER BY lcHID
GO
--SET SHOWPLAN_XML ON
GO
DECLARE @lcID int = 2
-- I believe this produces bad plan and is defect in SQL Server optimizer.
-- variable value cardinality is 1 and SQL Server should know that. Optiomal plan is to do index seek with key lookup.
-- This does not happen.
SELECT lcCode FROM dbo.vwLocationCodes l WHERE l.lcID = @lcID-- OPTION(RECOMPILE) -- bad plan
-- this is a plan I expect.
SELECT lcCode FROM dbo.vwLocationCodes l WHERE l.lcID = 2 -- good plan
SELECT *
FROM dbo.Items itm
LEFT JOIN dbo.vwLocationCodes l ON l.lcID = itm.lcID
OPTION(RECOMPILE)
SELECT *
FROM dbo.Items itm
OUTER APPLY
SELECT *
FROM dbo.vwLocationCodes l
WHERE l.lcID = itm.lcID
) l
-- I reviewed these but I need a view here, can't be SP
-- http://sqlblogcasts.com/blogs/tonyrogerson/archive/2008/05/17/non-recursive-common-table-expressions-performance-sucks-1-cte-self-join-cte-sub-query-inline-expansion.aspx
-- http://social.msdn.microsoft.com/Forums/sqlserver/en-US/22d2d580-0ff8-4a9b-b0d0-e6a8345062df/issue-with-select-using-a-recursive-cte-and-parameterizing-the-query?forum=transactsql
GO
--SET SHOWPLAN_XML OFF
GO
ROLLBACK
Vladimir Moldovanenko -
Query tuning for query using connect by prior
I have written following query to fetch the data. The query is written in this format because there are multiple rows, which make one recrd and we need to bring that record into one row.
For one CAT(commented here), this query takes around 4 minutes and fetches 6900 records but when it runs for 3 CAT, it takes 17 mins.
I want to tune this as this has to run for 350 CAT values.
It is doing FTS on the main table. I tried to use different hints like PARALLEL, APPEND (in insert) but nothing worked.
The cost of the query is 51.
Any help/suggestions will be appreciated.
SELECT DISTINCT MIN(SEQ) SEQ,
PT, APP, IT, LR, QT,CD, M_A_FLAG,
STRAGG(REM) REM, -- aggregates the data from different columns to one which is parent
CAT
FROM (WITH R AS (SELECT CAT, SEQ, PT, M_A_FLAG, IT, LR,QT,CD, REM, APP
FROM table1
WHERE REC = '36' AND M_A_FLAG = '1'
--AND CAT = '11113')
SELECT CAT, SEQ,
CONNECT_BY_ROOT PT AS PT,
CONNECT_BY_ROOT APP AS APPL,
M_A_FLAG,
CONNECT_BY_ROOT IT AS IT,
CONNECT_BY_ROOT LR AS LR,
CONNECT_BY_ROOT QT AS QT,
CONNECT_BY_ROOT CD AS CD,
REM
FROM R A
START WITH PT IS NOT NULL
CONNECT BY PRIOR SEQ + 1 = SEQ
AND PRIOR CAT = CAT
AND PT IS NULL)
GROUP BY PT, APP, IT,LR, QT, CD, M_A_FLAG, CAT
ORDER BY SEQ;
Thanks.
Edited by: user2544469 on Feb 11, 2011 1:12 AMThe following threads detail the approach and information required.
Please gather relevant info and post back.
How to post a SQL tuning request - HOW TO: Post a SQL statement tuning request - template posting
When your query takes too long - When your query takes too long ... -
Using START WITH and CONNECT BY PRIOR in a report
Hi - I am using Oracle 9i and reports 10g. Does anyone know of a reason why running my sql in TOAD will produce the correct results, but the report is dropping records? I am using start with and connect by prior to build a hierarchy of linked records. The report is dropping the "child records" and only returning records from the route level.
Thanks you for your help.Hi user574499
Could u pls share us ur Query...?
Regards,
Abdetu... -
Issue with the below query. The query is not getting filtered for the condition hier_typ_c in('BS') with the connect by prior
query. query is fetching all the hier_type_c in the table like 'BS', 'CO', 'EC' etc....
Just wondering how do i restrict the query just to fetch the type_c ='BS' alone? why is it giving all the records??
Select
Level as LEVEL_CODE,
h.HIER_PRNT_NODE_I as PARENT,
h.HIER_CHLD_NODE_I as CHILD,
h.HIER_CHLD_NODE_X || ' (' || h.HIER_CHLD_NODE_I || ')' as ALIAS
From (Select Distinct HIER_CHLD_NODE_I, HIER_PRNT_NODE_I,
HIER_CHLD_NODE_X from .HIER_DIMN
where hier_typ_c in('BS') and CURR_VER_C = 'Y') h
Start with h.HIER_PRNT_NODE_I = 'ROOT'
Connect by prior
h.HIER_CHLD_NODE_I = h.HIER_PRNT_NODE_I
Order by LEVEL_CODE, parent, childHi
It loks like you're doing it right.
By basing the CONNECT BY query on a sub-query that has this WHERE clasue:
where hier_typ_c in('BS') and CURR_VER_C = 'Y') hyou should exclude not only nodes whose hier_typ_c is not 'BS', but also their descendants.
Post some sample data (CREATE TABLE and INSERT statements) and the results you want from that data.
Are you sure the query you posted is what you're actually running?
I would expect the sub-query FROM clause to cause an error because of the '.'.
from .HIER_DIMNEdited by: Frank Kulash on Sep 29, 2009 11:16 AM -
Connect by prior (hierarchical query)
Hi All,
Some1 asked me a question which goes like this:
Source
emp_no dep_no
110 10
110 20
110 30
110 40
120 10
130 10
130 20
write a query to achieve the following output from the above source
emp_no dept_no
110 10203040
120 10
130 1020
Now I have come across solutions with 'connect by prior' clauses but I am nt able to understand how oracle is producing that result , Could someone point me to a good article or text that can explain this concept very thoroughly( I have searched on google and got to see many articles but I couldnt able to understand it since these articles were not explaining everything)
Regards
RahulYou can try this:
SQL> ed
Wrote file afiedt.buf
1 SELECT deptno,MAX(TRIM(SUBSTR(SYS_CONNECT_BY_PATH(empid,','),2)))
2 KEEP(DENSE_RANK LAST ORDER BY deptno) FROM
3 (SELECT deptno,empid,ROW_NUMBER() OVER(PARTITION BY deptno ORDER BY deptno) curr,
4 ROW_NUMBER() OVER(PARTITION BY deptno ORDER BY deptno) - 1 prev
5 FROM emp)
6 CONNECT BY PRIOR curr = prev
7 AND deptno = PRIOR deptno
8 START WITH curr = 1
9* group by deptno
SQL> /
DEPTNO MAX(TRIM(SUBSTR(SYS_CONNECT_BY_PATH(EMPID,','),2)))KEEP(DENSE_RANKLASTORDERBYDEPTNO)
10 1,2,3,4
20 5,6,7
SQL> select deptno,empid from emp;
DEPTNO EMPID
10 1
10 2
10 3
10 4
20 5
20 6
20 7
7 rows selected.
SQL>
Maybe you are looking for
-
Upgrading to Windows 7 and other questions answered.
After reading a few posts around the forum, I decided to add a little to the discussions. First, if you bought a computer from HP and didnt qualify for an upgrade, and still want windows 7, your best bet is to go OEM. OEM software is the same as reta
-
Nano No Longer Connecting...
Alright, I've recently had my entire computer reset. I've installed iTunes 7, and it doesn't recognize my iPod nano. Not the newer, bigger one, the older one. It charges and plays in my 360 just fine. I plug it in and am prompted to install new hardw
-
Hi, i try to migrate the HSC0 from version 6.1 to version 7.1 and take this opportunity to consult on the installation of HSC0 where the PARMLIB member LKEYINFO (LKEYDEF) Product for this new version V 7.1 is telling me no longer supported, please I
-
Duplicate and remove "copy" from name?
how to remove the "copy" in the name of a duplicate layer? Or better even: avoid having Illustrator add "Copy" to the name
-
PI 7.1 Exchange profile parameter:
Hi I got a chance to have a look at PI 7.1. While going through the Exchange Profile parameters, I found a new addition to the existing parameter list. Its called internal. I could not find any information about it. help.sap documenation also does no