Thursday, October 21, 2021

Exadata -- I/O Resource Manager / IORM / Inter-database configuration

As you may already know (actually, I think you definetely know since we are in 2021 and we are now talking about 9th generation of Exadata:), we have an IO Resource Manager in Exadata.. Actually, this is pretty old subject, but! I just could find a space to write it down. :)

Also check my previous post ( written in 2014) named "Exadata -- For Exadata Database Machine Admins -- Filtered Information" ->  https://ermanarslan.blogspot.com/2014/03/exadata-for-exadata-database-machine.html . 

In that post , I give a filtered information (including IORM , migration and other stuff)  for Exadata Admins.

The I/O resource manager is called IORM (acronym) and it is used for managing the Storage /Cell I/O resources in Exadata. In addition to the database resource manager and instance caging for the CPU-like resource management; we can also manage our I/O resource with IORM in Exadata)

Here is a diagram for the description of the architecture of IORM. (reference: Centroid)

So, we can manage our IO resources based on the Categories, Databases and consumer groups. There is a hierarchy as you see in the picture.. The hierarchy used to distribute I/O.

IORM should be used on Exadata especially if you have a lot of databases running on Exadata Machine.. IORM is a friend of consolidation projects, in my opinion..

In this post, I will give some info about the implementation and some example commands along with their purposes, used in real life.

This will be about implementing inter-database IO resource management and what we do in these types of implementations is basically managing the I/O resources of the Oracle Databases that are running on Exadata.. So, we do our work in the Cell/Storage level .. The configuration is per cell basis and we use cellcli and/or dcli to configure the Cells accordingly.

We use the unique names of the databases ( db unique name) while configuring the IORM inter database plans and basically we tell IORM to manage our I/O by following a set of rules.

Here is an example;

"Let %80 of the IO Resources to be used by EBS (while the Store layer is not under a heavy load).. Let %70 of the IO Resources to be used by DWH (while the Storage layer is not under a heavy load).. Don't let EBS to occupy more than %65 of the I/O Resources, while DWH is doing a heavy I/O. Don't Let DWH to occupy more than %35 of the I/O Resources while EBS is doing a heavy I/O.  Let other databases (not EBS, not DWH) to use the remaining I/O resources.. Don't let other databases to prevent EBS or DWH from using I/O resources when they needed."

Here is an example for configuring an IORM inter database plan;

We first check the current plan.. 

-----------------------

dcli -g ~/cell_group -l root cellcli -e list iormplan detail       (I hope you have a proper cell_group.. If you don't, you can create one or you can use cellcli for issuing the commands in each cell)

We set iorm plan objective to auto -> 

-----------------------

alter iormplan objective=auto (in each cell)  -- auto is a must .. This objective lets the IORM to decide the appropriate objective depending on the active workload on the cell.

or 

dcli -g ~/cell_group -l root cellcli -e alter iormplan objective = auto   (in one go using dcli)

We alter the cell to set our IORM plan.. Note that, we use "-" in the end of the lines (except the last line) and we can't use limit for "other" databases..  Using LIMIT attribute for other databases is not allowed -> CELL-00048: The limit attribute is not permitted when specifying dbplan "other" directives.  

Also note that, using LIMIT attribute, we can limit max I/O for a database. So, we ensure that database can not utilize more than that % of I/O resources.

Well, we connect to each cell and issue the following alter iormplan commands to tell IORM what to do while managing the IO resources of our databases;

-----------------------

alter iormplan -

dbplan=((name=EBSPRD, level=1, allocation=65, limit=80, flashcache=on),  -

 (name=DWPRD,  level=1, allocation=35, limit=70, flashcache=on),  -

 (name=other, level=2, allocation=10, flashcache=on))

With this action, we actually configured the IORM and we are done.. Still, we check the IORM plan is active -> 

-----------------------

dcli -g ~/cell_group -l root cellcli -e list iormplan detail

As for monitoring; we use metric_iorm.pl script. We get that script from MOS Note "Tool for Gathering I/O Resource Manager Metrics: metric_iorm.pl (Doc ID 1337265.1)" and follow the instructions documented there.

Okay.. This is pretty much it! I hope you find this useful.

Sunday, October 10, 2021

Erman Arslan's Oracle Forum / September 2021 - "Questions and Answers Series"

Question: How much time do you spend/lose?

Answer: Well, how much time I gain? :) 


Remember, you can ask questions and get remote support using my forum. 36 issues this month!
Just click on the link named "Erman Arslan's Oracle Forum is available now.
Click here to ask a question", which is available on the main page of Erman Arslan's Oracle Blog
-- or just use the direct link:  


Come on, let's see what we've been up to in September + in the beginning of October 2021. #amaerman
Do not forget to read the blog posts too :)

DR setup for ebs by satish

Reduce downtime for patching by satish

workflow notifications not received by raiq1

ORA-29024: Certificate validation failure by big

High load average in test server by satish

2572809.1 confusion by satish

Workflow oam configuration by satish

Applying missing patches ETCC by satish

dualfs by big

Authentication in apex by satish

JAR expiration date by big

Jar signing: issue with adsign.txt and admin not creating proper jarlist.txt by iqbaljawaid138

incremental update scripts by Roshan

Patch "27491934" overlays " 14825718 ". Conflict check between them is skipped. by satish

RMAN RETENTION POLICY by big

Smtp server - backup scripts by satish

Additional Core addition R12.2 RAC by satish

FA custom value set - error disabling values by satish

Security question by satish

forefully change a password after login by raiq1

slow performance by big

ACL by big

Apex Ebs queries by satish

Workflow issue by satish

sysadmin cannot connect by big

adkeystore and adsign by big

golden gate index issue by Roshan

Oracle data block corruption error in ebs database by raiq1

Apex ORDS EBS by satish

House Keeping in EBSR12 by raiq1

find command impact. by raiq1

Upgradation of grid infrastructure on Exadata X7-2 by Zaheer

Restore RMAN Backup of 11g on 19C by Zaheer

Disk satuaration by satish

DB upgrade (11.2.0.3 to 11.2.0.4) by Barzu

Smtp server - sending email by satish


Saturday, October 9, 2021

Exadata / RDBMS -- DBCA fails KFOD-00101: LRM error [110] - [DBT-05801] There are no ASM disk groups detected.

This time I will keep it short..

This is for the ones who use RAC or Exadata or ASM or GRID .. Should I keep going ? :)

Well, in a migration project we were using XTTS. The target was Exadata ( actually it is needless to say:) It was a new one though.. An Exadata X8-2M.. (Actually, not so new.. Already started talking about Exadata X9-2) 

Anyways, we were creating the target database using DBCA to do the things by the MAA documents and to make it clean.. DBCA failed with KFOD-00101: LRM error [110] .. 

KFOD-00101: LRM error [110] while parsing command line arguments
SEVERE: Oct 08, 2021 2:02:42 PM oracle.install.commons.util.exception.AbstractErrorAdvisor getDetailedMessage
SEVERE: [FATAL] [DBT-05801] There are no ASM disk groups detected.
CAUSE: ASM may not be configured, or ASM disk groups are not created yet.
ACTION: Create ASM disk groups, or change the storage location to File System.

KFOD 101 error was a well known one but! the LRM "110" error was not so famous, so we did a strace check. strace showed that DBUA was trying to read an unrelated init.ora file which was located in the $GRID_HOME/dbs directory.. 

That init.ora was placed there accidentally by the customer. So we removed it. This action solved the problem.  Okay. I think this post is over :)

However, let me also point out one more thing;

I found this worth sharing with you, because it looked pretty interesting before we found the cause. 

Maybe it still is..!  It shows how fragile the environments, the binaries and the tools are. So we need to keep it clean not only to increase our efficieny but also to avoid unnecessary errors.

So , we should keep the environment clean (including our GRID & Database environment:)

EBS / RDBMS -- 19C Upgrade -- Post Upgrade fails "Unable to determine whether the database is pluggable (PDB) or not."

Here I 'am here writing after a long investigation. A long investigation on an error encountered txkPostPDBCreationTasks.pl. I hear you saying -> txkPostPDBCreationTasks again! :) 

Yes. It is a little buggy I think :)

Actually, this time (again!:) the problem was super clear.  I checked the java code and here is what was happening;

The txkPostsPDBCreationTasks.pl was trying to run adbldxml and adbldxml was trying to run the java "GenerateContext" in turn and, GenerateContext was calling getPDBCDB method and that getPDBCDB method was just trying to execute a simple query to check the container configuration -> "select name from v$pdbs" ! just a query to v$pdbs.. No sophisticated check was there! That was it and that v$pdbs was already populated correctly in the database.. No problems with the connection of sqlplus, listeners (both scan and local) were  registered, v$pdbs was correct, no related invalids in the db, the documents followed line by line! .. So the java code was failing somehow.. 

Note that, adbldxml.pl was also failing..

I must admit that, we tried lots of things even though we believed that it was a pure java problem..

As for the solution, we created an Oracle SR and Oracle Support sent us a new adbldxml.pl. We replaced the original adbldxml.pl with the original one and the problem dissapeared!

A quick check showed the difference in getJava_Cmd method.

It seemed the new adbldxml had hard coded $ORACLE_HOME/appsutil/jre , which is set to jre_top.

Earlier, (probably) it was set to $ORACLE_HOME/jdk/jre.

The problem was associated with the following bug : 

Bug 31222688 - ADBLDXML.PL SCRIPT FAILS IN TXKPOSTPDBCREATIONTASKS.PL

I will revisit this blog post and give you the patch number (Ofcourse if we will have one...)

EBS / RDBMS -- 19C Upgrade -- Post Upgrade fails due to missing jar (orai18n.jar) in classpath

Upgrading an EBS RAC Database to 19C (RU 12 & OJVM 12) requires the MOS note "Using Oracle 19c RAC Multitenant (Single PDB) with Oracle E-Business Suite Release 12.1 (Doc ID 2530680.1)" to be followed, and there you will do lots of stuff including the post upgrade tasks... 
Today's issue is encountered while executing the txkPostPDBCreationTasks.pl. ( a post upgrade task actually)

I won't go into the details about the actions that we take for this complex upgrade work (it is complex, because it is EBS! :), but! I will give you the solution that we designed and implemented for getting rid of the following errors in txkPostPDBCreationTasks.pl run;

StackTrace:
java.sql.SQLException: Non supported character set (add orai18n.jar in your classpath): WE8ISO8859P9
at oracle.sql.CharacterSetUnknown.failCharsetUnknown(CharacterSetFactoryThin.java:233)
at oracle.sql.CharacterSetUnknown.convert(CharacterSetFactoryThin.java:194)
at oracle.jdbc.driver.PhysicalConnection.throughDbCharset(PhysicalConnection.java:10425)
at oracle.jdbc.driver.PhysicalConnection.enquoteIdentifier(PhysicalConnection.java:10502)
at oracle.jdbc.driver.OracleStatement.enquoteIdentifier(OracleStatement.java:6452)
at oracle.jdbc.driver.OracleStatement.getColumnIndex(OracleStatement.java:3853)
at oracle.jdbc.driver.InsensitiveScrollableResultSet.findColumn(InsensitiveScrollableResultSet.java:270)
at oracle.apps.ad.autoconfig.RestoreProfile.createRestoreFile(RestoreProfile.java:294)
at oracle.apps.ad.autoconfig.RestoreProfile.generateRestoreScript(RestoreProfile.java:128)
at oracle.apps.ad.autoconfig.AppltopDrivers.main(AppltopDrivers.java:1426)

It is needless to say that, we've already put orai18n.jar in the correct directories, as it is stated in the upgrade documents but here we are, still failing unexpectedly in the post upgrade tasks..

The exact phase that we failed was the autoconfig and the failing script (autoconfig executes a bunch of script to do its work, as you know..) was adgentns.pl (+adconfig.pl).

It  was obvious that the issue was related with the classpath.. classpath that is passed to java.. 
adgentns.pl was failing but adclone.pl was also requiring a change.

So I checked the code ( the perl scripts adgentns.pl and adconfig.pl) and added the ora18in.jar in to the classpaths defined there in those perl scripts.. Those perls script execute java and I modified their classpaths (added ora18in.jar) used for executing those java .. (this action requires some knowledge in perl, bytheway) With this action, the issue was fixed! So we could continue the remaining tasks and finished the upgrade! 


No other solution is available at the moment.. 

This should also be directed to development, right? Ofcourse we did it at by opening a SR. However; we fixed the issue on ourselves and could continue upgrading.

I will revisit this blog post and update it with a patch number.. (probably.. because I think the development will write a fix for it.)

Tuesday, October 5, 2021

EBS / RDBMS -- 19C Upgrade -- DBUA fails at %50 -- due to failing JAVA check -- JServer has not been correctly loaded into the database

Recently encountered this issue while upgrading an EBS 12.1 database to 19C ( 11.2.0.4 to 19C RU 12--currently the latest one).

Oracle 19C home opatch information:

opatch lspatches

28318139;ORA-31003 ERROR WHEN IMPORTING FULL DATABASE IN PARALLEL

31424070;APPSST19C XTTS PDB - TABLE IMPORT/CREATION FAILED WITH ORA-39083 ORA-14334

32904851;Database Release Update : 19.12.0.0.210720 (32904851)

32876380;OJVM RELEASE UPDATE: 19.12.0.0.210720 (32876380)

29585399;OCW RELEASE UPDATE 19.3.0.0.0 (29585399)

These kinds of unexpected failures are annoying, especially in EBS 19C upgrades where we upgrade the OS, GRID and Databases.. Note that we even containerize the database (in a Single CDB and Single PDB form) during these upgrades and failing even during the DBUA run brings us an extra and unexpected cost..

Besides, we apply lots of apps patches to be in the tatest Tech. code level and to make apps tier be interoperable with 19C.. Well, we do and need to do lots of thing but we fail during DBUA run! 

Luckily we have fixes /or workarounds :)

Let's see today's issue and the solution we implemented;

We were trying to upgrade our 11.2.0.4 EBS database to 19C using DBUA.

DBUA failed at %50.. It basically could not validate the Java packages and Java Virtual Machine.. Those components were VALID before the upgrade, but during the upgrade they became INVALID.



Note that, we didn't cancel , we didn't abort our DBUA sesssion and checked the logs.. (if we could fix the issue,we could just push the Retry button and we could make DBUA continue from where it left off)

The log clearly showed the following and it was the reason that made DBUA complain ->

SQL> BEGIN

IF sys.dbms_registry.is_loaded('JAVAVM',sys.dbms_registry.release_version) != 1 THEN

RAISE_APPLICATION_ERROR(-20000,

'JServer has not been correctly loaded into the database.');

END IF;

END;

 /

ERROR at line 1:

ORA-20000: JServer has not been correctly loaded into the database.

ORA-06512: at line 3

SQL> comp_name, status from dba_registry

Oracle Database Catalog Views UPGRADED

Oracle Database Packages and Types UPGRADED

JServer JAVA Virtual Machine VALID

Oracle Database Java Packages INVALID

Oracle XDK UPGRADED

Oracle Real Application Clusters UPGRADED

OLAP Analytic Workspace UPGRADED

Oracle Multimedia UPGRADED

Spatial UPGRADED

Oracle Text UPGRADED

Oracle XML Database UPGRADED

Oracle OLAP API UPGRADED

OLAP Catalog OPTION OFF


Oracle Database Java Packages was INVALID.  As a result of that; sys.dbms_registry.is_loaded couldn't return 1.. The problem was invalid objects and actually those were supposed compiled in the later stage of the upgrade.. However; it seems we needed to have some of those objects valid even during the upgrade.. So this seemed like an issue which couldn't be predicted by Oracle.

Note that we also had ORA-06598 and it was ignorable.. Unrelated with this issue but just wanted to share: ORA-06598: insufficient INHERIT PRIVILEGES privilege error during upgrade from 11.2.0.2 to 12.1 using DBUA ( Doc ID 1911119.1 )

Anyways; we had a guaranteed restore point but we didn't want to restore our database and retry the failing operation because, probably; we would get exactly the same error in our next try. 

Okay let's jump to the conclusion;

We fixed the issue by following the action plan below;

We executed urltp.sql (compiled the invalids) .. We executed it from the 19C env.. We run utlrp.sql 3-4 times to make sure that the dependent objects are validated as well (if they could be valid ofcourse)) .. Executing ultrp 3-4 times was logical.. We were in the middle of an upgrade, and normally we had thousands of invalid at that moment.. So multiple executions of utlrp was logical to be sure that all the objects that can be validated, were handled correctly by this compilation process.

Once the compilation was finished, we pushed the retry button in the failed DBUA session.. It failed in the first attempt (due to its failed/closed) session, but the second attempt it could continue and the issue was resolved.. Upgrade wass fnished successfully , no invalid components in the dba registry and we just got it resolved!

Seems like this error we faced during the upgrade may be a common issue for 11.2.0.4 to 12.1(or higher) upgrades. But it was interesting. So I just noted it down and wanted to share!

Friday, September 3, 2021

Erman Arslan's Oracle Forum / August 2021 - "Questions and Answers Series" -- 45 interesting Questions/Issues this month!

Question: How much time do you spend/lose?

Answer: Well, how much time I gain? :) 

Remember, you can ask questions and get remote support using my forum. 45 issues this month!
Just click on the link named "Erman Arslan's Oracle Forum is available now.
Click here to ask a question", which is available on the main page of Erman Arslan's Oracle Blog
-- or just use the direct link:  


Come on, let's see what we've been up to in August + in the beginning of September 2021. #amaerman
Do not forget to read the blog posts too :)



















Topics (1766)Sub Forum
 Smtp server - sending email by satishEBS 12.2
 Confusion on jdk/jre by satishEBS 12.2
 golden gate index issue by RoshanDatabase
 Restore RMAN Backup of 11g on 19C by ZaheerDatabase
 Time setting in erp by satishEBS 12.1/12.0/11i
 NIC alias in Rhel 7 oracle rac by satishRAC
 RDS over UDP by satishRAC
 DB upgrade (11.2.0.3 to 11.2.0.4) by BarzuDatabase
 golden gate trail reader by RoshanDatabase
 Identifying number of hardware devices multipathLinux
 Apex installation in ebs by satishEBS 12.2
 Lun’s selection in 2 node rac by satishRAC
 mount filesystem linux by RoshanLinux
 Permission to only one directory by satishLinux
 Disabling path in multipath by satishLinux
 Multipath pre-requisites by satishDatabase
 Error in listener log by satishDatabase
 Prerequisite for configuring FMW 11.1.1.9EBS 12.2
 Firing alerts from shell scripts using smtp in RedHatDatabase
 JRE and JDK with ebs by satishEBS 12.2
 JAR expiration date by bigEBS 12.2
 SEC_CASE_SENSITIVE_LOGON by bigDatabase
 If Forgot your password by bigEBS 12.1/12.0/11i
 Configure WorkFlow mailer by bigEBS 12.1/12.0/11i
 Report Manager not working for office 365 in oracle r12.1.3  EBS 12.1/12.0/11i
 Error opening oat page for specific user in r12EBS 12.2
 Install 12c rootpre.sh by bigDatabase
 Smtp test by satishEBS 12.2
 OJVM patch 12c database l by satishEBS 12.2
 java.lang.UnsatisfiedLinkError: njni11EBS 12.2
 Adop prepare failed by bigEBS 12.2
 OS Upgrade of Exadata x6-2 by ZaheerEXADATA
 Cannot find or open library file: -l java by bigDatabase
 Upgrade OBIEE 11g to OAS 5.5/ 5.9 by ZaheerFMW WLS
 adcfgclone.pl on DB tiers by bigEBS 12.2
 Data from PROD to DEV by bigEBS 12.2
 Blank Page when connecting by bigEBS 12.2
 FRM-40833 FRM-40735 Opening Any Forms After 12.2.4 - 12.2.8 upgradeEBS 12.2
 PDB Using txkCreatePDB.pl PDB conversion failed Database
 resize redo logs to decrease archivelog generationDatabase
 adopclone_devserver folder is missing by bigEBS 12.2
 Refresh DB ORACLE_HOME by bigEBS 12.2
 Oracle homes refresh in rac environment to latest PSUEBS 12.2
 Browser supporting R12.2.5 forms users by satishEBS 12.2
 HTML Agent by bigEBS 12.2

Tuesday, August 17, 2021

Exadata X8M-2 & PCA X8-2 -- Part 3 Migration / Datapump for relatively small tables and indexes + Datapump dump file I/O

We have used online redefinition for moving big tables with big LOB columns from one tablespace to another and we have seen it in the previous post.

In this post, we will take a look at the datapump process that we used for moving the small sized tables ( LOB-free tables smaller than 10GBs -- )

Datapump is a tool that we use in logical migrations, some logical backups and in some other daily operations, sometimes for the upgrades and I think you all know that. So this blog post is written for telling you the story, the general process -- not the details of the well known datapump tool. 

Let's start with an interesting event that we suddenly found ourself in..  That is, datapump export was very slow. We were exporting the data into an ACFS mount exported from an Exadata (using NFS --through a 10 gig network).. So it shouldn't be anywhere near slow.. But! suprisingly it was...

We saw datapump dump file I/O events in the parallel export sessions.. So we suspected from the ACFS..  We did a couple of dd tests on the server (HP UX in this case).. Pure sequential I/O to the NFS share was slow.. However; dd tests on Exadata side performed well.. Then we saw that a parallel & full rman backup was running on Exadata side. A backup software (through a rman channel) was transffering the blocks to a network storage.. There was no backup network there.. So it was the network bandwitdh causing the slowness.. Our ACFS I/O was based on NFS in the first place, so cancelled the backup and everything went fine!  -- an interesting event, right? 

Anyways, just for the quick info, we are moving tables from one tablespace to another just to get rid of an offline, unrecoverable datafile because it prevents us using XTTS for our main goal. That is, migrating one of our database from HPUX to Exadata X8-2M..

Let's tell this datapump part of the story like we're doing it right now;

We have a limited downtime, so the process should be quick.. This is a production and that's why the process should be complete & error-free as well..

Here is the process;

  • Before importing the tables, we disable the DDL trigger (usually we have at least one in almost every customer environment, and usually they create problems -- grant-related access problems --during import/impdp ..)
  • We also ensure that we have the required free space in the target tablespace and we also ensure the users of the objects that we are planning to move, have quota on the target tablespace.
  • We check the current situation, I mean row counts, table counts, constraints, MV logs, index counts, object validity, grants etc, and we note all the check that we do at this point.. ( we will compare them with the checks that we will do after we complete movimng the objects to the target tablespace)

Some easy examples for the check queries:

select table_name from dba_tables where tablespace_name='ERMAN_TBS';

select count(*) from dba_tables where tablespace_name='ERMAN_TBS'; 

select  index_name from dba_indexes where tablespace_name='ERMAN_TBS';

select  count(*) from dba_indexes where tablespace_name='ERMAN_TBS';

select index_name from dba_indexes where table_name in (select table_name from dba_tables where tablespace_name='ERMAN_TBS');

select count(*) from dba_indexes where table_name in (select table_name from dba_tables where tablespace_name='ERMAN_TBS');

select trigger_name from dba_triggers where table_name in (select table_name from dba_tables where tablespace_name='ERMAN_TBS');

select count(*) from dba_triggers where table_name in (select table_name from dba_tables where tablespace_name='ERMAN_TBS');

select * from dba_tab_privs where table_name in (select table_name from dba_tables where tablespace_name='ERMAN_TBS');

select count(*) from dba_tab_privs where table_name in (select table_name from dba_tables where tablespace_name='ERMAN_TBS');

select owner, object_type, count (*) from dba_objects where status='INVALID' group by owner, object_type order by 1,2;

  • We get our downtime, shutdown the apps tier, shutdown the db listener, ensure we have no sessions in the database, no session other than us.. Ofcourse we can also take other session-blocking-actions, but these are enough in lots of the cases..
  • We export the tables we interested in;
Example command:

nohup expdp \"/ as sysdba\" DIRECTORY=ERM_DIR  EXCLUDE=TABLE:\"IN\(\'S_ERMAN\',\'S_ERMAN_INTERIM\',\'S_ERM_EMP\',\'S_ERM_LOG\',\'S_ERM_ITEM\',\'S_ERM_RP_LOG\'\)\"   DUMPFILE=ERM_%U.dmp  LOGFILE=ERM_20210813.log TABLESPACES=ERMAN  PARALLEL=8 &

  • Then we import them into the new tablespace. I will not give all the details about the datapump arguments used in this example. I think you already understand what we are trying to do here, so the arguments are aligned with our goal. (If not read above once again + read the previous blog post..)
nohup impdp \"/ as sysdba\" DIRECTORY=ERM_DIR DUMPFILE=SDATA_%U.dmp LOGFILE=imp_ERM_20210813.log table_exists_action=replace remap_tablespace=ERMAN:ERMAN_NEW PARALLEL=8 &       

  • After the datapump import, we do our checks(object comparison etcs..), compile invalids, take the corrective actions for the errors that we may have during the import..
  • Finally, we enable the DDL trigger (if we have one) and start our listener + applications
That's it.. 

At this point, we can get rid of that problematic datafile residing in the old tablespace.. We moved everything from that tablespace to the new one, right? It is time to drop the old tablespace (optional) and to continue on our way with the Exadata XTTS migration.

Friday, August 13, 2021

Exadata X8M-2 & PCA X8-2 -- Part 3 Migration / ONLINE REDEFINITION for Big LOB Tables

In the previous post, I mentioned that we decided to move the objects residing in the problematic tablespace ( having an offline datafile) to a new tablespace and we decided on a hybrid method for accomplishing this task. We planned to move the big LOB tables using the Online Redefinition .. In addition to that, we decided to use datapump (expdp - impdp) to move the small sized tables to the new tablespace with a minimal downtime.

In this blog post, I will take a look at the Online Redefinition side of the work and give you the general information about the process.

First of all , we couldn't move tables online with the alter table move online clause, since the database version was 12.1.

We couldn't use expdp-impdp to move the big LOB tables, because it required a big downtime +  the LOBs were Basicfile -- expdp can not leverage parallelism for the Basicfile lobs.

So, we decided to move those big lob tables (some of them were bigger than 1.5 TB) using online redefitinion and it almost perfectly worked!

Note that, no one needs to be afraid of the online redefinition as it is used with basic API calls and it is pretty straight forward. It is based on the materialized views (MVs) and refresh technology that we already have in Oracle Databases for a very long time.. 

What happens in the background is; a MV based refresh and alter table rename based switch operations..

So, a MV is created, then it is fully refreshed and then it is synched with the fast refreshes (by the help of the MV logs) and then the object names are switched -- just after the final last sync... 

All of these are done via API. So you don't need to know the internals to do the work..

Let's go through the process with an example;

We first created our target/new tablespace with the CRATE TABLESPACE caluse;

CREATE TABLESPACE ERMAN_NEW DATAFILE '+ERM' SIZE 32767M AUTOEXTEND ON NEXT 1G MAXSIZE 32767M, '+ERM' SIZE 32767M AUTOEXTEND ON NEXT 1G MAXSIZE 32767M, '+ERM' SIZE 32767M AUTOEXTEND ON NEXT 1G MAXSIZE 32767MLOGGING
DEFAULT NO INMEMORY ONLINE EXTENT MANAGEMENT LOCAL AUTOALLOCATE BLOCKSIZE 8K SEGMENT SPACE MANAGEMENT AUTO FLASHBACK ON;

We checked if we can do use online redefition for moving the table that we interested in.
BEGIN DBMS_REDEFINITION.CAN_REDEF_TABLE('ERMAN','S_ERMAN', DBMS_REDEFINITION.CONS_USE_ROWID); END; /

We checked the source LOB columns.. We didn't want to get ORA-01555 or ORA-22924 in the middle of our operation.. So we used a big enough LOB retention (based on undo retention) or PCTVERSION 100 for the source LOB columns.. ( we alter them that way..)

Note that; if you see ORA-22924 in the same error stack with ORA-01555 then it means; the problem is directly related with the LOBs.

Error: ORA-22924
Text: snapshot too old
---------------------------------------------------------------------------
Cause: The version of the LOB value needed for the consistent read was already overwritten by another
writer.

Note that, we use PCTVERSION or RETENTION, not both at the same time.

select table_name, segment_name, pctversion, retention
from dba_lobs where table_name in ('S_ERMAN');

In our case we used PCTVERSION.. In our case, using PCTVERSION was a more guarenteed method.

Some examples for altering the LOBs -> 

alter table ERMAN.S_ERMAN modify lob(VIDEO) (retention);
alter table SIEBEL.S_ERMAN modify lob(PICTURE) (PCTVERSION 100);

Well, after creating the new tablespace and altering the LOBs, we created our target table.. Target table had the same structure as the source ( ofcourse we could do some improvements in the definitions in the definition, like changing the LOBS from basicfile to securefile).. We created the new table in the new ta lespace..

CREATE TABLE ERMAN.S_ERMAN_NEW(
ROW_ID VARCHAR2(15 CHAR), CREATED DATE DEFAULT sysdate, CREATED_BY VARCHAR2(15 CHAR), LAST_UPD DATE DEFAULT sysdate,
.....
...

LOB (PICTURE) STORE AS SECUREFILE ( TABLESPACE ERMAN_NEW ENABLE STORAGE IN ROW CHUNK 8192 RETENTION AUTO NOCACHE LOGGING STORAGE ( INITIAL 64K NEXT 1M MINEXTENTS 1 MAXEXTENTS UNLIMITED PCTINCREASE 0 BUFFER_POOL DEFAULT ))
...
LOGGING NOCOMPRESS NOCACHE MONITORING ENABLE ROW MOVEMENT;

We checked our redologs and ensure they are aligned to support this heavy operation.

SELECT a.GROUP#, a.THREAD#, a.SEQUENCE#, a.ARCHIVED, a.STATUS, b.MEMBER AS REDOLOG_FILE_NAME, (a.BYTES/1024/1024) AS SIZE_MB FROM v$log a JOIN v$logfile b ON a.Group#=b.Group# ORDER BY a.GROUP#;

We might add some redologs if we thought that it is required for the operation.. ( Big tables would produce big redo -- and archivelogs)

Example: ALTER DATABASE ADD LOGFILE GROUP 4 ('+ERMAN','+RECO') SIZE 2048M;

Well, we started our redefitinion operation finally :) -> 
--we started it with 4 parallel in the case.

ALTER SESSION FORCE PARALLEL DML PARALLEL 4; 
ALTER SESSION FORCE PARALLEL QUERY PARALLEL 4; 
BEGIN DBMS_REDEFINITION.START_REDEF_TABLE( uname => 'ERMAN', orig_table => 'S_ERMAN', int_table => 'S_ERMAN_NEW', options_flag => DBMS_REDEFINITION.CONS_USE_ROWID);
 END; /

Note that, if we have a primary key in the source table, then we use CONS_USE_PK instead of CONS_USE_ROWID..

START_REDEF_TABLE takes some time as it is where the initialization/full copy happens.

After the START_REDEF_TABLE completed, we copied the dependent objects from the source table to target table.

DECLARE error_count pls_integer := 0; BEGIN DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS('ERMAN', 'S_ERMAN', 'S_ERMAN_NEW', dbms_redefinition.cons_orig_params, FALSE,TRUE,TRUE,FALSE, error_count); 
DBMS_OUTPUT.PUT_LINE('errors := ' || TO_CHAR(error_count)); END; /

Note that, if you  have materialized view logs on the table that you want to redef, then you should consider using copy_mvlog argument of copy_table_dependents.. It should be TRUE (by default it is false).. Alternatively, you should leave it FALSE , and recreate MV logs after you finish redef.

You can check the definition of the arguments used in COPY_TABLE_DEPENDENTS procedure, but one thing to point out for our case is that, we told the procedure to not to copy the triggers.. 

DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS( uname IN VARCHAR2, orig_table IN VARCHAR2, int_table IN VARCHAR2, copy_indexes IN PLS_INTEGER := 1, copy_triggers IN BOOLEAN := TRUE, copy_constraints IN BOOLEAN := TRUE, copy_privileges IN BOOLEAN := TRUE, ignore_errors IN BOOLEAN := FALSE, num_errors OUT PLS_INTEGER, copy_statistics IN BOOLEAN := FALSE);

We did so, because of a bug in our release , an ORA-600 produced in the later sync phase.. 
(ORA-00600: internal error code, arguments: [kglidinsi1], [2], [], [], [], [], [], [], [], [], [], [])

So we decided to create the triggers manually just after the redef is finished / just before letting applications to access the new-current table..

Just after copying the dependents objects, we put an exclusive lock in the table.. (ofcourse relevant application modules were stopped at the same time)  Normally, you don't have to do this but we just wanted to guarantee the no-access. We wanted to guarantee that because in case of a failure in the later stages of the redefitinion, we might want to continue the redefitinion manually.. I mean dropping the MV and making the new table the actual one manually. 

--again; it is not a must.
LOCK TABLE ERMAN.S_ERMAN IN EXCLUSIVE MODE;

So before finishing our redef , we compared the target and source tables and ensured they are structurally similar. We also checked the invalid object count just in case. We even checked the row counts -- just in case.

select * from dba_objects where status='INVALID'; 
select * from dba_triggers where table_name='S_ERMAN'; 
select * from dba_indexes where status!='VALID'; 
select count(*) from ERMAN.S_ERMAN;
select count(*) from ERMAN.S_ERMAN_NEW;
select count(*) , 'source_table' from dba_constraints where table_name='S_ERMAN' UNION ALL select count(*) ,'interim_table' from dba_constraints where table_name='S_ERMAN_NEW'; 
select count(*) , 'source_table' from dba_triggers where table_name='S_ERMAN' UNION ALL select count(*) ,'interim_table' from dba_triggers where table_name='S_ERMAN_NEW';
select count(*) , 'source_table' from dba_indexes where table_name='S_ERMAN' UNION ALL select count(*) ,'interim_table' from dba_indexes where table_name='S_ERMAN_NEW';

Well at this point we synchronized the new table; ( a fast refresh)
EXEC DBMS_REDEFINITION.sync_interim_table('ERMAN','S_ERMAN','S_ERMAN_NEW'); 

Lastly, we finished the redef, and our new table was actualized at this point.

.EXEC DBMS_REDEFINITION.finish_redef_table('ERMAN','S_ERMAN','S_ERMAN_NEW');

Note, in case you get any errors in this stage, you should check the detail of the error and get the information about which stage it failed and then you may find a way to continue manually from there.. However, what is recommended is to abort the redef, solve the problem and start another redef/retry.

Abort redef example:

EXEC DBMS_REDEFINITION.abort_redef_table('ERMAN','S_ERMAN','S_ERMAN_NEW');

Well, after the redef was finished, we checked the new table and ensured it is actualized and its name was switched with the old current table and it was now in the new tablespace..

select table_name,tablespace_name from dba_tables where table_name in('S_ERMAN','S_ERMAN_NEW');

Note that, S_ERMAN is the new table now and it is in the new tablespace.. So names/tables were switched!

2 important notes on 2 dangerous points;

1) Table statistics are important. If you do not copying statistics in the copy dependents phase, then you may get yourself in to trouble. So either copy them in the copy dependents phase or copy them before starting the redef phase -- manually (this is also a little adventurous --  I mean copying table stats from one table to another in the same database is a little tricky and requires a hack and it is not always successful..)
Statistics level is also important.. In some environments, column-level should also be there..

Stats collection example: 

EXEC dbms_stats.gather_table_stats('ERMAN','S_ERMAN', method_opt=> 'FOR ALL COLUMNS SIZE AUTO', granularity => 'ALL', degree => 8 ,cascade => true, estimate_percent => dbms_stats.auto_sample_size);

Note that, we also have copy_statistics argument available in copy_table_dependents.. So we may even make redefinition to that statistics task during our redef process...

2) Constraints may be created in the target table without enable validate.. So you might need to alter the target table to make them enable validate..

Well, before finishing the work we did the following checks;

--Check errors 
 SELECT OBJECT_NAME, BASE_TABLE_NAME, DDL_TXT FROM DBA_REDEFINITION_ERRORS;

- VERIFY THAT THE PRMARY KEY WAS COPIED TO THE REDEFINED TABLE 

 select DBMS_METADATA.GET_DDL('TABLE','S_ERNAN','TEST') FROM DUAL;

We might drop the old table.. But we didn't.. We didn't have a space pressure and the migration that we would do later was based on XTTS method. So we have the opportunity to tell the XTTS not to migrate the old tablespace in the first place.

-- DROP THE OLD TABLE (as it is no longer needed) 
 drop table S_ERMAN_NEW;

Okay. I suppose we are done for today :)

Next post will be about those remaining small tables which were moved using datapump.. 
I know using datapump is superclear for most of you, but we are telling our story here, story of a big migration project :) So I try to explain every stage and want to share real life cases as much as I can :) 

Stay tuned.