Oracle MOS has one matching Documentation:
Slow Query On External Table If User Executing the Select Does Not Have "Create/Drop Any Directory" Privileges (Doc ID 2034938.1)
Symptoms . Query against external tables perform slowly . User executing the select does not have "create any directory" or "drop any directory" privileges . The slowest query from the 10046 trace is the following recursive SQL: SELECT NAME, PATH, READ, WRITE, EXECUTE FROM SYS.LOADER_DIR_OBJS; Solution 1. The solution is to gather statistics for the KZSROROL column as follows: exec dbms_stats.gather_table_stats(null,'X$KZSRO',method_opt=>'for columns KZSROROL',no_invalidate => false); 2. Afterwards to make sure that these statistics will not get deleted by future runs of DBMS_STATS.GATHER_FIXED_OBJECTS_STATS command, lock the statistics: exec dbms_stats.lock_table_stats('SYS','X$KZSRO');This performance problem is worth of studying because it is directly related to System Privileges.
We will set up one System privilege and one Object privilege. Toggling both privileges, make 5 different tests:
Test-1: Object privilege: YES; System privilege: YES Test-2: Object privilege: YES; System privilege: NO Test-3: Object privilege: NO; System privilege: YES Test-4: Object privilege: NO; System privilege: NO Test-5: Object privilege: NO; System privilege: NO, and SQL PatchThe first two Tests are querying one external table; the next three are querying SYS.LOADER_DIR_OBJS. Test-5 is same as Test-4, but with SQL Patch applied.
Oracle 12.1 introduced SQL Patch (unofficial, undocumented) to tune packaged SQL Statements. Although it is possible to manipulate xplan with SQL Patch, but it cannot detour Oracle security to influence query result.
There is another related MOS Docu: Diagnosing a High Number of Executions Against Table SYS.DIR$ (Doc ID 2230171.1)
Note: All tests are done in Oracle 12.1.0.2 on Solaris.
1. Test Setup
sqlplus admin/admin123@TESTDB
drop user ksun cascade;
create user ksun identified by test123;
grant select any table, create any table, drop any table, create session, execute any procedure to ksun;
grant create any directory to ksun;
--revoke create any directory from ksun;
create or replace directory test_dir as '/oradata/app/oracle/admin/testdb/io';
grant read, write on directory test_dir to ksun;
--revoke read, write on directory test_dir from ksun;
exec dbms_stats.unlock_table_stats('SYS','X$KZSRO');
exec dbms_stats.gather_table_stats('SYS','X$KZSRO',method_opt=>'for columns KZSROROL',no_invalidate => false);
exec dbms_stats.lock_table_stats('SYS','X$KZSRO');
drop table testt1_ext;
create table testt1_ext
organization external
(type oracle_datapump
default directory test_dir
location ('testt1_ext.txt'))
as select 321 x from dual;
2. Test-1: Object privilege: YES; System privilege: YES
sqlplus admin/admin123@TESTDB
grant read, write on directory test_dir to ksun;
grant create any directory to ksun;
select * from sys.dba_sys_privs where grantee = 'KSUN';
GRAN PRIVILEGE ADMIN_OPTION COMMON
---- ---------------------- ------------ ------
KSUN CREATE TABLE NO NO
KSUN EXECUTE ANY PROCEDURE NO NO
KSUN DROP ANY TABLE NO NO
KSUN CREATE ANY TABLE NO NO
KSUN CREATE ANY DIRECTORY NO NO
KSUN SELECT ANY TABLE NO NO
KSUN CREATE SESSION NO NO
select grantee, table_name, privilege, type from sys.dba_tab_privs where grantee = 'KSUN';
GRANTEE TABLE_NAME PRIVILEGE TYPE
------- ---------- --------- ---------
KSUN TEST_DIR READ DIRECTORY
KSUN TEST_DIR WRITE DIRECTORY
The query takes less than 1 second.
sqlplus ksun/test123@TESTDB
select sql_id, executions, rows_processed, buffer_gets, elapsed_time, cpu_time, last_load_time --,v.*
from v$sql v where sql_id = 'f5ra7dru5fk5n';
SQL_ID EXECUTIONS ROWS_PROCESSED BUFFER_GETS ELAPSED_TIME CPU_TIME LAST_LOAD_TIME
------------- ---------- -------------- ----------- ------------ ---------- -------------------
f5ra7dru5fk5n 5 5660 32729 198104 198283 2018-02-19/08:38:40
select * from testt1_ext;
X
----------
321
1 row selected.
Elapsed: 00:00:00.03
select sql_id, executions, rows_processed, buffer_gets, elapsed_time, cpu_time, last_load_time --,v.*
from v$sql v where sql_id = 'f5ra7dru5fk5n';
SQL_ID EXECUTIONS ROWS_PROCESSED BUFFER_GETS ELAPSED_TIME CPU_TIME LAST_LOAD_TIME
------------- ---------- -------------- ----------- ------------ ---------- -------------------
f5ra7dru5fk5n 6 6792 37343 217328 217563 2018-02-19/08:38:40
(delta BUFFER_GETS=37343-32729=4,614, ELAPSED_TIME=217328-198104=19,224)
alter session set tracefile_identifier = 'ksun_trc_test1';
exec dbms_monitor.session_trace_enable(waits=>true, binds=>false, plan_stat=>'all_executions');
select * from testt1_ext;
exec dbms_monitor.session_trace_disable;
********************************************************************************
SQL ID: f5ra7dru5fk5n Plan Hash: 1161458834
SELECT NAME, PATH, READ, WRITE, EXECUTE FROM SYS.LOADER_DIR_OBJS
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 1133 0.05 0.05 0 3474 0 1132
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 1135 0.05 0.05 0 3474 0 1132
Rows (avg) Row Source Operation
---------- ---------------------------------------------------
1132 VIEW LOADER_DIR_OBJS (cr=4614 pr=0 pw=0 time=53950 us cost=1189 size=2381728 card=1132)
1132 UNION-ALL (cr=4614 pr=0 pw=0 time=53093 us)
1132 NESTED LOOPS (cr=4614 pr=0 pw=0 time=51662 us cost=1131 size=99528 card=1131)
1132 NESTED LOOPS (cr=3482 pr=0 pw=0 time=48085 us cost=1131 size=99528 card=1131)
1132 FIXED TABLE FULL X$DIR (cr=1140 pr=0 pw=0 time=39002 us cost=0 size=65598 card=1131)
1132 INDEX RANGE SCAN I_OBJ1 (cr=2342 pr=0 pw=0 time=3597 us cost=1 size=0 card=1)(object id 1591123)
1132 TABLE ACCESS BY INDEX ROWID OBJ$ (cr=1132 pr=0 pw=0 time=2996 us cost=1 size=30 card=1)
1 FIXED TABLE FULL X$KZSPR (cr=0 pr=0 pw=0 time=29 us cost=0 size=7 card=1)
0 HASH GROUP BY (cr=0 pr=0 pw=0 time=411 us cost=58 size=105 card=1)
0 FILTER (cr=0 pr=0 pw=0 time=29 us)
0 NESTED LOOPS (cr=0 pr=0 pw=0 time=0 us cost=57 size=105 card=1)
0 NESTED LOOPS (cr=0 pr=0 pw=0 time=0 us cost=57 size=47 card=1)
0 HASH JOIN RIGHT SEMI (cr=0 pr=0 pw=0 time=0 us cost=56 size=17 card=1)
0 VIEW VW_NSO_1 (cr=0 pr=0 pw=0 time=0 us cost=0 size=60 card=15)
0 FIXED TABLE FULL X$KZSRO (cr=0 pr=0 pw=0 time=0 us cost=0 size=60 card=15)
0 TABLE ACCESS FULL OBJAUTH$ (cr=0 pr=0 pw=0 time=0 us cost=56 size=120471 card=9267)
0 TABLE ACCESS BY INDEX ROWID BATCHED OBJ$ (cr=0 pr=0 pw=0 time=0 us cost=1 size=30 card=1)
0 INDEX RANGE SCAN I_OBJ1 (cr=0 pr=0 pw=0 time=0 us cost=1 size=0 card=1)(object id 1591123)
0 FIXED TABLE FIXED INDEX X$DIR (ind:1) (cr=0 pr=0 pw=0 time=0 us cost=0 size=58 card=1)
1 FIXED TABLE FULL X$KZSPR (cr=0 pr=0 pw=0 time=27 us cost=0 size=7 card=1)
********************************************************************************
3. Test-2: Object privilege: YES; System privilege: NO
sqlplus admin/admin123@TESTDB
grant read, write on directory test_dir to ksun;
revoke create any directory from ksun;
The query takes about 17 seconds because of subquery TABLE FULL X$KZSRO.
sqlplus ksun/test123@TESTDB
select sql_id, executions, rows_processed, buffer_gets, elapsed_time, cpu_time, last_load_time --,v.*
from v$sql v where sql_id = 'f5ra7dru5fk5n';
SQL_ID EXECUTIONS ROWS_PROCESSED BUFFER_GETS ELAPSED_TIME CPU_TIME LAST_LOAD_TIME
------------- ---------- -------------- ----------- ------------ ---------- -------------------
f5ra7dru5fk5n 6 6792 37343 217328 217563 2018-02-19/08:38:40
select * from testt1_ext;
X
----------
321
1 row selected.
Elapsed: 00:00:17.93
select sql_id, executions, rows_processed, buffer_gets, elapsed_time, cpu_time, last_load_time --,v.*
from v$sql v where sql_id = 'f5ra7dru5fk5n';
SQL_ID EXECUTIONS ROWS_PROCESSED BUFFER_GETS ELAPSED_TIME CPU_TIME LAST_LOAD_TIME
------------- ---------- -------------- ----------- ------------ ---------- -------------------
f5ra7dru5fk5n 7 6793 109986 18108955 18104124 2018-02-19/08:38:40
(delta BUFFER_GETS=109986-37343=72,643, ELAPSED_TIME=18108955-217328=17,891,627)
alter session set max_dump_file_size = UNLIMITED;
alter session set tracefile_identifier = 'ksun_trc_test2';
exec dbms_monitor.session_trace_enable(waits=>true, binds=>false, plan_stat=>'all_executions');
select * from testt1_ext;
alter session set session_cached_cursors = 0;
exec dbms_monitor.session_trace_disable;
alter session set session_cached_cursors = 200;
********************************************************************************
SQL ID: f5ra7dru5fk5n Plan Hash: 1161458834
SELECT NAME, PATH, READ, WRITE, EXECUTE FROM SYS.LOADER_DIR_OBJS
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 2 0.03 0.03 0 235 0 0
Execute 2 0.00 0.00 0 0 0 0
Fetch 4 38.11 38.10 0 13750 0 2
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 8 38.15 38.13 0 13985 0 2
Rows (avg) Row Source Operation
---------- ---------------------------------------------------
1 VIEW LOADER_DIR_OBJS (cr=77167 pr=0 pw=0 time=19800468 us cost=1189 size=2381728 card=1132)
1 UNION-ALL (cr=77167 pr=0 pw=0 time=19800465 us)
0 NESTED LOOPS (cr=5776 pr=0 pw=0 time=124426 us cost=1131 size=99528 card=1131)
1132 NESTED LOOPS (cr=5747 pr=0 pw=0 time=125176 us cost=1131 size=99528 card=1131)
1132 FIXED TABLE FULL X$DIR (cr=5664 pr=0 pw=0 time=120445 us cost=0 size=65598 card=1131)
1132 INDEX RANGE SCAN I_OBJ1 (cr=83 pr=0 pw=0 time=1644 us cost=1 size=0 card=1)(object id 1591123)
0 TABLE ACCESS BY INDEX ROWID OBJ$ (cr=29 pr=0 pw=0 time=964 us cost=1 size=30 card=1)
0 FIXED TABLE FULL X$KZSPR (cr=0 pr=0 pw=0 time=30 us cost=0 size=7 card=1)
1 HASH GROUP BY (cr=71391 pr=0 pw=0 time=19676026 us cost=58 size=105 card=1)
2 FILTER (cr=71391 pr=0 pw=0 time=19675276 us)
2 NESTED LOOPS (cr=71391 pr=0 pw=0 time=19675254 us cost=57 size=105 card=1)
32313 NESTED LOOPS (cr=6763 pr=0 pw=0 time=363426 us cost=57 size=47 card=1)
32313 HASH JOIN RIGHT SEMI (cr=196 pr=0 pw=0 time=65194 us cost=56 size=17 card=1)
2 VIEW VW_NSO_1 (cr=0 pr=0 pw=0 time=10 us cost=0 size=60 card=15)
2 FIXED TABLE FULL X$KZSRO (cr=0 pr=0 pw=0 time=6 us cost=0 size=60 card=15)
43515 TABLE ACCESS FULL OBJAUTH$ (cr=196 pr=0 pw=0 time=45666 us cost=56 size=120471 card=9267)
32313 TABLE ACCESS BY INDEX ROWID BATCHED OBJ$ (cr=6567 pr=0 pw=0 time=227682 us cost=1 size=30 card=1)
32313 INDEX RANGE SCAN I_OBJ1 (cr=4851 pr=0 pw=0 time=118484 us cost=1 size=0 card=1)(object id 1591123)
2 FIXED TABLE FIXED INDEX X$DIR (ind:1) (cr=64628 pr=0 pw=0 time=19318193 us cost=0 size=58 card=1)
0 FIXED TABLE FULL X$KZSPR (cr=0 pr=0 pw=0 time=16 us cost=0 size=7 card=1)
********************************************************************************
4. Test-3: Object privilege: NO; System privilege: YES
sqlplus admin/admin123@TESTDB
revoke read, write on directory test_dir from ksun;
grant create any directory to ksun;
Make the test:
sqlplus ksun/test123@TESTDB
SELECT NAME, PATH, READ, WRITE, EXECUTE FROM SYS.LOADER_DIR_OBJS
NAME PATH READ WRITE EXECUTE
---------- ----------------------------------- ------ ------ -------
TEST_DIR /oradata/app/oracle/admin/testdb/io TRUE TRUE TRUE
1 row selected.
Elapsed: 00:00:00.04
The select returns 1 row, and takes less than 1 second.Here the xplan:
sqlplus admin/admin123@TESTDB
select * from table(dbms_xplan.display_cursor('f5ra7dru5fk5n', null, 'ADVANCED ALLSTATS LAST'));
SQL_ID f5ra7dru5fk5n, child number 0
-------------------------------------
SELECT NAME, PATH, READ, WRITE, EXECUTE FROM SYS.LOADER_DIR_OBJS
Plan hash value: 1161458834
--------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time |
--------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 1189 (100)| |
| 1 | VIEW | LOADER_DIR_OBJS | 1132 | 2325K| 1189 (1)| 00:00:01 |
| 2 | UNION-ALL | | | | | |
| 3 | NESTED LOOPS | | 1131 | 99528 | 1131 (0)| 00:00:01 |
| 4 | NESTED LOOPS | | 1131 | 99528 | 1131 (0)| 00:00:01 |
| 5 | FIXED TABLE FULL | X$DIR | 1131 | 65598 | 0 (0)| |
|* 6 | INDEX RANGE SCAN | I_OBJ1 | 1 | | 1 (0)| 00:00:01 |
|* 7 | TABLE ACCESS BY INDEX ROWID | OBJ$ | 1 | 30 | 1 (0)| 00:00:01 |
|* 8 | FIXED TABLE FULL | X$KZSPR | 1 | 7 | 0 (0)| |
| 9 | HASH GROUP BY | | 1 | 105 | 58 (2)| 00:00:01 |
|* 10 | FILTER | | | | | |
| 11 | NESTED LOOPS | | 1 | 105 | 57 (0)| 00:00:01 |
| 12 | NESTED LOOPS | | 1 | 47 | 57 (0)| 00:00:01 |
|* 13 | HASH JOIN RIGHT SEMI | | 1 | 17 | 56 (0)| 00:00:01 |
| 14 | VIEW | VW_NSO_1 | 15 | 60 | 0 (0)| |
| 15 | FIXED TABLE FULL | X$KZSRO | 15 | 60 | 0 (0)| |
|* 16 | TABLE ACCESS FULL | OBJAUTH$ | 9267 | 117K| 56 (0)| 00:00:01 |
| 17 | TABLE ACCESS BY INDEX ROWID BATCHED| OBJ$ | 1 | 30 | 1 (0)| 00:00:01 |
|* 18 | INDEX RANGE SCAN | I_OBJ1 | 1 | | 1 (0)| 00:00:01 |
|* 19 | FIXED TABLE FIXED INDEX | X$DIR (ind:1) | 1 | 58 | 0 (0)| |
|* 20 | FIXED TABLE FULL | X$KZSPR | 1 | 7 | 0 (0)| |
--------------------------------------------------------------------------------------------------------------
5. Test-4: Object privilege: NO; System privilege: NO
Revoke both privileges:
sqlplus admin/admin123@TESTDB
revoke read, write on directory test_dir from ksun;
revoke create any directory from ksun;
Make the test:
sqlplus ksun/test123@TESTDB
SELECT NAME, PATH, READ, WRITE, EXECUTE FROM SYS.LOADER_DIR_OBJS
no rows selected
Elapsed: 00:00:12.49
no rows selected, and takes about 12 seconds.Here the xplan (same as Test-3):
sqlplus admin/admin123@TESTDB
select * from table(dbms_xplan.display_cursor('f5ra7dru5fk5n', null, 'ADVANCED ALLSTATS LAST'));
SQL_ID f5ra7dru5fk5n, child number 0
-------------------------------------
SELECT NAME, PATH, READ, WRITE, EXECUTE FROM SYS.LOADER_DIR_OBJS
Plan hash value: 1161458834
-----------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time | OMem | 1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 1189 (100)| | | | |
| 1 | VIEW | LOADER_DIR_OBJS | 1132 | 2325K| 1189 (1)| 00:00:01 | | | |
| 2 | UNION-ALL | | | | | | | | |
| 3 | NESTED LOOPS | | 1131 | 99528 | 1131 (0)| 00:00:01 | | | |
| 4 | NESTED LOOPS | | 1131 | 99528 | 1131 (0)| 00:00:01 | | | |
| 5 | FIXED TABLE FULL | X$DIR | 1131 | 65598 | 0 (0)| | | | |
|* 6 | INDEX RANGE SCAN | I_OBJ1 | 1 | | 1 (0)| 00:00:01 | | | |
|* 7 | TABLE ACCESS BY INDEX ROWID | OBJ$ | 1 | 30 | 1 (0)| 00:00:01 | | | |
|* 8 | FIXED TABLE FULL | X$KZSPR | 1 | 7 | 0 (0)| | | | |
| 9 | HASH GROUP BY | | 1 | 105 | 58 (2)| 00:00:01 | 831K| 831K| |
|* 10 | FILTER | | | | | | | | |
| 11 | NESTED LOOPS | | 1 | 105 | 57 (0)| 00:00:01 | | | |
| 12 | NESTED LOOPS | | 1 | 47 | 57 (0)| 00:00:01 | | | |
|* 13 | HASH JOIN RIGHT SEMI | | 1 | 17 | 56 (0)| 00:00:01 | 2293K| 2293K| 709K (0)|
| 14 | VIEW | VW_NSO_1 | 15 | 60 | 0 (0)| | | | |
| 15 | FIXED TABLE FULL | X$KZSRO | 15 | 60 | 0 (0)| | | | |
|* 16 | TABLE ACCESS FULL | OBJAUTH$ | 9267 | 117K| 56 (0)| 00:00:01 | | | |
| 17 | TABLE ACCESS BY INDEX ROWID BATCHED| OBJ$ | 1 | 30 | 1 (0)| 00:00:01 | | | |
|* 18 | INDEX RANGE SCAN | I_OBJ1 | 1 | | 1 (0)| 00:00:01 | | | |
|* 19 | FIXED TABLE FIXED INDEX | X$DIR (ind:1) | 1 | 58 | 0 (0)| | | | |
|* 20 | FIXED TABLE FULL | X$KZSPR | 1 | 7 | 0 (0)| | | | |
-----------------------------------------------------------------------------------------------------------------------------------------
6. Test-5: Object privilege: NO; System privilege: NO, and SQL Patch
Since the recursive query is located in Oracle internal packaged application, SQL Patch is used to add hints.
One similar test was done by Blog: Slow external table access.
Revoke both privileges and create SQL Patch:
sqlplus admin/admin123@TESTDB
revoke read, write on directory test_dir from ksun;
revoke create any directory from ksun;
begin
sys.dbms_sqldiag_internal.i_create_patch(
sql_text => 'SELECT NAME, PATH, READ, WRITE, EXECUTE FROM SYS.LOADER_DIR_OBJS'
,hint_text => 'CARDINALITY(@"SEL$2" "D"@"SEL$2", 2) CARDINALITY(@"SEL$2" "O"@"SEL$2", 3) '||
'CARDINALITY(@"SEL$0C7B6CF6" "D"@"SEL$6" 4) '||
'USE_HASH(@"SEL$2" "D"@"SEL$2" O@SEL$2) USE_HASH(@"SEL$0C7B6CF6" "D"@"SEL$6")'
,name => 'SQLPATCH123');
end;
/
select name, created, status from dba_sql_patches where name in ('SQLPATCH123');
NAME CREATED STATUS
----------- ------------------- -------
SQLPATCH123 9-FEB-2018 11:15:22 ENABLED
select dbms_lob.substr(comp_data, 80, 1) hint, signature from sys.SQLOBJ$DATA t;
HINT SIGNATURE
-------------------------------------------------------------------------------- ---------------------
<outline_data><hint><![CDATA[CARDINALITY(@"SEL$2" "D"@"SEL$2", 2) CARDINALITY(@" 516452634368408982
<outline_data><hint><![CDATA[ IGNORE_OPTIM_EMBEDDED_HINTS 9073911181602513588
alter system flush shared_pool;
Make the test:
sqlplus ksun/test123@TESTDB
SELECT NAME, PATH, READ, WRITE, EXECUTE FROM SYS.LOADER_DIR_OBJS;
no rows selected
Elapsed: 00:00:00.29
Although query is fast (less than 1 second), but no rows selected. Therefore, it is not possible to bypass Oracle Security by SQL Patch. Xplan confirms that the SQL Patch was applied (also indicated in Note: SQL patch "SQLPATCH123") because it is different with that of Test-4.
sqlplus admin/admin123@TESTDB
select * from table(dbms_xplan.display_cursor('f5ra7dru5fk5n', null, 'ADVANCED ALLSTATS LAST'));
SQL_ID f5ra7dru5fk5n, child number 0
-------------------------------------
SELECT NAME, PATH, READ, WRITE, EXECUTE FROM SYS.LOADER_DIR_OBJS
Plan hash value: 153645881
------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time | OMem | 1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 3522 (100)| | | | |
| 1 | VIEW | LOADER_DIR_OBJS | 3 | 6312 | 3522 (1)| 00:00:01 | | | |
| 2 | UNION-ALL | | | | | | | | |
|* 3 | HASH JOIN | | 2 | 176 | 3515 (0)| 00:00:01 | 964K| 964K| 1297K (0)|
| 4 | FIXED TABLE FULL | X$DIR | 2 | 116 | 0 (0)| | | | |
|* 5 | INDEX FAST FULL SCAN | I_OBJ2 | 3 | 90 | 3515 (0)| 00:00:01 | | | |
|* 6 | FIXED TABLE FULL | X$KZSPR | 1 | 7 | 0 (0)| | | | |
| 7 | HASH GROUP BY | | 1 | 105 | 7 (15)| 00:00:01 | 831K| 831K| |
|* 8 | FILTER | | | | | | | | |
|* 9 | HASH JOIN SEMI | | 1 | 105 | 6 (0)| 00:00:01 | 1927K| 1186K| 2361K (0)|
| 10 | NESTED LOOPS | | 1 | 101 | 6 (0)| 00:00:01 | | | |
| 11 | NESTED LOOPS | | 4 | 352 | 4 (0)| 00:00:01 | | | |
| 12 | FIXED TABLE FULL | X$DIR | 4 | 232 | 0 (0)| | | | |
| 13 | TABLE ACCESS BY INDEX ROWID BATCHED| OBJ$ | 1 | 30 | 1 (0)| 00:00:01 | | | |
|* 14 | INDEX RANGE SCAN | I_OBJ1 | 1 | | 1 (0)| 00:00:01 | | | |
|* 15 | INDEX RANGE SCAN | I_OBJAUTH1 | 1 | 13 | 1 (0)| 00:00:01 | | | |
| 16 | VIEW | VW_NSO_1 | 15 | 60 | 0 (0)| | | | |
| 17 | FIXED TABLE FULL | X$KZSRO | 15 | 60 | 0 (0)| | | | |
|* 18 | FIXED TABLE FULL | X$KZSPR | 1 | 7 | 0 (0)| | | | |
------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SET$1 / LOADER_DIR_OBJS@SEL$1
2 - SET$1
3 - SEL$2
4 - SEL$2 / D@SEL$2
5 - SEL$2 / O@SEL$2
6 - SEL$C8360722 / X$KZSPR@SEL$5
7 - SEL$0C7B6CF6
12 - SEL$0C7B6CF6 / D@SEL$6
13 - SEL$0C7B6CF6 / O@SEL$6
14 - SEL$0C7B6CF6 / O@SEL$6
15 - SEL$0C7B6CF6 / OA@SEL$6
16 - SEL$3C459230 / VW_NSO_1@SEL$0C7B6CF6
17 - SEL$3C459230 / X$KZSRO@SEL$7
18 - SEL$2F35337B / X$KZSPR@SEL$10
Note
-----
- SQL patch "SQLPATCH123" used for this statement
After above test, drop used SQL patch:
sqlplus admin/admin123@TESTDB
exec dbms_sqldiag.drop_sql_patch('SQLPATCH123');
6. Discussions
In summary:
With System privilege (Test-1 and Test-3), queries on external table and SYS.LOADER_DIR_OBJS are fast. Without System privilege (Test-2 and Test-4), queries are slow. Without System privilege (Test-5), but with SQL Patch, query is fast, but no rows selected.Therefore, above 5 Tests showed that query result and performance depend on faultless System privilege.
Actually, the query on SYS.LOADER_DIR_OBJS:
select name, path, read, write, execute from sys.loader_dir_objs;
is a recursive statement when accessing external table:
select * from testt1_ext;
The performance is caused by the recursive statement.In case of missing System privilege, "SQL Patch" can be used to manipulate its xplan, and makes it fast. But the result is different in comparing to query with System privilege.
Looking the difference of SQL Trace xplan between Test-1 (fast) and Test-2 (slow), we can see that subquery on X$KZSRO in fast xplan returns 0 rows, but in slow xplan returns 2 rows, and hence generates expensive NESTED LOOPS.
Here the definition of SYS.LOADER_DIR_OBJS:
create or replace force view sys.loader_dir_objs (name, path, read, write, execute) bequeath definer as
select o.name, d.os_path, 'TRUE', 'TRUE', 'TRUE'
from sys.obj$ o, sys.x$dir d
where o.obj# = d.obj#
and ( o.owner# = uid
or exists (select null from v$enabledprivs where priv_number in (-177, -178)))
union all
select o.name,
d.os_path,
decode (sum (decode (oa.privilege#, 17, 1, 0)), 0, 'FALSE', 'TRUE'),
decode (sum (decode (oa.privilege#, 18, 1, 0)), 0, 'FALSE', 'TRUE'),
decode (sum (decode (oa.privilege#, 12, 1, 0)), 0, 'FALSE', 'TRUE')
from sys.obj$ o, sys.x$dir d, sys.objauth$ oa
where o.obj# = d.obj#
and oa.obj# = o.obj#
and oa.privilege# in (12, 17, 18)
and oa.grantee# in (select kzsrorol from x$kzsro)
and not ( o.owner# = uid
or exists (select null from v$enabledprivs where priv_number in (-177, -178)))
group by o.name, d.os_path;