Let’s meet at TROUG Ankara ORACLE Day!

Date :25 April 2024

Address: ORACLE Ankara Office | 312 Vista Eskişehir Yolu 2176.Cadde No:9/7 Söğütözü Çankaya 06530 Ankara

Agenda:

13:00 – 13:30  The Success Story of OCM and Oracle Certificates- Talip Hakan Öztürk, OCM, Oracle ACE Pro

13:30 – 14:00  Oracle Database 23c: 10 New Magic Features – Sevay Yılmaz, Database Operations Manager

14:00 – 14:30  Kubernetes and Oracle – Faruk ÇEVİK, Oracle ACE

14:30 – 15:00  Oracle ODA & Exadata – Ercihan Toprakçı Oracle Principle Solution Engineer

Kayıt için; admin@troug.org

For registration; admin@troug.org

RAC instance startup failed with error LRM-00109

Hello,

On 12.2 RAC database, we couldn’t start one of the instance. Only an instance was running during a time. Cannot startup the failed instance both with ‘srvctl start instance -d dbtalip -i dbtalip2’ or ‘sqlplus startup’ command. It gives the following error message.

ORA-01078: failure in processing system parameters
LRM-00109: could not open parameter file ‘/u01/app/oracle/product/12.2.0/dbhome1/dbs/initdbtalip.ora’

Database spfile was on ASM and you can check the spfile location with the following command.

srvctl config database -d dbtalip

Database unique name:DBTALIP
Database name: DBTALIP
Oracle home: /u01/app/oracle/product/12.2.0/dbhome1
Oracle user: oracle
Spfile: +DATA/DBTALIP/PARAMETERFILE/spfile.248.899238302
Password file: +DATA/DBTALIP/PASSWORD/pwdDBTALIP.256.186232184

Oracle binary file under $GRID_HOME does not have the SUID bit privilege ,So RDBMS cannot access ASM when startup.

ls -al $GRID_HOME/bin/oracle
-rwxr-x--x 1 grid oinstall 200678464 Mar 16 12:04 oracle

Oracle binary should have permission of 6751. To correct the permission, as owner of oracle binary.

su - grid
cd $ORACLE_HOME/bin
chmod 6751 oracle
ls -l $ORACLE_HOME/bin/oracle
-rwsr-s--x 1 grid oinstall 200678464 Mar 16 12:04 oracle

Adaptive Cursor Sharing & Bind peeking in Oracle

Hello,

In this blog post, I want to demonstrate the concept of bind peeking. Firstly, Bind peeking was introduced in Oracle 9i. The query optimizer peeks at the values of userdefined bind variables on the first invocation of a cursor. This feature allows the optimizer to determine the selectivity of any WHERE clause condition. Up to 10g, no further peeking takes place on subsequent invocations of the cursor and the cursor is shared based on the standard cursor-sharing criteria, even if subsequent invocations use different bind values.
From 11g, the adaptive cursor sharing feature enables a single statement that contains bind variables to use different execution plans for different binds.

OK let me prepare test environment for doing example of bind variables.

# sqlplus / as sysdba
SQL>create user DBM identified by oracle
SQL>default tablespace USERS
SQL>quota unlimited on USERS;
SQL>grant dba to dbm;
SQL>connect dbm/oracle
Connected.

SQL> alter session set optimizer_mode='ALL_ROWS';

Enable bind peeking feature

SQL> alter session set "_optim_peek_user_binds"=true;

Let me test with CPU costing off

SQL> alter session set "_optimizer_cost_model"='io';

SQL> create table survey
( ID number(5),
beverage varchar2(20)
);

Now, I have a survey that shows 80000 people prefer to drink Coco Cola while only one person drinks RedWine and another coffee.

SQL> Begin
For i in 1..80000 Loop
insert into survey Values (i, 'Cola');
End Loop;
insert into survey Values (80001, 'RedWine');
insert into survey Values(80002, 'Coffee');
commit;
End;
/
SQL> create index drink_idx on survey(beverage);
SQL> begin
dbms_stats.gather_table_stats(ownName => 'DBM', TabName => 'SURVEY', method_opt => 'For All Indexed Columns Size Auto', cascade => True);
end;
/

According to the Cursor_Sharing parameter value (it is exact) means that queries that differ only by their literal values will NOT be shared.

Let me examine the execution plan using autotrace in sqlplus.

SQL> set autotrace traceonly explain
SQL> select * from survey
where beverage= 'Cola';
Elapsed: 00:00:02.46
Execution Plan
----------------------------------------------------------
Plan hash value: 102092465

------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
------------------------------------------------------------
| 0 | SELECT STATEMENT | | 26667 | 260K| 39 |
|* 1 | TABLE ACCESS FULL| SURVEY | 26667 | 260K| 39 |
------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("BEVERAGE"='Cola')



SQL> select count(*) from survey
where beverage= 'Cola';

Elapsed: 00:00:00.03
Execution Plan
----------------------------------------------------------
Plan hash value: 3060591156

-------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
-------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 6 | 29 |
| 1 | SORT AGGREGATE | | 1 | 6 | |
|* 2 | INDEX FAST FULL SCAN| DRINK_IDX | 26667 | 156K| 29 |
-------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter("BEVERAGE"='Cola')

You will see either Index Fast Full Scan or Table Full Access. Now let me show the plan for a different value that we know only matches 1 row.

SQL> select * from survey
where beverage= 'Coffee';
Elapsed: 00:00:00.09

Execution Plan
----------------------------------------------------------
Plan hash value: 1191206642

---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 10 | 2 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| SURVEY | 1 | 10 | 2 |
|* 2 | INDEX RANGE SCAN | DRINK_IDX | 1 | | 1 |
---------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("BEVERAGE"='Coffee')

You see Index Range Scan, since from the statistics, the optimizer knows that there is only one row satisfying the condition. So the optimizer chooses Index Range access path.
Now let me define a bind variable and assign different values.

SQL> variable drink varchar2(20);
SQL> exec :drink :='Cola';
SQL> select count(*) from survey
16:52:15 2 where beverage= :drink;

Elapsed: 00:00:00.04
Execution Plan
----------------------------------------------------------
Plan hash value: 3060591156

-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 6 | 50 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 6 | | |
|* 2 | INDEX FAST FULL SCAN| DRINK_IDX | 26667 | 156K| 50 (0)| 00:00:01 |
-----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter("BEVERAGE"=:DRINK)

With this new query we get a new plan which has Index Fast Full Scan or FTS. If we now assign a different value for the bind variable like Coffee.

SQL> exec :drink :='Coffee';

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.01
16:52:44 SQL> select count(*) from survey
16:52:48 2 where beverage= :drink;

Elapsed: 00:00:00.03
Execution Plan
----------------------------------------------------------
Plan hash value: 3060591156

-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 6 | 50 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 6 | | |
|* 2 | INDEX FAST FULL SCAN| DRINK_IDX | 26667 | 156K| 50 (0)| 00:00:01 |
-----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter("BEVERAGE"=:DRINK)

The query is same, it is shared and the first plan is re-used even though the value for the bind variable has changed. In this case the same plan is not the optimal plan for this value. Oracle has peeked on the value of :drink and chosen the optimal plan once again. When bind variables are used in a statement, it is assumed that cursor sharing is intended and that the plan chosen for any set of binds peeked will produce acceptable performance for all sets of binds. If different invocations of the cursor would significantly benefit from different execution plans and this is critical to the application, then you should consider whether using bind variables for the query is appropriate in this case.

The bind peeking which is enabled by default. Following is the command to disabled it.

alter system set "_optim_peek_user_binds" = false scope=both;

Adaptive cursor sharing is introduced in Oracle 11g version. ACS is help in choosing the different execution plan for different bind variables value for SQL Query. From 11g, the adaptive cursor sharing feature enables a single statement that contains bind variables to use different execution plans for different binds. Overcome the use of single execution plan in case of bind variables. Adaptive cursor sharing is a solution to provide the shareability of binds, with the plan adaptability of literals. You can check the adaptive cursor sharing is enabled or not as below query.

select a.ksppinm name,
b.ksppstvl value,
b.ksppstdf deflt,
decode
(a.ksppity, 1,
'boolean', 2,
'string', 3,
'number', 4,
'file', a.ksppity) type,
a.ksppdesc description
from
sys.x$ksppi a,
sys.x$ksppcv b
where
a.indx = b.indx
and
a.ksppinm like '%_optimizer_extended_cursor_sharing%'
order by
name;

RMAN Duplicate Failing with Transparent Data Encryption

Hello,

RMAN Duplicate Failing with TDE “ORA-28365: wallet is not” open error.

archived log file name=/u01/app/oracle/product/19.0.0/dbhome_1/dbs/arch2_1897_1160948353.dbf thread=2 sequence=0
RMAN-00571: ===========================================================
RMAN-00569: =============== ERROR MESSAGE STACK FOLLOWS ===============
RMAN-00571: ===========================================================
RMAN-03002: failure of recover command at 03/28/2024 11:12:41
ORA-00283: recovery session canceled due to errors
RMAN-11003: failure during parse/execution of SQL statement: alter database recover logfile ‘/u01/app/oracle/product/19.0.0/dbhome_1/dbs/arch2_1897_1160948353.dbf’
ORA-00283: recovery session canceled due to errors
ORA-28365: wallet is not open

Let me configure AUTO_LOGIN wallet. Copy the wallet file (ewallet.p12) from source database server to new clone database server. You can check the wallet file location on source database from sqlnet.ora file.

Modify sqlnet.ora file in clone database ORACLE_HOME to reflect the location of the wallet file:


WALLET_LOCATION=
(SOURCE=
(METHOD=FILE)
(METHOD_DATA=(DIRECTORY= /u01/app/oracle/TESTDB/wallet/cert)))
ENCRYPTION_WALLET_LOCATION =
(SOURCE = (METHOD = FILE)
(METHOD_DATA =
(DIRECTORY = /u01/app/oracle/TESTDB/wallet/cert)
)
)

You must set wallet_root parameter to above wallet root directory.

SQL> show parameter wallet
NAME TYPE VALUE
———————————— ———– ——————————
ssl_wallet string
wallet_root string
SQL> alter system set wallet_root=’/u01/app/oracle/TESTDB/wallet’

SQL> show parameter wallet
NAME TYPE VALUE
———————————— ———– ——————————
ssl_wallet string
wallet_root string /u01/app/oracle/TESTDB/wallet
SQL>

Now, invoke orapki utility on the clone database server to make the wallet auto-login:

$ orapki wallet create -wallet /u01/app/oracle/TESTDB/wallet/cert -pwd "PASS" -auto_login

If above step is successful, you should find a new file is created in the same directory called cwallet.sso

You can validate wallet password as below mkstore command.

mkstore -wrl /u01/app/oracle/TESTDB/wallet/cert -list
orapki wallet display -wallet . -pwd PASSWORD

Now, STARTUP NOMOUNT the auxiliary instance and try the duplicate command.

How To Clean SYSAUX Tablespace? Purging data from WRI$_ADV_OBJECTS

Hello,

SYSAUX Tablespace grows rapidly and consumes more space. Querying V$SYSAUX_OCCUPANTS shows SM/ADVISOR on top.

SQL> SET LINES 120
SQL> COL OCCUPANT_NAME FORMAT A30
SQL> SELECT OCCUPANT_NAME,SPACE_USAGE_KBYTES FROM V$SYSAUX_OCCUPANTS ORDER BY SPACE_USAGE_KBYTES DESC;

And further querying DBA_SEGMENTS shows WRI$_ADV_OBJECTS consume more space in SYSAUX.

SQL> COL SEGMENT_NAME FORMAT A30
SQL> COL OWNER FORMAT A10
SQL> COL TABLESPACE_NAME FORMAT A10
SQL> COL SEGMENT_TYPE FORMAT A15
SQL> SELECT * FROM (SELECT SEGMENT_NAME,OWNER,TABLESPACE_NAME,BYTES/1024/1024 "SIZE(MB)",SEGMENT_TYPE FROM DBA_SEGMENTS WHERE TABLESPACE_NAME='SYSAUX' ORDER BY BYTES DESC) WHERE ROWNUM COL TASK_NAME FORMAT A35
SQL> SELECT TASK_NAME, COUNT(*) CNT FROM DBA_ADVISOR_OBJECTS GROUP BY TASK_NAME ORDER BY CNT DESC;

The Statistics Advisor Task(AUTO_STATS_ADVISOR_TASK) can be dropped to release the space occupied by that advisor output data.

DECLARE
v_tname VARCHAR2(32767);
BEGIN
v_tname := 'AUTO_STATS_ADVISOR_TASK';
DBMS_STATS.DROP_ADVISOR_TASK(v_tname);
END;
/

Once the task is dropped then all of its dependent task output data would be deleted from the WRI$_ADV_OBJECTS table. Now, let me reorganize the table WRI$_ADV_OBJECTS and its indexes after dropping the task.

SQL> ALTER TABLE WRI$_ADV_OBJECTS MOVE;
SQL> ALTER INDEX WRI$_ADV_OBJECTS_IDX_01 REBUILD;
SQL> ALTER INDEX WRI$_ADV_OBJECTS_PK REBUILD;
SQL> ALTER INDEX WRI$_ADV_OBJECTS_IDX_02 REBUILD;

You must ensure all indexes are valid.

SQL> column index_name format a30
SQL> select index_name,status from dba_indexes where table_name='WRI$_ADV_OBJECTS' ;

For Multitenant/PDB environment, reorganize the table and its indexes as follows:

SQL> alter session set container=;
SQL> exec dbms_pdb.exec_as_oracle_script('ALTER TABLE WRI$_ADV_OBJECTS MOVE');
SQL> exec dbms_pdb.exec_as_oracle_script('ALTER INDEX WRI$_ADV_OBJECTS_PK REBUILD');
SQL> exec dbms_pdb.exec_as_oracle_script('ALTER INDEX WRI$_ADV_OBJECTS_IDX_01 REBUILD');
SQL> exec dbms_pdb.exec_as_oracle_script('ALTER INDEX WRI$_ADV_OBJECTS_IDX_02 REBUILD');

Dropping the task AUTO_STATS_ADVISOR_TASK would cause errors as follows when the task name is referenced.

ORA-20001: Statistics Advisor: Invalid Task Name For the current user
If the above error happens, then recreate the AUTO_STATS_ADVISOR_TASK as follows to resolve the errors:

SQL> conn sys / as sysdba
SQL> EXEC DBMS_STATS.INIT_PACKAGE();

Recreating the task would again cause SYSAUX space to grow. Check whether the Auto Statistics Advisor task is created

SQL> select name, ctime, how_created, OWNER_NAME from sys.wri$_adv_tasks where name in ('AUTO_STATS_ADVISOR_TASK','INDIVIDUAL_STATS_ADVISOR_TASK');

If there are too many records in the table WRI$_ADV_OBJECTS for AUTO_STATS_ADVISOR_TASK, then huge UNDO would be required. In such cases, following method can be implemented to purge the data by avoiding excessive redo/undo generation.
Check the number of rows in WRI$_ADV_OBJECTS for Auto Stats Advisor Task.

SQL> SELECT COUNT(*) FROM WRI$_ADV_OBJECTS WHERE TASK_ID=(SELECT DISTINCT ID FROM WRI$_ADV_TASKS WHERE NAME='AUTO_STATS_ADVISOR_TASK');

CTAS from WRI$_ADV_OBJECTS to keep the rows apart from AUTO_STATS_ADVISOR_TASK

SQL> CREATE TABLE WRI$_ADV_OBJECTS_NEW AS SELECT * FROM WRI$_ADV_OBJECTS WHERE TASK_ID !=(SELECT DISTINCT ID FROM WRI$_ADV_TASKS WHERE NAME='AUTO_STATS_ADVISOR_TASK');
SQL> SELECT COUNT(*) FROM WRI$_ADV_OBJECTS_NEW;

Now, truncate the table

SQL> TRUNCATE TABLE WRI$_ADV_OBJECTS;

Insert the rows from backed up table WRI$_ADV_OBJECTS_NEW to restore the records of ther advisor objects.

SQL> INSERT /*+ APPEND */ INTO WRI$_ADV_OBJECTS SELECT * FROM WRI$_ADV_OBJECTS_NEW;

Note that, for 19c & above, use the below insert statement to avoid ORA-54013 error as there is a new column SQL_ID_VC added to WRI$_ADV_OBJECTS.

SQL> INSERT INTO WRI$_ADV_OBJECTS("ID" ,"TYPE" ,"TASK_ID" ,"EXEC_NAME" ,"ATTR1" ,"ATTR2" ,"ATTR3" ,"ATTR4" ,"ATTR5" ,"ATTR6" ,"ATTR7" ,"ATTR8" ,"ATTR9" ,"ATTR10","ATTR11","ATTR12","ATTR13","ATTR14","ATTR15","ATTR16","ATTR17","ATTR18","ATTR19","ATTR20","OTHER" ,"SPARE_N1" ,"SPARE_N2" ,"SPARE_N3" ,"SPARE_N4" ,"SPARE_C1" ,"SPARE_C2" ,"SPARE_C3" ,"SPARE_C4" ) SELECT "ID" ,"TYPE" ,"TASK_ID" ,"EXEC_NAME" ,"ATTR1" ,"ATTR2" ,"ATTR3" ,"ATTR4" ,"ATTR5" ,"ATTR6" ,"ATTR7" ,"ATTR8" ,"ATTR9" ,
"ATTR10","ATTR11","ATTR12","ATTR13","ATTR14","ATTR15","ATTR16","ATTR17","ATTR18","ATTR19","ATTR20","OTHER" ,"SPARE_N1" , "SPARE_N2" ,"SPARE_N3" ,"SPARE_N4" ,"SPARE_C1" ,"SPARE_C2" ,"SPARE_C3" ,"SPARE_C4" FROM WRI$_ADV_OBJECTS_NEW;
SQL> COMMIT;
SQL> ALTER INDEX WRI$_ADV_OBJECTS_IDX_02 REBUILD;
SQL> ALTER INDEX WRI$_ADV_OBJECTS_IDX_01 REBUILD;
SQL> ALTER INDEX WRI$_ADV_OBJECTS_PK REBUILD;

Drop the statistics advisor task from dictionary to refrain from executing.

DECLARE
v_tname VARCHAR2(32767);
BEGIN
v_tname := 'AUTO_STATS_ADVISOR_TASK';
DBMS_STATS.DROP_ADVISOR_TASK(v_tname);
END;
/

The Optimizer Statistics Advisor Task (AUTO_STATS_ADVISOR_TASK) can be recreated any time by running the following if DBA(s) wants to use the Statistics Advisor.

SQL> EXEC DBMS_STATS.INIT_PACKAGE();