Wednesday, March 27, 2013

Move SQL Server transaction log files to a different location via TSQL


To optimize I/O performance of a database, it's always a good idea to keep LOG file & DATA file in separate physical drives. 

The transaction log file records every data change and DML transaction executed in the database.  Writing to the transaction log file is sequential in nature as compared to the database files which are typically random I/O.  As such, placing the log file on separate physical disk from database will allow the disk to work in sequential manner and perform optimally.  

I'm going to show a demonstration of moving LOG files to another drive.


1: Capture database and transaction log file information

USE AdventureWorks
GO
sp_helpfile
GO

2: Set database to single user mode and detach database

Use MASTER
GO
-- Set database to single user mode
ALTER DATABASE adventureWorks
SET SINGLE_USER
GO
-- Detach the database
sp_detach_db 'AdventureWorks'
GO

*** Now the database is detached.  Once the detach process is completed, then you can copy and paste the new transaction log file then delete the old transaction log file via Windows Explorer.  Once this is completed, we can attach the database with SQL Server database log file at new location with the following script:

3: Attach database with log file at new location

USE master
GO
-- Now Attach the database
sp_attach_DB 'AdventureWorks',
'D:\Program Files\Microsoft SQL Server\MSSQL\Data\AdventureWorks_Data.mdf',
'E:\Move LogFile here through T-SQL\AdventureWorks_Log.ldf'
GO

4. Validate the LOG moving

After the final attach command  transaction log file has been moved to new location and database is operational with log file on new location.  Verifying the new database transaction log location can be accomplished by re-running 

USE AdventureWorks
GO
sp_helpfile
GO

Thursday, March 14, 2013

Bringing a database out of Restoring state in SQL Server



What if I restored a database with “NO RECOVERY” option keeping in mind that I’d keep continuing with another Differential backup set / Transactional backup set next. But then I’ve decided not to proceed further?

At this moment, database is in “Restoring” state and inaccesible.

I need to run following script bringing a database back from restoring state to normal.


RESTORE DATABASE
WITH RECOVERY

MSSQL Server : The log or differential backup cannot be restored because no files are ready to rollforward

I was facing following error while restoring Differential backup.

Restore failed for Server ''. (Microsoft.SqlServer.Smo) Additional Information: System.Data.SqlClient.SqlError: The log or differential backup cannot be restored because no files are ready to rollforward. (Microsoft.SqlServer.Smo) 

The reason for this erro is: no database that was left in non-operational mode, and thus has not been cleaned up such that uncommitted transactions have not been rolled back. 

The easy way to reproduce this error is to 

-Backup the database using full recover mode 
- Do full and differential backups. 
- Restore the DB, First from Full backup then Differential

I got the above error while trying to restore the differential backup (after you just restored the full backup). 

Reason for the error:

I restored the Full backup with Recovery option. It must be restored with NORECOVERY option to allow rest of the backup sets to be restored (Differential/Transactional)

In the Microsoft SQL Server Management Studio there are three options on the Option "page" while restoring a database. 

Option 1 (the default): Leave the database ready to use by rolling back uncommitted transactions. Additional transaction logs cannot be restored.(RESTORE WITH RECOVERY) 

Option 2: Leave the database non-operational, and do not roll back uncommitted transactions. Additional transaction logs can be restored.(RESTORE WITH NORECOVERY) 

To properly restore a database that is backup up using full recovery mode with full and differential backups, here are steps:

Restore Full Backup:

  1. Open the Restore Database window in Microsoft SQL Server Management Studio
  2. Ensure the To database field is filled in with the name you want.
  3. Choose From device as the Source for restore.
  4. Choose the full backup file you want to restore. In most cases this is the most recent full backup file.
  5. Click the Options page on the left navigation.
  6. Choose Leave the database non-operational, and do not roll back uncommitted transactions. Additional transaction logs can be restored.(RESTORE WITH NORECOVERY). 
Restore Differential backup:
  1. Open the Restore Database window in Microsoft SQL Server Management Studio
  2. Ensure the To database field is filled in with the name you want. The same that you specified in step 2 for the Restore Full backup
  3. Choose From device as the Source for restore.
  4. Choose the differential backup file you want to restore. In most cases this is the most recent differential backup file.
  5. Click the Options page on the left navigation.
  6. Choose the default: Leave the database ready to use by rolling back uncommitted transactions. Additional transaction logs cannot be restored.(RESTORE WITH RECOVERY) 

If you want to restore Transactional log after Differential backup restore, then Choose "RESTORE WITH NORECOVERY" instead of "RESTORE WITH RECOVERY".

RESTORE WITH RECOVERY Needs to be the final step of a recovery process.

MSSQL Server: The tail of the log for the database "DATABASE" has not been backed up.

I was facing the following error error when attempting to restore a database in Microsoft SQL Server:

System.Data.SqlClient.SqlError: The tail of the log for the database "DATABASE" has not been backed up. Use BACKUP LOG WITH NORECOVERY to backup the log if it contains work you do not want to lose. Use the WITH REPLACE or WITH STOPAT clause of the RESTORE statement to just overwrite the contents of the log.


Solution:

Select "Overwrite the existing database" from Restore option.



This will overwrite the tail of of database log , as my DB is corrupted and wanted to restore from last full backup so it's fine for my case.

Friday, March 08, 2013

MSSQL Linked Server error: The OLE DB provider "OraOLEDB.Oracle" for linked server supplied inconsistent metadata for a column


I was trying to pull data from Oracle to MSSqlserver database using Linked server.

select * from [LINK_NAME]..SCOTT.DESCRIPTION;

But it was failing with the below error:

Msg 7356, Level 16, State 1, Line 1
The OLE DB provider "OraOLEDB.Oracle" for linked server "LINK_NAME" supplied inconsistent metadata for a column. The column "MANUFACTURER_NAME" (compile-time ordinal 6) of object ""SCOTT"."DESCRIPTION"" was reported to have a "LENGTH" of 100 at compile time and 200 at run time.

Not quite sure about the column metadata inconsistency the error reported. But got the following workaround using OPENQUERY option.

Here’s how it worked.
Select * from OPENQUERY(LINK_NAME,’SELECT * FROM SCOTT.DESCRIPTION’);

Thursday, March 07, 2013

MS SQLSERVER to ORACLE connectivity with Linked Server configuration:




1. Install Oracle Client where MSSQLSERVER is running. I've used 11.2.0 client for my case.

2. Add oracle TNS Entries for the target Oracle Database. TNS location would be:

$ORACLE_HOME/network/admin/tnsnames.ora

Here is a sample TNS file. You need to copy this from the oracle server where you want to connect.
oraLab01 =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = oralab01)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = lab.com)
    )

3. Now start configuring mssql server LINKED SERVER.

Server Objects --> Linked Servers -->Right click on Linked Servers --> New Linked Server

Here you need to mention the link name, provider name etc. As I’m connecting to Non MSSQL so I had to select "Other data Source" as server type. 

4. Select Oracle Provider for OLE DB from Provider drop down.
Type data source & provider string similar to the TNS file.





5. Click Security from left side. And select "Be made using security context" then Type username & password.




6. Click Provider --> OraOLEDB.Oracle --> Right click-->Properties --> check "Allow inprocess"-->OK

7. Right click on newly created connection ---> Test Connection ---> Success!!!

Now you can either browse the tables from Linked Server connection or you may run following to select your tables.

select * from [oralab01]..scott.tiger;



Wednesday, February 20, 2013

ORA-00054: resource busy and acquire with NOWAIT specified


A common error we face on day to day life. Happens when someone tries to modify a table which is already locked by other user.

Now there are couple of ways to get rid of it.

   1. Check to see which user is locking the object and then kill the session.

select a.sid, a.serial#
from v$session a, v$locked_object b, dba_objects c
where b.object_id = c.object_id
and a.sid = b.session_id
and OBJECT_NAME='EMP';

alter system kill session 'sid,serial#'; 

2. In 11g we can set ddl_lock_timeout to allow DDL to wait for the object becomes available. We can specify how long we’d want to wait for executing DDL.
 
SQL> alter session set ddl_lock_timeout = 600;
Session altered.
SQL> alter table emp add (gender varchar2(10));
Table altered.


  3. If you don’t want to hamper other users, then either try executing DDL at off-peak hours or
  4. Wait for few minutes until the other user releases the lock on same object.
  5. In 11g you can put a table in readonly mode to ensure no one locking it and then execute your command.

SQL> alter table emp read only;
Session altered.
 SQL> alter table emp add (gender varchar2(10));
Table altered.

ORA-00018 maximum number of sessions exceeded


ORA-00018 maximum number of sessions exceeded
Cause: All session state objects are in use.
Action: Increase the value of the SESSIONS initialization parameter.
 
ORA-00018 comes under "Oracle Database Server Messages". These messages are generated by the Oracle database server when running any Oracle program.

How to increase SESSION initialization parameter:
1. Login as sysdba
 sqlplus / as sysdba
 
2. Check Current Setting of Parameters
 sql> show parameter sessions
 sql> show parameter processes
 sql> show parameter transactions
 
3. If you are planning to increase "sessions" parameter you should also plan to increase "processes and "transactions" parameters.
 
A basic formula for determining  these parameter values is as follows:
 
  processes=x
  sessions=x*1.1+5
  transactions=sessions*1.1
  
4. These paramters can't be modified in memory. You have to modify the spfile only (scope=spfile) and bounce the instance.
 
 sql> alter system set processes=500 scope=spfile;
 sql> alter system set sessions=555 scope=spfile;
 sql> alter system set transactions=610 scope=spfile;
 sql> shutdown abort
 sql> startup 
 

How to SCRUB/MASK data using expdp (REMAP_DATA feature)


This is a common requirement for DBA to export data from production for various purposes. In a restricted & compliant environment it’s a must to mask / scrub particular data while exporting from production.
Here’s a simple demonstration. I’ve got the hint from metalink.

  1. Create a package to mask data

Note: The package needs to be created under the schema which would be used to connect to datapump utility. I’ve used SYSTEM user for this case.

as
  function toggle_case(p_value varchar2) return varchar2;
end;
/

create or replace package body datapump_remap_test
as
  function toggle_case(p_value varchar2) return varchar2 is
  begin
    return translate(p_value,    
      'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()_+-=\/ ',
        'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
end;
end;
/

  2. Datapump export with REMAP_DATA parameter:

We’d be using the created package to scrub data for particular table columns. My package would basically replace all mentioned column data into ‘xxxxx’
For this example, I’ve chosen to scrub HR.FIRST_NAME & SALES. The export dump would export the FNADVI schema as well as the the table mentioned with scrubbed column.

expdp system dumpfile=fnadvi.dmp directory=dump logfile=fnadvi.dmp.log schemas=fnadvi remap_data=fnadvi.HR.first_name:system.datapump_remap_test.toggle_case remap_data=fnadvi.SALES.address:system.datapump_remap_test.toggle_case

  3. Import the schema
Now you the import can be done anywhere with scrubbed data.

Thursday, February 14, 2013

WRAPPING Oracle procedure/function


In order to hide any procedure/function we can use oracle wrap utility. This would hide the code from user, but still the procedure can execute.

Here is the demonstration.

1   1. Create an sql file on database OS.

[oracle@lab ~]$ cat wrapping_proc.sql
CREATE OR REPLACE PROCEDURE wrapping_proc
IS
BEGIN
   DBMS_OUTPUT.PUT_LINE('WRAP TESTING');
 END;
/

    2. WRAP the sql file, this would create a wrapped file with .plb extension. Try the below command.

[oracle@lab ~]$ wrap iname=wrapping_proc.sql
PL/SQL Wrapper: Release 11.2.0.2.0- 64bit Production on Thu Feb 14 15:33:26 2013
Copyright (c) 1993, 2009, Oracle.  All rights reserved.
Processing wrapping_proc.sql to wrapping_proc.plb

3. Now copy the content of .plb file, and execute it after logging into the database.

[oracle@lab~]$ cat wrapping_proc.plb
CREATE OR REPLACE PROCEDURE wrapping_proc wrapped
a000000
1
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
7
50 92
AjmXfCjRF6msrZKufRFrtUPnC5gwg5nnm7+fMr2ywFwWlvJWFoVHDNCWFpeui5t0i8DAMv7S
hglpabhSm7JK/iiyveeysx0GMCyuJOqygaXKxqYCL7GPL64kvzIu9tFE6iQf9jmms29vnw==
/

4. Logging into the database to execute it.

[oracle@lab~]$ sqlplus scott/tiger
SQL> CREATE OR REPLACE PROCEDURE wrapping_proc wrapped
  2  a000000
  3  1
abcd
  4    5  abcd
abcd
  6    7  abcd
abcd
  8    9  abcd
 10  abcd
 11  abcd
 12  abcd
abcd
 13   14  abcd
 15  abcd
 16  abcd
 17  abcd
 18  abcd
 19  7
 20  50 92
 21  AjmXfCjRF6msrZKufRFrtUPnC5gwg5nnm7+fMr2ywFwWlvJWFoVHDNCWFpeui5t0i8DAMv7S
 22  hglpabhSm7JK/iiyveeysx0GMCyuJOqygaXKxqYCL7GPL64kvzIu9tFE6iQf9jmms29vnw==
 23
 24
 25  /

Procedure created.

   5.  Try executing and it works!

SQL> exec wrapping_proc;

PL/SQL procedure successfully completed.

SQL> drop procedure wrapping_proc;

Procedure dropped.


Now the interesting part is Even though Oracle claims the wrapped code can't be unwrapped. But it does!!!
There are couple of weblink where you can easily unwrap it. So the point of wrapping has become useless :(

The following link is one of them.
http://www.codecrete.net/UnwrapIt/

ORA-39083/ORA-02304 during impdp


Was facing the following errors while impdp. Reason for this error is OID should be unique in each DB. In this case, OID in the impdp was using old schema value thus failing.

ORA-39083: Object type TYPE failed to create with error:
ORA-02304: invalid object identifier literal

Solution is to use transform=OID:n on my impdp parameter.

Example :
impdp username DIRECTORY=DUMP transform=OID:n DUMPFILE=schema.dmp

Now all good!

Tuesday, February 12, 2013

Moving LOBS along with Tables


Moving a regular table to a different tablespace is straight forward.

Alter table move tablespace  ;

And then rebuild the indexes as it becomes invalid. But what if the table has LOB segments? Similar to INDEX, the LOB doesn’t moves where the table just relocated.

You can run the followings to see where it’s located. And take decision where do you want the LOB to move.

select owner, table_name, column_name,tablespace_name from dba_lobs where segment_name in (select segment_name from dba_segments where tablespace_name = 'SCOTT_DATA' );
Example:

select owner, table_name, column_name,tablespace_name from dba_lobs where segment_name in (select segment_name from dba_segments where tablespace_name like '%DATA' )
and table_name like '%LOG%'
and owner like 'SL%';

If you want to move only lob segment to a new tablespace then your command will be,

ALTER TABLE table_name MOVE LOB(lob_columnname) STORE AS (TABLESPACE new_tablespace_name);

We can also move table and LOB altogether with the below command:

ALTER TABLE table_name MOVE
TABLESPACE new_tablespace

LOB (lobcol1,lobcol2) STORE AS
(TABLESPACE new_tablespace);

Thursday, January 31, 2013

"ORA-12502: TNS:listener received no CONNECT_DATA" when connecting to a SCAN address


This is a client side error. Nothing to do with the database. Usually, if the hostname used in tnsnames.ora are not resolvable by the client then the subject lined error appears.

For my case, I was facing this error for a 2 node RAC cluster 11gR2 database. We are using SCAN address in the tnsnames.ora. Even though the client can resolve scan still it's failing. 
Why?
Because, not only the SCAN but all server in the cluster needs to be resolvable by application clients. This includes the host VIPs and real IP of all the servers in the RAC configuration.

Look at the demonstration of this error:
 I can ping the DB alias from client pc.

#tnsping DB1

TNS Ping Utility for Linux: Version 11.2.0.1.0 - Production on 31-JAN-2013 14:13:09
Copyright (c) 1997, 2009, Oracle.  All rights reserved.
Used parameter files:
/opt/oracle/product/11.2.0/client_1/network/admin/sqlnet.ora

Used TNSNAMES adapter to resolve the alias
Attempting to contact (DESCRIPTION = (ADDRESS=(PROTOCOL=TCP)(HOST=db1-scan)(PORT=1521)) (CONNECT_DATA = (SERVER=dedicated) (SERVICE_NAME= db1.mycompany.com)))
OK (0 msec)

But, Can't connect to the database using SQLPLUS.

sqlplus ***/****@db1

SQL*Plus: Release 11.2.0.1.0 Production on Thu Jan 31 14:13:35 2013
Copyright (c) 1982, 2009, Oracle.  All rights reserved.
ERROR:
ORA-12502: TNS:listener received no CONNECT_DATA from client


It's because, the client firewall rule is blocking it from communicating either.
VIP/Real IPS of all the servers associated with RAC configuration.

The problem was fixed after fixing firewall in accessing VIP.