Search This Blog

Friday, June 18, 2021

Oracle 19c Preinstall-What does it actually do?

I set up a lot of systems, lately about a new RAC cluster a week.  We use a lot of automation and scripting, but if some of that can be done for you, that just makes it even easier. I love what the pre-install Oracle DB rpm provides.  How do you use it?

yum install oracle-database-preinstall-19c.x86_64 

About 30 seconds later, the system is 99% ready for a RAC install.  In a previous post <<click here>>, I detailed how to download the version 12 RPM and modify it to work with Redhat.  That's no longer necessary, the 19c version will install into RHEL...there's no longer a requirement on OEL.  You may still want to look at that post to see how to make modifications to the RPM (for instance, how to change the parameters, the UID's and GID's to match your environment.)

Recently I had an issue where I was getting different results on my test system than other people were getting, and I suspected it came down to the OS parameters that were being set.  I had used a minimal RHEL 7 install and added the pre-install rpm.  I knew roughly what that did, but not the details.  I looked up the Oracle documentation and all I found was this (for 12c):

When installed, the Oracle Preinstallation RPM does the following:

  • Automatically downloads and installs any additional RPM packages needed for installing Oracle Grid Infrastructure and Oracle Database, and resolves any dependencies
  • Creates an oracle user, and creates the oraInventory (oinstall) and OSDBA (dba) groups for that user
  • As needed, sets sysctl.conf settings, system startup parameters, and driver parameters to values based on recommendations from the Oracle RDBMS Pre-Install program
  • Sets hard and soft resource limits
  • Sets other recommended parameters, depending on your kernel version


Ok...that's not very detailed.  If you go to a sysadmin and say "I set other recommended parameters..." he'll have lots of follow up questions for you....

So...I once again tore open the RPM, found where the logs were sent and went through them.  This is what is ACTUALLY does:

When you install the RPM, it verifies several other rpms exist that are needed for Oracle (or installs them if they're missing).  If these rpms require rpms you don't have, yum will install those too.  Here's the list:

procps module-init-tools ethtool initscripts bind-utils nfs-utils util-linux-ng pam
xorg-x11-utils xorg-x11-xauth smartmontools
binutils glibc glibc-devel
ksh libaio libaio-devel libgcc libstdc++ libstdc++-devel
make sysstat openssh-clients
psmisc net-tools unzip bc tar

...in addition, 

if you're on RHEL7, it'll also require compat-libcap1

if you're on RHEL8, it'll require both libnsl compat-openssl10

The next thing it does is add the required OS groups.  They are:

oinstall,dba,oper,backupdba,dgdba,kmdba,racdba

...and then creates the oracle OS user and puts it in those groups.

Next, it adjusts settings in sysctl.conf:

fs.file-max = 6815744
kernel.sem = 250 32000 100 128
kernel.shmmni = 4096
kernel.shmall = 1073741824
kernel.shmmax = 4398046511104
kernel.panic_on_oops = 1
net.core.rmem_default = 262144
net.core.rmem_max = 4194304
net.core.wmem_default = 262144
net.core.wmem_max = 1048576
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2
fs.aio-max-nr = 1048576
net.ipv4.ip_local_port_range = 9000 65500

Be aware, it sets fs.aio-max-nr to a value *much* lower than you likely need.  See note 2229798.1 for details.

Next, on my system it set up user limits with these values.  I *think* the memlock setting was based on the amount of ram I had in my VM at the time...which was, not much:

Adding oracle soft nofile 1024
Adding oracle hard nofile 65536
Adding oracle soft nproc 16384
Adding oracle hard nproc 16384
Adding oracle soft stack 10240
Adding oracle hard stack 32768
Adding oracle hard memlock 134217728
Adding oracle soft memlock 134217728
Adding oracle soft data unlimited
Adding oracle hard data unlimited

Next, it adjusts the boot parameters:

Originally   : crashkernel=auto rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet

Changed to : crashkernel=auto rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet numa=off transparent_hugepage=never (which also disabled thp’s memory compaction)

Lastly, it edits /etc/sysconfig/network:

Adding NOZEROCONF=yes

You may need to adjust those settings for your environment if its large.  Sizing issues aside, after you install the rpm, within a few seconds you'll have a very stable system, ready for a RAC install.  There are still other recommended things you should do...for example, verifying the network is using jumbo packets for the interconnect and reserving hugepages for your SGA, but the RPM does a lot of the OS work for you.  

Hopefully this will help you better answer the question, "What does the Oracle Pre-install RPM do?"

Thursday, July 23, 2020

The complete post-12c online procedure to move a file from file system to ASM (ORA-01110,ORA-01157,ORA-01187,ORA-12850,RMAN-03009)

In the Coronovirus-19 world, most of us would rather spend time learning about the Seattle Kraken, Max Ehrich, Roy Jones Jr and the Washington Football Team.  They'll probably eventually do what Prince did and just call themselves, "Symbol." Roy Jones and Max Ehrich will both get knocked out and the Blues will have one more team to beat before they get their next cup.  If you're reading this...you probably also care about Oracle databases...so let me tell you about a recent experience I had.

A client I work with had an issue the other day (actually 2 issues) in a container database.  This database has very strict uptime SLA's...so downtime for a bounce of an instance isn't an option.  The online process to move a datafile from file system to ASM is a 3 step process in 12c+...until now I've always thought it was a single "move datafile" command.

1. They hit a bug similar to the issue discussed in note 2558640.1, while doing a select from cdb_data_files, they got "ORA-12850: Could not allocate slaves on all specified instances: 3 needed, 0 allocated".  

2. This happened in a script that's used to add datafiles as needed.  Unfortunately, that script created a datafile with some of the error text instead of "+DATA"...so the file was created in the dbs directory on node 1 instead of putting it into ASM.  This is RAC, so the datafile was only able to be accessed on the first node.  RAC requires shared storage.


First order of business, get it working again.  This is 18.7, so it was easy to move the file into ASM without downtime.  The filename was ridiculous with special characters, and the file was on the file system on node 1, so from node 1 I did:


alter database move datafile 1654 to '+DATA' ;


...and that worked, now the datafile is in ASM's shared storage.  I kicked off a backup (which failed):



                RMAN-03009: failure of backup command on ch4 channel at 07/23/2020 11:23:24 
                ORA-01157: cannot identify/lock data file 1654 - see DBWR trace file
                ORA-01110: data file 1654: '+DATA/DB/DATAFILE/sysaux.22113.1246514439'

On node 1, this file is 100% working in ASM.  On other nodes, it was unavailable, giving ORA-01157's.  In gv$datafile I could see it was online and available on all nodes.  This made no sense to me.  I even double checked by going into asmcmd and doing an "ls" from one of the nodes that was failing...yep...it was there.  It was acting like it was offline, but reporting it was online.

I googled/checked metalink and didn't really find a good hit.  Finally I thought...there's no harm in onlining a file that says its online...so I did an:

ALTER DATABASE DATAFILE 1654 ONLINE;

The error changed from:
ORA-01157: cannot identify/lock data file 1654 
to:
ORA-01187 cannot read from file 1654 because it failed verification tests

It was still working on node 1, but getting ORA-01187 on the other nodes.  This time I found a solution:

ALTER SYSTEM CHECK DATAFILES;

...which I did on the nodes that were having issues.  After that, everything began to work.

With the solution and the original error, I went back on MOS and this time found the ultimate solution: (DOC 2499264.1) which states:

ORA-01157 error is expected to occur when running a query on dba_datafiles on a particular instance (of RAC database) for a file moved (just after creation) from Filesystem to ASM, without instance wide identification.
 
This problem was previously addressed in Bug 27268242 which was also closed as "Not a Bug" because this is an expected behavior.

(I think they meant cluster or database-wide identification.) 
<VENT> Come on, Oracle!  You shouldn't expect to get an error when running a correct query on a valid datafile.  This just causes more trouble and steps and after a datafile move, there's no reason to leave it in a partially working state.  If you're in RAC and somebody moves a file to ASM...let the other nodes know!  There's no conceivable situation where somebody would want to move a file in RAC and have it only available to a single instance...make the alter database datafile move check datafiles when its coming from the filesystem for us!  
<?VENT>

Until Larry starts listening to me...this means we have multiple steps.

That note also included a resolution:
alter system check datafiles;
alter system flush shared_pool; 

...so at this point, the datafile is working correctly on all nodes.

This means we have 3 statements to do when we move a file from the file system to ASM:
alter database move datafile 1654 to '+DATA';
alter system check datafiles;

alter system flush shared_pool; 

Now that its working, I can re-address problem #1 above...the root cause.

Note 2558640.1 discusses a similar problem when OEM is hitting the views that have the datafiles.  My issues isn't in OEM, but in every other way this matches up.  The work around:


alter system set "_px_cdb_view_enabled"=false comment='Work-around for internal view error and OEM-see bug 29595328';

This prevents the issue from happening again, but it also slows down the query (and others) hitting the cdb_data_files from 45 seconds (there's a lot of datafiles) to 90 seconds.  I suppose that's better than getting this error...I opened an SR to ask this be fixed in future releases.

I love the new feature in 12c+ to do online datafile moves...but it would be great if the process was documented when moving a datafile from the file system...all I've seen in the doc's is the basic move datafile command, not all 3 steps.

With the system working and in a state where this won't happen again...I can now return to C19's bad hair and toilet paper and coin shortages.

Wednesday, May 6, 2020

RHEL7 Control Groups on Oracle Database Servers


After some linux patching on some database servers I was surprised to see an entry in an alert log I hadn’t seen before…complete with a WARNING message.  After digging around I found it was due to Linux control groups.  In an effort to manage a server with multiple workloads, RHEL7 introduced control groups and they’ve increased features/abilities with each dot release.  On the affected  Oracle nodes in RHEL7 we see entries on startup in the alert log:

************************ Large Pages Information *******************
Parameter use_large_pages = ONLY
Per process system memlock (soft) limit = UNLIMITED

Large page usage restricted to processor group "user.slice"

Total Shared Global Region in Large Pages = 60 GB (100%)

WARNING:
  The parameter _linux_prepage_large_pages is explicitly disabled.
  Oracle strongly recommends setting the _linux_prepage_large_pages
  parameter since the instance  is running in a Processor Group. If there is
  insufficient large page memory, instance may encounter SIGBUS error
  and may terminate abnormally.

Large Pages used by this instance: 30721 (60 GB)
Large Pages unused in Processor Group user.slice = 1722 (3444 MB)
Large Pages configured in Processor Group user.slice = 120000 (234 GB)
Large Page size = 2048 KB

You may also see:
Large page usage restricted to processor group "system.slice/oracle-ohasd.service"

…this concerned me because if our large page usage is restricted and we can’t do a prepage, eventually the db_cache would warm up and allocate memory beyond the limitation, causing an instance crash.  Also, “WARNING” on startup is something to take a closer look at.  That undocumented parameter was most definitely NOT explicitly disabled.  This message appears in every database that’s being controlled by processor groups, so it appears prepage of large pages is disabled automatically.  There’s a note (2414778.1) that says this message can be ignored and its removed in 12.2+.

So…what amount of memory is our group being limited to by default?
>systemctl show user.slice|grep Mem

MemoryCurrent=18446744073709551615
MemoryAccounting=no
MemoryLimit=18446744073709551615

…which works out to be 17,179,869,184GB, (roughly 17 Exabytes) which is probably a sufficient amount of RAM (per node) for any database out there…so we’re basically being limited to slightly less than infinity….nothing to worry about.

Are control groups useful in a multi-database instance server environment?  To set up CPU limits per instance, you could use this or instance caging…I would prefer to set the cpu_count parameter and use instance caging.  Memory Limits?  Memory utilization for the SGA is set via sga_target/max_size…so I don’t think there’s a play for it here either.  Maybe the accounting features could be useful…if you wanted to see how much CPU one instance in a multiple instance db server was using historically?  There are awr tables that track that…but getting the information from CG might be easier….

One potentially useful way to use control groups for a database server with multiple instances is to throttle bandwidth on IO to prevent one instance from using up all the IO and affecting the performance of a different instance (assuming each instance is on its own asm disks or luns.)  There’s a note about how to get that to work on Metalink: 2495924.1.  This has been a useful feature in Exadata for years with IORM…now you can have similar functionality without Exadata.

One other interesting feature of control groups is the ability to look at the resources each group is using in real time (if you have accounting on) with the systemd-cgtop command.  If you don’t have accounting, you’ll see something like this, which is a summary of process counts, cpu, memory and IO for each group:






It took some time to find the details about what the new alert log entries were telling me with the new warning and processor group information.  Hopefully this information will save you some time. 

Friday, August 30, 2019

Oracle Cloud Backups - The easy way to mass delete files in a large OCI bucket

In some previous posts, I talked about the benefits of doing backups to Oracle's cloud...if you run the numbers it will be significantly (magnitudes) less expensive than backups on prem or to other cloud vendors.  Its safer than keeping backups geographically close to you, they're very fast (depending on your WAN speed, the storage array's write speed will be the bottleneck for your restore), they're encrypted, compressed and secured.  Once you have everything scripted...its a "set it and forget it."  The uptime far exceeds typical on-site backup MML systems...which is important because failing to do timely archivelog backups may translate into a database outage.

I've really only had 1 complaint until now.  Here's the full story...skip down to "The Solution" if you're impatient.

When I first helped a customer set up their backups to Oracle's Classic backup service (pre-OCI), there was a problem.  The design called for the database backups to go into a different bucket for each databases.  When the non-prod databases were refreshed from production, they wanted to delete the bucket that held those backups.  No problem...there's a big red delete button on the bucket page, right?  Wrong!  You can't delete a bucket that has files in it.  When you do a backup of even a medium sized database, you can have hundreds of thousands of files in it.  The only way to delete files on the console is to select 100 at a time and click delete.  I had 10 databases/buckets, over a million files and it took me about 5 seconds to delete 100 files.  If I did nothing else...we're talking ~14 hrs of work.  In reality it was going to take somebody days to delete the backups after every refresh.  Completely unacceptable....

I opened an SR to ask for a better way.  They pointed me to Cloudberry Explorer (which is a pretty cool product.)  CBE allows you do pull up the files in Oracle's (or virtually any other) cloud in an interface similar to Window's file explorer.  Great!  I set it up, selected all the files I wanted to delete and clicked the little delete button.  After the files were indexed,  it kicked off multiple threads to get this done.  3 by 3 (about 3 sec per file), they started to delete.  I left my laptop to it over the weekend.  When I came back on Mon...it was still deleting them.

I updated the SR...they pointed me to using curl in batch to hit the API (Doc ID 2289491.1).  Cool!  I love linux scripting...it took a while to set it up, but eventually I got it to work...and one by one (about 3 sec per file) they started to delete.  Argh.

A colleague I work with wrote a similar procedure in perl...but it was using the same API, and had the same results.

I updated the SR...they essentially said there's no way to do what I'm trying to do any faster.

I opened an new SR for an enhancement request to add a way to do mass deletes...here's the response:

"The expectation to delete the bucket directly is like a Self Destructive program ,Many customer will accidentally delete the container and will come back to US for recovery which is not possible."
...and then they closed my enhancement  request.

My first thought was to send an email to Linus Torvalds and let him know about the terrible mistake he made introducing rm to his OS.  (sarcasm)  My second thought was that the company that charges for my TB's of storage usage isn't motivated to help me delete the storage.

The Solution:  Lifecycle the files out.
1. First enable Service Permissions (click here).
2. In OCI, go to Object Storage, click on the bucket you want to clean up and click on "Lifecycle Policy Rules."  Click on "Create Rule."
3.  Put in anything for name (its going to be deleted in a minute, so this doesn't matter.) Select "Delete" from the lifecycle action and set the number of days to 1.  Leave the state at the default Enabled, then click the Create button.  This will immediately start deleting all the files in the bucket that are over 1 day old...in my case, that was all of them.


4. The Approximate Count for the bucket will update in a few minutes.  Soon (within a min or so) it will say 0 objects.  Now when you click the red Delete button to remove the bucket, it will go away.  I was able to remove about 150 Terrabytes in a few seconds.

I have no idea why Oracle made this so difficult...their job is to provide a resource, not protect us from making a mistake.  Anyway, I hope this helps some of you out.

Tuesday, August 13, 2019

How to monetize your blog with BAT

I think one thing is clear at this point...you'll either get into blockchain technology, or you'll regret it when you get in later.  This is still the time of "Early Adopters"...you're not too late.  How does this tie in to a mainly Oracle/database blog?  Recently I heard Oracle's Larry Ellison gave a speech to Wharton Business School graduates about blockchain where he said this is the single most important new technology in decades.  A Bloomberg report stated Oracle is ready to announce its entry into Blockchain including a platform as a service (PaaS) Blockchain product...IBM and others have already done the same thing.  We've all seen blockchain enter the finance and IoT spaces, but the applications are endless...its my other passion, besides databases.  You could say blockchain is a new database technology.  Its going to change the world.

Blockchain gave us Bitcoin and many other coins/tokens.  You've all heard of Bitcoin, but you may not have heard of Basic Attention Coin (BAT).  BAT works with the Brave browser, which can generate BAT tokens as you use it.  It then allows you to tip websites automatically when you use them.  *More info here*.  To do this you just need to download and use the Brave browser . Think "Chrome" but its faster, more secure, ads blocked, built by Brendan Eich, the guy that invented java script and Mozilla.  The idea is that from a user's perspective, you can reward content creators (like websites, twitter/youtube/blog channels, etc) when they help you out (at really no cost to you)...and from the content provider's perspective, they can get free money.

I've used it for about a year, and it keeps getting better, but I wanted to monetize my blog with it.  To do this, you have to register your channel, to do that, you need to put in a file with a key into a folder called ".well-known".  Blogger has no way to do this, but I found a way to get it to work.

1. Go to https://publishers.basicattentiontoken.org/publishers/home
2. Create an account and click on "Add Channel"
3. Click on Website
4. Add your website: ie: otipstricks.blogspot.com
You're then given two options to verify via DNS or by adding a file...choose to add the file.

That will give you the instructions to add a file called /.well-known/brave-rewards-verification.txt with metadata in it.

5. Now go into your blog's settings and go to "Pages" and click "New Page."
6. I named my page brave-rewards-verification.txt, although I'm not sure that was necessary, and then I pasted in the metadata I got from step 4.
7. Click save and publish...this gives you a page you can access like this:
https://otipstricks.blogspot.com/p/this-is-brave-rewards-publisher.html
8. Back to blogger settings->search preferences->Custom Redirects->Edit->New Redirect
9. Create a redirect that looks like this, with relative paths:
From:/.well-known/brave-rewards-verification.txt
To:/p/this-is-brave-rewards-publisher.html
Permanent:Yes
10. Now go back to https://publishers.basicattentiontoken.org/publishers/home and click on the verify button.  Within a few seconds it will say, "Channel Verified."
11. Now create an uphold wallet (which is another link on that page and follow the instructions to connect it to your new bat publishers account, and you're done.  Now, when people come to your page, they can tip your blog automatically, in the background.

Now, when you go into brave and click on brave rewards, you can check your website:



Thursday, August 8, 2019

Oracle's Backup Cloud Service (OCI) - 3 setup your backup

In this series of posts:

Oracle's Backup Cloud Service (OCI)-1 - The Oracle OCI Backup Cloud

Oracle's Backup Cloud Service (OCI) - 2 - setup OCI and your server environment

Oracle's Backup Cloud Service (OCI) - 3 - You are here


At this point, you've read about why you want to use OCI and the benefits and you've read how to setup your environment for it.  This one is about setting up your backups to use it.  The only negative I can say after using OCP/OCI for over a year is that they change the security certificates without warning.  If you install/setup the software per the docs and you have a lot of databases...this can easily occupy many hours that day, reinstalling all the OCI software for every Oracle_Home in your infrastructure.  This is why in my previous post, I recommended you use a shared mount.

You have already:
1. Installed OCI software on a shared mount
2. Setup a container in the cloud web page
3. Used the jar file to create the environment files you need
4. Enabled block change tracking in the database (for incrementals)
5. Enabled medium compression in rman (per the OCI backup docs, this is normally licensed as part of the compression pack, but it appears if you're paying for OCI backups, this is included.  Talk to your Oracle sales guy.)

In the server you used in the last post, as the db software owner:
1. cd /nas/dba/backups/cfg
     2. ls
        ...you should see a file called opc[database name].ora
     3. You can use this as a template for all your other databases...just copy the file to have the new database name and update the container parameter in the file.  

      4. If you use stored scripts in an rman repository, you can add the backup scripts similar to this.  This is just the archivelog backup...you'll want incrementals and fulls, obviously, but the key is the allocate channel commands, which are the same.  Add more channels to increase performance...until your network guys complain:

printing stored global script: tstoracle01_TSTDB1_arch
{
allocate channel ch1 DEVICE TYPE 'SBT_TAPE' CONNECT 'sys/[the_pw]@TSTDB1' PARMS  'SBT_LIBRARY=/nas/dba/backups/cfg/libopc.so, SBT_PARMS=(OPC_PFILE=/nas/dba/backups/cfg/opcTSTDB_a.ora)';
allocate channel ch2 DEVICE TYPE 'SBT_TAPE' CONNECT 'sys/[the_pw]@TSTDB2' PARMS  'SBT_LIBRARY=/nas/dba/backups/cfg/libopc.so, SBT_PARMS=(OPC_PFILE=/nas/dba/backups/cfg/opcTSTDB_a.ora)';
allocate channel ch3 DEVICE TYPE 'SBT_TAPE' CONNECT 'sys/[the_pw]@TSTDB3' PARMS  'SBT_LIBRARY=/nas/dba/backups/cfg/libopc.so, SBT_PARMS=(OPC_PFILE=/nas/dba/backups/cfg/opcTSTDB_a.ora)';
crosscheck archivelog all;
delete expired archivelog all;
backup as compressed backupset archivelog filesperset 8 not backed up 1 times delete input;
}

   5. Make sure your rman environment is set up correctly:

CONFIGURE COMPRESSION ALGORITHM 'MEDIUM';
CONFIGURE DEFAULT DEVICE TYPE TO SBT_TAPE;
CONFIGURE CHANNEL DEVICE TYPE 'SBT_TAPE' PARMS 'SBT_LIBRARY=/nas/dba/backups/cfg/libopc.so, SBT_PARMS=(OPC_PFILE=/nas/dba/backups/cfg/opcTSTDB_a.ora)';

    6. Assuming you can tnsping to each node from node 1, and you kick off the script from node 1, when you kick off the backup, it should work from all 3 nodes.  You'll also need a maint script to delete backups that are outside of your retention period...otherwise your OCI storage will grow too large.  Here's an example of a maint script:
printing stored global script: global_maint_backup
{
crosscheck backupset device type sbt_tape;
crosscheck archivelog all;
delete noprompt expired archivelog all;
delete noprompt expired backup;
delete noprompt obsolete;
}

  
    7. One of the requirements for OCI is that the backups MUST be encrypted.  This is easy...before your backup script, after you get in to rman, just add:
    
       set encryption on identified by '1VeryGoodPassword!' ONLY;
     ...and when you do the restore, you have to add a line to decrypt:
       set decryption identified by '1VeryGoodPassword!';

    8. When you do the restore, you'll probably want to use many more channels then you do when you're backing up...assuming its an emergency and you need the restore done asap.  When you add lots of channels, depending on your network equipment, it may help you compete for bandwidth favorably from the cat videos being watched by all the marketing managers at your company.
       

Oracle's Backup Cloud Service (OCI) - 2 (setup OCI and your server environment)

In this series of posts:

Oracle's Backup Cloud Service (OCI)-1 - The Oracle OCI Backup Cloud

Oracle's Backup Cloud Service (OCI) - 2 - You are here

Oracle's Backup Cloud Service (OCI) - 3 setup your backup


In my previous post, I talked about OCI Backups and their advantages.  Here's how you do it:

Before you start, verify you have Java 1.7+ installed on your server (java -version) and download the MML software:
http://www.oracle.com/technetwork/database/availability/oracle-cloud-backup-2162729.html

In a browser, go to:
https://console.us-ashburn-1.oraclecloud.com/

1. Setup your tenant
2. Create your user

...those steps keep changing, so I'm not going to tell you how to do them...but if you go to that page, it should be pretty self-explanatory.  Ok, so at this point you're in.

3. On the top right, select the region that's geo-located closest to you.  Be aware of any in-country requirements for your database backups.




     4.   On the top left, click on the hamburger (the button with 3 lines), and then click “Object Storage”.  The Object Storage page will appear:




5. To make management easier, put each database’s backups into its own bucket.  If you don’t see the bucket for the database you’re working on, create one by clicking on the “Create Bucket” button.

6. Fill in the “Bucket Name” text box with the database you want to add and select “standard tier”, then click the “Create Bucket” button.  The list price of standard tier is $0.025 cents/GB, and archive price is $0.0025 cents, but you’re required to keep archive for 90 days and there’s up to a 4 hour lag if you need to pull back archived files...so unless its a rare backup you're going to keep for an extended time, you want standard.


7.   For the install to work, we first need to get:  


          a.Cloud Infrastructure API signing keys
          b.tenant OCID
          c.user OCID
          d.fingerprint of our RSI key. 

      8. Click the profile button in the top right corner (it looks like a head in a circle) and select user details. Click "copy" and paste the USER OCID to the editor of your choice.  It should start out with: "ocid1.user.oc1.."

      9. Click again on the profile button in the top right corner (that looks like a head in a circle) and this time select "Tenancy: [whatever your tenancy is called]"

     10. Under the Tenancy information, click on "Copy" and copy the tenant OCID and paste it into the editor of your choice.

     11. Assuming you have an nfs mount that's shared on all your database servers, make a directory on that mount...  ie: mkdir /nas/dba/backups/cfg/opc_wallet

      12. In your database server, go to the directory you unzipped the software into and get a new RSA key pair:
         java -jar oci_install.jar -newRSAKeyPair -walletDir /nas/dba/backups/cfg/opc_wallet

      13. View the oci_pub file and select it so it loads into your laptop's clipboard (starting at the first dash, stopping after the last dash)
      
      14. Once again back to the Profile button in the top right corner, click on your user and scroll down to the bottom of the page where it says, "API Keys" and click Ad Public Keys and paste in your new key from the previous step...when complete, click ADD.

      15. A new fingerprint will be displayed.  Select that fingerprint and paste into the text editor of your choice.

      16. Using all the things you put in your editor of choice, create the install command.  Put yours all in one line...I broke this out to make it more readable:

  java -jar oci_install.jar -host https://objectstorage.us-phoenix-1.oraclecloud.com
    -pvtKeyFile  /nas/dba/backups/cfg/opc_wallet/oci_pvt
   -pubFingerPrint [paste finger print here]
   -tOCID [paste tenancy OCID]
   -uOCID [paste user OCID]
   -libDir /nas/dba/backups/cfg
   -walletDir /nas/dba/backups/cfg/opc_wallet
   -bucket [the bucket you created in step 5]
   -cOCID [the OCID of the compartment you're using, if any]
   -configFile /nas/dba/backups/cfg

  




Oracle's Backup Cloud Service (OCI)-1


In this series of posts:
Oracle's Backup Cloud Service (OCI)-1 - You are here

Oracle's Backup Cloud Service (OCI) - 2 setup OCI and your server environment

Oracle's Backup Cloud Service (OCI) - 3 setup your backup



IMHO, one of the best use cases for the cloud is backups.  I honestly don't know why Oracle doesn't market this more...its been the best Oracle Cloud experience I've seen.  The bar is low there...but this service has been flawless.  The questions re:security have been MOSTLY answered (save a few for AWS at Capital One).  One of the trends I'm seeing is for companies to move some of their database backups to the cloud.  If you can't handle downtime more than a few minutes, this isn't for you, you may need storage array snaps or a fast dataguard failover...but what about your dev/test/qa database backups?  Putting at least some of your backups in the cloud might make a lot of financial sense.  In a recent analysis, I saw a company that found it was (all things considered) about 400% cheaper to put their dev/test backups in Oracle's cloud.  Backing up to Oracle's new OCI cloud (as opposed to Oracle's Classic Cloud Backup service) was even cheaper than AWS Glacier for their use case.

What about restore performance?  Dev/Test might be more tolerant than prod for an outage during a restore/recovery, but how long are we talking here?  The answer:it really depends more on your infrastructure than it does on the OCI cloud...it is FAST.  My test used an all-flash Dell/EMC VMax and my 3 RAC nodes were the only things on the new array.  I have no way to know how much spare network bandwidth there was, but I did this test at night using a 1Gb link.  The key is...using Oracle backups allows you to use medium compression.  So...whatever your bandwidth is...multiple that by your compression ratio, and that's the restore speed you can expect (unless you hit a different bottleneck...storage array performance, cpu, etc...).  I posted in the past about the performance benefits for using rman compression.  In a recent test, my waits were on writing to the storage array, not the network or OCI itself.

The Test:
Oracle RAC 12.2

Almost 14TB (13,940,708 MB)
Starting at 9:53
Finishing at 12:52
...so 3 hrs...~4.66TB/hr.

So you ask...its secured, its much cheaper and its as fast as it could possibly be?  You also get an automatic air-gap, offsite backup.  What's the downside?

Once you understand it, its easy to do and the up-time has been great, too, but the instructions are almost impossible to locate online...and when you do, they're obsolete or talking about classic, not OCI.  The only instructions (that weren't wrong) I found were in the README...but they weren't great and they were about how to set it up for a database...you probable have more than 1, right?  Several times/yr, maybe without warning, Oracle will update their security certificates which will force you to do a re-install...but if you plan your installation with this in mind, you can make that almost painless.  In my next post, I'll describe what I did.....








Wednesday, August 7, 2019

Data Cleanup (how to exercise the ghost from the machine)

The scariest movie I ever saw was the Exorcist...to tell the truth, I don't think I actually saw it...while I was watching it I had my eyes closed half the time and I left early.  This is relevant to Oracle Databases...stay with me here.  Database upgrades are a *HOT* topic right now...with the extinction of 12.1.0.2 free support, everybody is moving to 18c or 19c.  I recently helped a customer with a problem that was preventing their database upgrades from being successful.  They were moving a legacy database into a multi-tenant pluggable database using datapump and rows were being dropped.  We initially assumed it was a character set issue, but we were going from UTF8 to UTF8.  We eventually learned that this database had long ago migrated to UTF8 from a different character set, and the conversion was done incorrectly, so we were left with bad data in the legacy tables.

They said they've had issues with "ghosts" in the data...two columns that appeared to equal each other not equaling each other in plsql, that kind of thing...but they always attributed it to bugs.  Now we knew the column's data had hidden, invisible characters in them.  They didn't care about the hidden characters, but the rest of the data in the column needed to be saved.  They only needed the basic, common ascii character set, so I wrote this quick little stored procedure to dynamically take the data and scan it, replacing any unusual characters with a space.  After this the import worked without an issue, and the database ghosts were exercised (no young and old priest required).  There were many 100 mil+ row tables, but the number of rows with bad data were only in the thousands...so I didn't do a forall update...if your data has a larger number of rows to change, you might want to modify this.

When its complete, you can see if everything worked ok with this:
select /*+ PARALLEL 8 */ * from ascii_check where CPOS=-1 order by 1,2,3;

[insert usual disclaimer here] I used this on many very large tables and it appears to do what I intended (which was to use the character's ascii code range to decide if it was a character we wanted to not), but review it closely to make sure it does what you want it to do in your environment before you use it. No warranties/promises...it'll probably not work...yada yada yada....

First, create this table that will serve as a log to keep all the data that was changed, in case something unexpected happens or you need to revert back:

create table ascii_check (Table_Owner varchar2(30),Table_Name varchar2(255), Col_Name varchar2(255), old_rowid varchar2(255), cpos number, code number, old_value varchar2(255 char));

...once you feel confident its doing what you want...you can submit it as a job, and have many tables being scanned and corrected at the same time.

CREATE OR REPLACE procedure data_cleanup
  (
  Table_Owner_in in varchar2,
  Table_Name_in in varchar2,
  Column_Name_in in varchar2,
  Testing_in in varchar2
  )
is
  v_Char number;
  v_String2 varchar2(32000);
  v_Flag boolean;
  v_Flag2 boolean := true;
  v_Counter number :=0;
  v_Errm varchar2(255);
  v_ErrTrack number :=0;
  v_Count number := 0;
  already_completed exception;
  pragma exception_init(already_completed,-20001);
  type rct_RowIDs is ref cursor;
  rc_RowIDs rct_RowIDs;
  v_Err_Rowid varchar2(18);
 
  type t_Row is record
  (
    Old_RowID varchar2(18),
    Old_Data varchar2(32000)
  );
  type t_Rows is table of t_Row index by pls_integer;
  c_Rows t_Rows;
begin
  execute immediate 'ALTER SESSION SET ddl_lock_timeout=900';
  select /*+ PARALLEL 16 */ count(0) into v_Count from ascii_check where table_owner=Table_Owner_in and Table_Name=Table_Name_in and col_name=Column_Name_in and old_value='Completed Successfully.';
  if v_Count!=0 then
    raise already_completed;
  end if;
  delete /*+ PARALLEL 16 */ from ascii_check where table_owner=Table_Owner_in and Table_Name=Table_Name_in and col_name=Column_Name_in and cpos=-1;
  v_ErrTrack := 1;

  OPEN rc_RowIDs FOR  'select /*+ PARALLEL 16 */ rowid,'||Column_Name_in||' from '||Table_Owner_in||'.'||Table_Name_in||' order by rowid';
  loop
    FETCH rc_RowIDs BULK COLLECT INTO c_Rows LIMIT 50000;
    v_ErrTrack := 2;
    -- for each row
    for i in 1..c_Rows.count loop
       
        v_ErrTrack := 3;
        v_String2 := '';
        v_Flag := false;
        -- for each character in each row
        for j in 1..nvl(length(c_Rows(i).Old_Data),0) loop
          v_ErrTrack := 4;
          v_Char := ascii(substr(c_Rows(i).Old_Data,j,1));
          v_ErrTrack := 5;
          if (v_Char<32 or v_Char>126) then
            v_String2 := v_String2||' ';
            v_Flag := true;
            v_ErrTrack := 6;
            insert into ascii_check values (Table_Owner_in,Table_Name_in,Column_Name_in,c_Rows(i).Old_RowID,j,v_Char,substr(c_Rows(i).Old_Data,1,240));
          elsif v_Char=39 then
            v_String2 := v_String2||'''''';
            v_Flag := true;
            v_ErrTrack := 6;
            insert into ascii_check values (Table_Owner_in,Table_Name_in,Column_Name_in,c_Rows(i).Old_RowID,j,v_Char,substr(c_Rows(i).Old_Data,1,240));
          else
            v_ErrTrack := 7;
            v_String2 := v_String2||substr(c_Rows(i).Old_Data,j,1);
          end if;
        end loop;
        v_ErrTrack := 8;
        if v_Flag then
          v_Counter := v_Counter +1;
          if Testing_in ='FALSE' then
            v_ErrTrack := 9;
            v_Err_Rowid := c_Rows(i).Old_RowID;
            begin
              execute immediate 'update '||Table_Owner_in||'.'||Table_Name_in||' set '||Column_Name_in||'='''||v_String2||''' where rowid='''||c_Rows(i).Old_RowID||'''';
            exception
              when DUP_VAL_ON_INDEX then
                execute immediate 'update '||Table_Owner_in||'.'||Table_Name_in||' set '||Column_Name_in||'=''EDITED-'||v_String2||''' where rowid='''||c_Rows(i).Old_RowID||'''';
                --insert into ascii_check values (Table_Owner_in,Table_Name_in, Column_Name_in, v_Err_Rowid, -1,-1,v_ErrTrack||'-'||v_String2);
                v_Flag2 := False;
            end;
          end if;
        end if;
        v_ErrTrack := 10;
    end loop;
    v_ErrTrack := 11;
    exit when c_Rows.count < 50000;
  end loop;
  close rc_RowIDs;
  dbms_output.put_line('There were '||v_Counter||' issues detected.');
  if v_Flag2 then
    insert into ascii_check values (Table_Owner_in,Table_Name_in,Column_Name_in,'',-1,-1,'Completed Successfully.');
  else
    insert into ascii_check values (Table_Owner_in,Table_Name_in,Column_Name_in,'',-1,-1,'Completed Unsuccessfully.');
  end if; 
  commit;
exception
  when already_completed then
    dbms_output.put_line('Already completed.  Exiting...');
  when others then   
    v_Errm := sqlerrm;
    dbms_output.put_line(v_Errm||'@'||v_ErrTrack);
    insert into ascii_check values (Table_Owner_in,Table_Name_in, Column_Name_in, substr(v_Errm,1,240), -1,-1,v_ErrTrack||'-'||v_String2||'-'||v_Err_Rowid);
    commit;
    close rc_RowIDs; 
end;
/




Tuesday, July 23, 2019

We're using up storage too fast! Where is all the growth coming from?

Technical challenges aside, its difficult to navigate the politics of being an Oracle DBA.  In today's world, data warehouses/data lakes are expected to ingest massive amounts of data and still perform well.  Ok, no problem...this can be done...but when the storage utilization spikes, the storage guys (who write the checks for the expensive storage arrays the data is on)...they want to know if/why they need to buy another storage array.  DBA's are expected to perform storage planning, but are rarely informed when the data owners increase utilization until after the fact.

This question comes up pretty often...why is the database growing so fast?  Coming in to a new environment I'm not familiar with...I have a bunch of scripts I usually run to get a profile of the databases.  Usually a non-technical manager wants to see a summary, so if this data can be presented graphically as part of a presentation, communication flows better, and it looks more professional.

All the storage utilization data is being kept in the history tables...its just a matter of pulling it .  This is a dynamic query that creates a query...the results of that can be put into Excel and graphed.  Once the results are graphed, things pretty clearly jump out at you.  So...

1. Run this query (if you aren't using 8k block size, change 8192 below to w/e you're using):

select stmnt from (
select 1 o1, 0 o2, 'with stacked as
(
select snap_id, tablespace_id, trunc(to_date(rtime,''MM/DD/YYYY HH24:MI:SS'')) rtime, (tablespace_size*8192)/1024/1024/1024 ts_size
from dba_hist_tbspc_space_usage tdu
where snap_id in (select max(snap_id) from dba_hist_tbspc_space_usage tdu2
                    where trunc(to_date(tdu.rtime,''MM/DD/YYYY HH24:MI:SS''))=trunc(to_date(tdu2.rtime,''MM/DD/YYYY HH24:MI:SS'')))
)
select distinct rtime,'  stmnt from dual
union all
select 2, TS#,'(select ts_size from stacked s2 where s2.tablespace_id='||TS#||' and s1.rtime=s2.rtime and rownum=1) as "'||NAME||'"'||decode((tsm-ts#),0,null,',') from v$tablespace ts1 , (select max(TS#) tsm from v$tablespace) ts2
union all
select 3,0,'from stacked s1
 where (select ts_size from stacked s2 where s2.tablespace_id=0 and s1.rtime=s2.rtime) is not null;' from dual
 ) order by o1,o2;

2. Take the output of that query, and run it.  It'll create a very wide data set with daily storage size data for each tablespace.

3. Cut/Paste and put that data into Excel.

4. Select the data columns in Excel and at the top, select insert, then on the "Charts" group, select your favorite chart type..."2-D, stacked area" works well for this data, IMHO.

You should now see something like this (GB on the Y axis):

...so now its clear where the acceleration in growth came from.  The relatively new, orange "troublemaker_data" tablespace had a ~10TB growth spurt until May 1st, where it looks like it leveled off.  This empowers you to go after the data owners and ask them if this will continue, and you can tell the storage guys there was growth but it settled down and they don't need to panic and buy more storage.

I hope this helps you with your storage planning!

Monday, July 22, 2019

Watch out for the latest 12.1 PSU/proactive patches!

We all have horror stories about "That one time, when we restored and recovered the database, and the CIO was calling out managers every few minutes, reminding them the company is at a stand-still...this is costing us $XXX,XXX per minute!!!!!"  Now imagine after a few hours in to your restore you have to say, "We hit a bug. We have to open an SR, get a patch and start over."  Discovering you can't successfully restore/recover when the heat is on due to a bug would make a great horror movie...nothing is more scary.  Luckily I hit this bug during a restore test...so I had some time to deal with it...but I thought I should let everybody know about it.

I know a lot of people are still running 12.1.0.2.  The Jan and Apr 2019 PSU (the two latest PSU's) introduce a bug (25107334) that cause you to be unable to open the database.  I hit this 3 hours into a restore:

ORA-65108: invalid use of a cursor belonging to another container

The work around is that you manually put the $SEED database into read-only mode.  Simple enough...but if you're restoring/recovering a database, that's not a option.  There's now a patch (25107334), that solves the issue.  While waiting for MOS to come up with a solution, I used a 19.3 home to restore the database, and it worked fine...so that's an optional work-around too.

As people migrate to 19.3, there are earlier bugs that prevent 12.1 from working with a 19.3 GI...those bugs are fixed in these PSU's...so patching 12.1.0.2 needs to be part of the 19.3 upgrade plan, and this patch needs to be part of the 12.1.0.2 patch.

Hopefully this will be part of future PSU/proactive patch bundles...and we can keep the nightmares in the movies! 

/*+ UPDATE */
The July PSU is out (12.1.0.2.190716) and per (1924126.1), 25107334 is fixed in that PSU.

Upgrade to Oracle 19.3!

Oracle has postponed End of Support for 11.2.0.4 many, many times, but no mas!  In fact, if you're running EBS, 11.2.0.4 is STILL supported with extended support fees waived, almost 11 years after its initial release.  I know a couple of large EBS shops that are still running on 11.2.0.4.  To upgrade the database for EBS is a huge task...so its understandable why they'd put this off as long as possible...but time is running out. See 742060.1 for details.

Also, 12.1 premier support ran out almost a year ago, but I know there are a lot of people still running critical databases on that version.

At this point, everybody is aware that Oracle changed their naming convention...so you can think of 19.3 really being 12.2.X.  There are *many* great new features in 19.3...its the terminal release of Oracle 12.2.  Oracle recommends you not upgrade at this point to anything other that 19c.  I've heard rumors that the next db version that'll be supported for EBS is 19.3 (currently the max is 12.1...they're skipping 12.2 and 18.3.)

So its inevitable...you're going to go to 19c.  Here's are some things to keep in mind:

1. In order to upgrade your database to 19.3, you...of course...need to upgrade your ASM's Grid Infrastructure to 19.3

2. In order to upgrade your Grid Infrastructure to 19.3, (assuming you're on RHEL) you MUST be on RHEL 7.  18.X was fine with RHEL 6, but 19.3 requires RHEL 7.

3. There are a lot of changes in the OS requirements.  Make sure you review/verify the install documentation before you install it.

I'll post more about the changes in the 19.3 upgrade process later.






Friday, April 26, 2019


19c Linux x86-64  for on-prem/non-Exadata is available for download!


Some interesting things to know...

1. Its available as the traditional download or as an RPM to download.
2. Just like the Exadata version that requires OEL 7, the on-prem version requires:
      OEL 7.4, UEK 4 (4.1.12-112.16.7+)
      OEL 7.4, UEK 5 (4.14.35-1818.1.6+)
      OEL 7.4, RH Compat (3.10.0-693.5.2.0.1+)
      RHEL 7.4+ (3.10.0-693.5.2.0.1+)
      SUSE ES 12 SP3 (4.4.103-92.56+)

Have fun!


Friday, April 12, 2019

Yet one more End Of Support date push for 11.2.0.4

If you haven't heard, on 1/26 Oracle updated their release/end of life document (742060.1) to say Extended Support fees have been waived through 12/31/2018.  I understand Oracle trying to work with their customers, but a lot of people took that to mean, "Great, I can postpone working on this upgrade."

12.1.0.2 has been around since 7/22/2014, so we're coming up to 3 years to plan and execute an upgrade.  11.2 has been around since 9/1/2010...the terminal patchset isn't as old, but 7 years for a database is an eternity.

/* UPDATE */

As of 4/6/2019, if you're on Oracle E-Business Suite, database 11.2 and 12.1 extended support fee waiver has been extended again through Dec 2020...Wow!  That's an extension of almost 2 years! (2522948.1)  That means 11.2 will have had a 10+year supported run!

This is understandable since I've heard Oracle is skipping 12.2 database support, and 18.3 isn't the "long-term" version (and 12.2 and 18.X) isn't going to be supported by EBS.  This means the database version you would need to upgrade to for EBS is 19.2.  Unfortunately, 19.2 isn't available yet for non-Exadata/ODA, so there's nothing to upgrade to for the majority of EBS customers.  They couldn't end support on 12.1 at the end of June and release 19.2 support for EBS at that same time.  It typically takes months to upgrade an entire EBS landscape...so...this was inevitable.

Still, I hope you don't read this and think this grants you more time to procrastinate.  There are *a lot* of great features in 19.2!  Don't allow getting kicked off the old database version to be your primary motivation!

Friday, April 27, 2018

Poor query performance after stats were gathered?

Although the Oracle optimizer is brilliant, its not infallible.  Its vulnerability is that it depends on good table statistics to determine an optimal plan.  I optimized a query today that was projecting to use over 2PB of temp space.  It was a *horrible* plan...I started to try to rewrite it and thought...why is Oracle doing this...there isn't THAT much data.  The first thing I checked was the accuracy of the table stats...within about 10 minutes I had the query completing in ~5 seconds. 

When it comes to gathering stats, there are 2 schools of thought out there...those that gather stats frequently and those that gather stats that generate plans they're happy with, then lock them...or at least gather them much less frequently and intentionally.

Some people believe stats should be gathered frequently to always have the optimal query performance all the time.  If the table data changes sizes dramatically and frequently...this might be ok.  If the stats were gathered with estimates (which is commonly done), its possible that you'll gather stats based on a subset of your data that doesn't represent the whole table.  So then your stats aren't great...but even then...usually the optimizer gets the right plan or a plan that's "close enough" that it doesn't cause any pain.  Jonathan Lewis points out in "The Cost-Based Optimizer" (great book, by the way), that one of the primary purposes of table statistics are to mathematically create relativity between the table row counts in a join. 

This means, if the largest table in a join today is the largest table tomorrow...ie: if you have 1mil rows today and it grows to 2 mil rows, you probably don't want your plan to change and so you don't need to regather stats. 

Let's say the 1mil row table becomes a 1 row table, you could regather stats and get a new plan and everything would be great.  The next day a data load brings it up to 10 mil rows...suddenly the plan that ran great isn't finishing in its SLA.  A good plan for a query today isn't necessarily a good plan tomorrow.

My opinion is...if your table sizes fluctuate, you probably want to gather stats when the tables are large and lock them, which will cause your plans to be stable.  If the table is much smaller tomorrow, your plan might not be optimal, but it won't be worse than it is today...so you'll have ~ consistency in run time performance (and you meet your SLA's.)

Oracle has made great strides to improve this...with 12.1's OPTIMIZER_ADAPTIVE_FEATURES and 12.2's OPTIMIZER_ADAPTIVE_STATISTICS, Oracle will correct itself with statistics feedback...which will prevent you from "falling off the temp usage cliff."  Although these features are great...it would be better to not have a problem that needs to be corrected in the first place. 

Since these problems are usually on complex views (on views, on views, on views...ets...)  Here's a little query you can run to find the dependencies of the top level view, gather stats on its tables/indexes, and lock them (so the problem doesn't happen again.)  I'm gathering them w/null est % (ie:compute)...adjust that and the degree/method_opt to fit your needs.  This should generate pretty good stats and lock them, allowing the optimizer to make its brilliant decisions once again.



select
  distinct 'begin'||chr(13)||'
     SYS.DBMS_STATS.GATHER_TABLE_STATS (
    ownname=>'''||o2.owner||''',
    tabname=>'''||o2.object_name||''',
    estimate_percent  => NULL,
    method_opt=> ''FOR ALL INDEXED COLUMNS SIZE AUTO '',
    degree            => 32,
    cascade           => TRUE,
    no_invalidate  => FALSE);'||chr(13)||
    'end;'||chr(13)||
    'exec dbms_stats.lock_table_stats('''||o2.owner||''','''||o2.object_name||''');'
from   sys.dba_objects o1,
       sys.dba_objects o2,
      (Select object_id, referenced_object_id
       from   (select object_id, referenced_object_id
               from   public_dependency
               where  referenced_object_id <> object_id) pd
       start with  object_id = (select object_id from dba_objects where object_name='YOUR_TABLE_NAME' and owner='YOUR_TABLE_OWNER')
       connect by nocycle prior referenced_object_id =  object_id) o3
where o1.object_id = o3.object_id
and   o2.object_id = o3.referenced_object_id
and o2.object_type='TABLE'
and   o1.owner not in ('SYS', 'SYSTEM')
and   o2.owner not in ('SYS', 'SYSTEM')
and   o1.object_name <> 'DUAL'
and   o2.object_name <> 'DUAL';  

Thursday, August 24, 2017

Effect of MBPS vs Latency

I do *a lot* of performance testing on high performance storage arrays for multiple vendors.  Usually if I'm involved, the client is expecting to put mission critical databases on their new expensive storage, and they need to know it performs well enough to meet their needs. 


So...parsing that out..."meet their needs"...means different things to different people.  Most businesses are cyclical, so the performance they need today is likely not the performance they need at their peek.  For example...Amazon does much more business the day after Thanksgiving than they do in a random day in May.  If you gather the usage stats being used in May and size it appropriately, you're going to get a call in a few months when performance is exposed. 


Before I talk about latency, let me just say AWR does a great job of keeping performance data, if you have your data kept long enough...preferably at least 2 business cycles so you can do comparisons and projections.


This statement will keep AWR data for 3 years, capturing it at an aggressive 15 minute interval:


execute dbms_workload_repository.modify_snapshot_settings (interval => 15,retention => 1576800);


...at that point, see my other post re:gathering IOPS and Throughput requirements.


Anyway, I often have discussions with people who don't understand the effect of latency on OLTP databases.  This is a overly-focused serial example, but its enough to make the point.  Think about this...let's say you have a normal 8K block Oracle database using Netapp or EMC NFS on an active-active 10Gb network.  Let's say your amazing all-SSD storage array is capable of flowing 10Gb between multiple paths.   So...the time to move 8K over a 10Gb pipe is...


Throughput...
10Gb/s=10485760Kb/s
(8Kb/s)/(10485760Kb/s)=0.000000762939453125 seconds to copy 8Kb over the 10Gb pipe.


Latency...by the time it passes through your FC network, gets processed by the storage array, gets retrieved from disk, and makes it back to your server can easily exceed a few ms...but for fun let's say we're getting an 8ms response time.  That's .008 seconds.


.008/0.000000762939453125=10,485.76...


...so the effect of latency on your block is 10,485X greater than the effect of throughput.  If your throughput magically got faster but your latency stayed the same...performance wouldn't really improve very much.  If you went from 8ms to 5ms, on the other hand, this would have a huge effect on your database performance.


There's a lot that can affect latency...usually the features in use on the storage array play a big part.  CPU utilization on the storage array can become too high.  This is ultra complicated for the storage array guys to diagnose.  On EMC VMAX3's for example, CPU is allocated to "pools" for different features.  So...even though you may not use eNAS, by default, you allocate a lot of your VMAX CPU cores to it.  When your FC traffic pegs its cores and latency tanks...the administrator may think to look at the CPU utilization and not see an issue...there's free CPU available...just not in the pool used for the FC front end cores, so it creates a bottleneck.  Awesome performance improvements are possible by working closely with your storage vendor to reduce latency during testing...about 6 months ago I worked with a team that achieved improvements by over 50% from the standard VMAX3 as delivered by adjusting those allocations.


All this to say...Latency is very important for common OLTP databases.  Don't ignore throughput, but don't focus on it.