Re: Predicates are not being pushed if casting PL/SQL table
Date: Mon, 7 Sep 2015 13:48:53 +0800
Message-ID: <CABx0cSUDZ=3XZ9x_ddfm9RdwdL4TumH9ihtk1vxa6XCg-UZT-Q_at_mail.gmail.com>
Thanks both, and sorry to waste your time on a bad test case. For you information, I have fixed (hopefully) test case, and still get same behaviour.
Yes, will drill into 10053 trace and see if I can get any further hints. By the way, and sorry for not mentioning before, this is on 11.2.0.4.
SQL> DROP TABLE
TEST_OBJECTS;
Table
dropped.
SQL> DROP TABLE
GTT_TEST_OBJECTS;
Table
dropped.
SQL> CREATE TABLE TEST_OBJECTS AS SELECT * FROM
DBA_OBJECTS;
Table
created.
SQL> CREATE INDEX TEST_OBJECTS_IDX ON
TEST_OBJECTS(OBJECT_ID);
Index
created.
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(NULL,
'TEST_OBJECTS');
PL/SQL procedure successfully
completed.
SQL>
SQL> CREATE OR REPLACE TYPE NUMBER_TABLE IS TABLE OF
NUMBER;
2
/
Type
created.
SQL> CREATE GLOBAL TEMPORARY TABLE GTT_TEST_OBJECTS (column_value number);
Table
created.
SQL> INSERT INTO GTT_TEST_OBJECTS2 VALUES (1);
1 row
created.
SQL> SQL> SQL> SELECT /*+ gather_plan_statistics */ null
2 FROM (SELECT DISTINCT OBJECT_ID FROM
TEST_OBJECTS)
3 WHERE OBJECT_ID IN (SELECT /*+ CARDINALITY(GTT_TEST_OBJECTS 1) */
column_value FROM
GTT_TEST_OBJECTS);
no rows
selected
SQL> SQL> SELECT * FROM TABLE(DBMS_XPLAN.display_cursor(format=>'ALLSTATS LAST')); PLAN_TABLE_OUTPUT
SQL_ID 00ggxzya0832u, child number
0
SELECT /*+ gather_plan_statistics */ null FROM (SELECT DISTINCT OBJECT_ID FROM TEST_OBJECTS) WHERE OBJECT_ID IN (SELECT /*+
CARDINALITY(GTT_TEST_OBJECTS 1) */ column_value FROM
GTT_TEST_OBJECTS)
Plan hash value:
1576474484
| Id | Operation | Name | Starts | E-Rows | A-Rows
| A-Time | OMem | 1Mem | Used-Mem
|
| 0 | SELECT STATEMENT | | 1 | | 0
|00:00:00.01 | | |
|
| 1 | VIEW | VM_NWVW_1 | 1 | 1 | 0
|00:00:00.01 | | |
|
| 2 | SORT UNIQUE NOSORT | | 1 | 1 | 0
|00:00:00.01 | | |
|
| 3 | NESTED LOOPS | | 1 | 1 | 0
|00:00:00.01 | | |
|
| 4 | SORT UNIQUE | | 1 | 1 | 0
|00:00:00.01 | 1024 | 1024 |
|
| 5 | TABLE ACCESS FULL| GTT_TEST_OBJECTS | 1 | 1 | 0
|00:00:00.01 | | |
|
|* 6 | INDEX RANGE SCAN | TEST_OBJECTS_IDX | 0 | 1 | 0 |00:00:00.01 | | | | ---------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
6 -
access("OBJECT_ID"="COLUMN_VALUE")
25 rows
selected.
SQL> SQL> SELECT /*+ gather_plan_statistics */ null
2 FROM (SELECT DISTINCT OBJECT_ID FROM
TEST_OBJECTS)
3 WHERE OBJECT_ID IN (SELECT /*+ CARDINALITY(GTT_TEST_OBJECTS 1) */
column_value FROM TABLE(NUMBER_TABLE(1))
GTT_TEST_OBJECTS);
no rows
selected
SQL> SQL> SELECT * FROM TABLE(DBMS_XPLAN.display_cursor(format=>'ALLSTATS LAST')); PLAN_TABLE_OUTPUT
SQL_ID 33cgqar810vch, child number
0
SELECT /*+ gather_plan_statistics */ null FROM (SELECT DISTINCT OBJECT_ID FROM TEST_OBJECTS) WHERE OBJECT_ID IN (SELECT /*+
CARDINALITY(GTT_TEST_OBJECTS 1) */ column_value
FROM
TABLE(NUMBER_TABLE(1))
GTT_TEST_OBJECTS)
Plan hash value:
1401649423
| Id | Operation | Name | Starts |
E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem
|
| 0 | SELECT STATEMENT | | 1
| | 0 |00:00:00.18 | 627 | | |
|(0)|
| 1 | MERGE JOIN SEMI | | 1
| 1 | 0 |00:00:00.18 | 627 | | |
|
| 2 | SORT JOIN | | 1
| 119K| 1 |00:00:00.18 | 627 | 2887K| 760K| 2566K
(0)|
| 3 | VIEW | | 1
| 119K| 119K|00:00:00.18 | 627 | | |
|
| 4 | HASH UNIQUE | | 1
| 119K| 119K|00:00:00.13 | 627 | 6695K| 2749K| 4623K
(0)|
| 5 | TABLE ACCESS FULL | TEST_OBJECTS | 1
| 119K| 119K|00:00:00.04 | 627 | | |
| |* 6 | SORT UNIQUE | | 1
| 1 | 0 |00:00:00.01 | 0 | 2048 | 2048 | 2048
| 7 | COLLECTION ITERATOR CONSTRUCTOR FETCH| | 1
| 1 | 1 |00:00:00.01 | 0 | | |
|
Predicate Information (identified by operation id):
6 -
access("OBJECT_ID"=VALUE(KOKBF$))
filter("OBJECT_ID"=VALUE(KOKBF$))
28 rows
selected.
On 5 September 2015 at 23:25, Dominic Brooks <dombrooks_at_hotmail.com> wrote:
> Stefan explained it a lot better than I did. > Even with the column reference corrected, I believe that the TABLE > subquery still won't be unnested. > e.g. > > SELECT null > FROM (SELECT DISTINCT OBJECT_ID FROM TEST_OBJECTS) > WHERE OBJECT_ID IN (SELECT VALUE(t) FROM TABLE(NUMBER_TABLE(1)) t); > > But it could be rewritten to avoid the subquery. > Something like (untested): > > SELECT DISTINCT obj.OBJECT_ID > FROM TEST_OBJECTS obj > , TABLE(NUMBER_TABLE(1)) t > WHERE obj.OBJECT_ID = VALUE(t) ; > > > Date: Sat, 5 Sep 2015 12:18:17 +0200 > > From: contact_at_soocs.de > > To: oracle-l_at_freelists.org; dombrooks_at_hotmail.com; jolliffe_at_gmail.com > > Subject: RE: Predicates are not being pushed if casting PL/SQL table > > > > > Hi Patrick, > > picking up Dominic's comment and your replies. Both test cases are not > equivalent (once i get 90131 rows and with the other 0 rows). > > > > > > > So seems it's not about predicates being pushed into subquery, but > subquery cannot be un-nested. I wonder why that is, what is it about the > outer > > > query having TABLE expression would prevent un-nesting this subquery? > > > > Here we go with a 12.1.0.1 CBO trace for your "TABLE(NUMBER_TABLE(1)" > example. > > --------------------8<------------------------------------ > > … > > SU - subquery unnesting > > FPD - filter push-down > > CVM - complex view merging > > SPJ - select-project-join > > … > > CVM: Merging SPJ view SEL$4 (#0) into SEL$3 (#0) > > Registered qb: SEL$07BDC5B4 0x6f6581a8 (VIEW MERGE SEL$3; SEL$4) > > --------------------- > > QUERY BLOCK SIGNATURE > > --------------------- > > signature (): qb_name=SEL$07BDC5B4 nbfros=1 flg=0 > > fro(0): flg=0 objn=0 hint_alias="KOKBF$0"_at_"SEL$4" > > … > > CBQT: copy not possible on query block SEL$07BDC5B4 (#0) because nested > table > > CBQT: copy not possible on query block SEL$1 (#0) because inner query > block constraints > > CBQT bypassed for query block SEL$1 (#0): Cannot copy query block. > > CBQT: Validity checks failed for 0u15kkytnwaqm. > > … > > SU: Checking validity of unnesting subquery SEL$07BDC5B4 (#0) > > SU: SU bypassed: Invalid correlated predicates. > > SU: Validity checks failed. > > … > > FPD: Considering simple filter push in query block SEL$1 (#0) > > EXISTS (SELECT 0 FROM TABLE("NUMBER_TABLE"(1)) "KOKBF$0") > > FPD: Considering simple filter push in query block SEL$07BDC5B4 (#0) > > :B1=:B2 > > try to generate transitive predicate from check constraints for query > block SEL$07BDC5B4 (#0) > > finally: :B1=:B2 > > try to generate transitive predicate from check constraints for query > block SEL$1 (#0) > > finally: EXISTS (SELECT 0 FROM TABLE("NUMBER_TABLE"(1)) "KOKBF$0") > > … > > Final query after transformations:******* UNPARSED QUERY IS ******* > > SELECT NULL "NULL" FROM (SELECT DISTINCT "TEST_OBJECTS"."OBJECT_ID" > "OBJECT_ID" FROM "TEST"."TEST_OBJECTS" "TEST_OBJECTS") "from$_subquery$_001" > > WHERE EXISTS (SELECT 0 FROM TABLE("NUMBER_TABLE"(1)) "KOKBF$0" WHERE > "from$_subquery$_001"."OBJECT_ID"="from$_subquery$_001"."OBJECT_ID") > > … > > --------------------8<------------------------------------ > > > > You can see the reason for it ("SU: SU bypassed: Invalid correlated > predicates.") and if you check the predicate section you gonna see that > your IN > > query was transformed to an EXISTS with the correlated predicate > "from$_subquery$_001"."OBJECT_ID"="from$_subquery$_001"."OBJECT_ID". This > is also > > what Dominic means with "Therefore object_id resolves to object_id > column from your distinct inline view". > > > > > > In contrast to that here is the snippet from your GTT_TEST_OBJECTS > example (also on 12.1.0.1). > > --------------------8<------------------------------------ > > … > > SELECT NULL "NULL" FROM (SELECT DISTINCT "TEST_OBJECTS"."OBJECT_ID" > "OBJECT_ID" FROM "TEST"."TEST_OBJECTS" "TEST_OBJECTS") "from$_subquery$_001" > > WHERE "from$_subquery$_001"."OBJECT_ID"=ANY (SELECT /*+ OPT_ESTIMATE > (TABLE "GTT_TEST_OBJECTS"_at_"SEL$3" ROWS=1.000000 ) */ > > "GTT_TEST_OBJECTS"."OBJECT_ID" "OBJECT_ID" FROM > "TEST"."GTT_TEST_OBJECTS" "GTT_TEST_OBJECTS") > > … > > SU: Unnesting query blocks in query block SEL$1 (#1) that are valid to > unnest. > > Subquery removal for query block SEL$3 (#2) > > RSW: Not valid for subquery removal SEL$3 (#2) > > Subquery unchanged. > > Subquery Unnesting on query block SEL$1 (#1)SU: Performing unnesting > that does not require costing. > > SU: Considering subquery unnest on query block SEL$1 (#1). > > SU: Checking validity of unnesting subquery SEL$3 (#2) > > SU: Passed validity checks. > > SU: Transforming ANY subquery to a join. > > … > > --------------------8<------------------------------------ > > > > Best Regards > > Stefan Koehler > > > > Freelance Oracle performance consultant and researcher > > Homepage: http://www.soocs.de > > Twitter: _at_OracleSK > > > > > > > Dominic Brooks <dombrooks_at_hotmail.com> hat am 4. September 2015 um > 14:08 geschrieben: > > > > > > Does the test case have an error? > > > Column name from collection is not "object_id" but value(alias) or > column_value. > > > Therefore object_id resolves to object_id column from your distinct > inline view > > -- > > http://www.freelists.org/webpage/oracle-l > > > > >
-- http://www.freelists.org/webpage/oracle-lReceived on Mon Sep 07 2015 - 07:48:53 CEST