Move Database Files

In Oracle 12c, a data file can be relocated while it is online. The command updates the control file and dictionary, and moves the file at the OS level. The procedure for relocating temp files, online redo logs, and control files remains unchanged.

-- move data file

SQL> alter database move datafile '/u01/oradata/db1/db1/system01.dbf' to '/u01/oradata/db1/system01.dbf';

Here are some noteworthy facts about relocating data files:
– The datafile must be online when this command is issued.
– The file is first copied to the new location, and then deleted from the old; this requires twice the space.
– There is an option to keep the source file; the default is to delete it.
– If the destination file exits, you will get an error, unless the reuse option is specified.
– In Windows, the source file is sometimes not deleted, even if the keep option is not used.
– If you flashback the database, a moved file will not be placed back in its origianl location.
– Moving a datafile on a data guard primary DB does not move it on the standby.
– PDB datafiles cannot be moved from the root container.
– You can move files from/to ASM.
– There are no special considerations for RAC.


Demo

The example illustrates how to move database files. The demo environment consists of an Oracle 12cR1 database running on an Oracle Linux guest, using Virtual Box on Windows. The example below shows how to move data files online. It also shows one procedure for moving other database files.

Example

The online move feature introduced in 12c applies to all data files, inlcuding those belonging to the system tablespace. However, there is no change in the procedure for moving temp files, online redo logs, and control files. Temp files and online redo logs can be added and dropped while the database is running. Moving control files requires a database bounce.

Move all datafiles, including system and undo.

SQL> select file_id,file_name,status from dba_data_files order by file_id;

FILE_ID    FILE_NAME                              STATUS
---------- -------------------------------------- ---------
1          /u01/oradata/db1/db1/system01.dbf      AVAILABLE
3          /u01/oradata/db1/db1/sysaux01.dbf      AVAILABLE
4          /u01/oradata/db1/db1/undotbs01.dbf     AVAILABLE
5          /u01/oradata/db1/db1/example01.dbf     AVAILABLE
6          /u01/oradata/db1/db1/users01.dbf       AVAILABLE

SQL> alter database move datafile '/u01/oradata/db1/db1/system01.dbf' to '/u01/oradata/db1/system01.dbf';

Database altered.

SQL> alter database move datafile '/u01/oradata/db1/db1/sysaux01.dbf' to '/u01/oradata/db1/sysaux01.dbf';

Database altered.

SQL> alter database move datafile '/u01/oradata/db1/db1/undotbs01.dbf' to '/u01/oradata/db1/undotbs01.dbf';

Database altered.

SQL> alter database move datafile '/u01/oradata/db1/db1/example01.dbf' to '/u01/oradata/db1/example01.dbf';

Database altered.

SQL> alter database move datafile '/u01/oradata/db1/db1/users01.dbf' to '/u01/oradata/db1/users01.dbf';

Database altered.

Verify dictionary has been updated.

SQL> select file_id,file_name,status from dba_data_files order by file_id;

FILE_ID    FILE_NAME                        STATUS
---------- -------------------------------- ---------
1          /u01/oradata/db1/system01.dbf    AVAILABLE
3          /u01/oradata/db1/sysaux01.dbf    AVAILABLE
4          /u01/oradata/db1/undotbs01.dbf   AVAILABLE
5          /u01/oradata/db1/example01.dbf   AVAILABLE
6          /u01/oradata/db1/users01.dbf     AVAILABLE

Verify data files have been relocated to destination directory at OS level.

SQL> !ls /u01/oradata/db1
db1 example01.dbf sysaux01.dbf system01.dbf undotbs01.dbf users01.dbf

… and deleted from source location.

SQL> !ls /u01/oradata/db1/db1
control01.ctl control02.ctl redo01.log redo02.log redo03.log temp01.dbf

Temp files cannot be moved online; to avoid downtime, you can add a new file and delete the old one.

SQL> alter tablespace temp add tempfile '/u01/oradata/db1/temp01.dbf' size 32m autoextend on next 16m maxsize 1024m;

Tablespace altered.

-- drop temp file; if there are active temp segments in it, you will get an error.

SQL> alter database tempfile '/u01/oradata/db1/db1/temp01.dbf' drop including datafiles;

Database altered.

Redo logs also cannot be moved online; to avoid downtime, you can add a new file and then delete the old one.

SQL> select f.group#,member,bytes,l.status from v$log l,v$logfile f where l.group#=f.group# order by 1;

GROUP#     MEMBER                   BYTES        STATUS
---------- ------------------------ ------------ -----------
1 /u01/oradata/db1/db1/redo01.log     52,428,800 CURRENT
2 /u01/oradata/db1/db1/redo02.log     52,428,800 INACTIVE
3 /u01/oradata/db1/db1/redo03.log     52,428,800 INACTIVE

Drop ORLs in /u01/oradata/db1/db1 and recreate them in /u01/oradata/db1.

Start with group 2 which is inactive.

SQL> alter database drop logfile group 2;

Database altered.

SQL> alter database add logfile group 2 '/u01/oradata/db1/redo02.log' size 50m reuse;

Database altered.

Group 3 is also inactive and can be dropped & recreated.

SQL> alter database drop logfile group 3;

Database altered.

SQL> alter database add logfile group 3 '/u01/oradata/db1/redo03.log' size 50m reuse;

Database altered.

Switch logfile to make group 2 current.

SQL> alter system switch logfile;

System altered.

SQL> select f.group#,member,bytes,l.status from v$log l,v$logfile f where l.group#=f.group# order by 1;

GROUP#     MEMBER                             BYTES        STATUS
---------- ---------------------------------- ------------ ----------
1          /u01/oradata/db1/db1/redo01.log      52,428,800 ACTIVE
2          /u01/oradata/db1/redo02.log          52,428,800 CURRENT
3          /u01/oradata/db1/redo03.log          52,428,800 UNUSED

Group 1 is still active; perform a checkpoint to make it inactive.

SQL> alter system checkpoint;

System altered.

SQL> select f.group#,member,bytes,l.status from v$log l,v$logfile f where l.group#=f.group# order by 1;

GROUP#     MEMBER                                    BYTES STATUS
———- ———————————- ———— ———–
1          /u01/oradata/db1/db1/redo01.log      52,428,800 INACTIVE
2          /u01/oradata/db1/redo02.log          52,428,800 CURRENT
3          /u01/oradata/db1/redo03.log          52,428,800 UNUSED

Now group 1 is inactive and can be dropped & recreated.

SQL> alter database drop logfile group 1;

Database altered.

SQL> alter database add logfile group 1 '/u01/oradata/db1/redo01.log' size 50m reuse;

Database altered.

Verify all ORLs are now in /u01/oradata/db1.

SQL> select f.group#,member,bytes,l.status from v$log l,v$logfile f where l.group#=f.group# order by 1;

GROUP#     MEMBER                        BYTES        STATUS
---------- ----------------------------- ------------ ----------
1          /u01/oradata/db1/redo01.log     52,428,800 UNUSED
2          /u01/oradata/db1/redo02.log     52,428,800 CURRENT
3          /u01/oradata/db1/redo03.log     52,428,800 UNUSED

Delete ORLs in /u01/oradata/db1/db1.

SQL> !rm /u01/oradata/db1/db1/redo0?.log

 

Moving control files requires downtime. They are currently in /u01/oradata/db1/db1 and will be moved to /u01/oradata/db1.

SQL> select name from v$controlfile;

NAME
-----------------------------------
/u01/oradata/db1/db1/control01.ctl
/u01/oradata/db1/db1/control02.ctl

Change their location in the spfile to /u01/oradata/db1.

SQL> alter system set control_files='/u01/oradata/db1/control01.ctl','/u01/oradata/db1/control02.ctl' scope=spfile;

System altered.

Shut down the database.

SQL> shu immediate
Database closed.
Database dismounted.
ORACLE instance shut down.

Move the files using OS commands.

SQL> !mv /u01/oradata/db1/db1/control01.ctl /u01/oradata/db1/control01.ctl

SQL> !mv /u01/oradata/db1/db1/control02.ctl /u01/oradata/db1/control02.ctl

Startup the database.

SQL> startup 
ORACLE instance started.

Total System Global Area 3607101440 bytes
Fixed Size 2930608 bytes
Variable Size 419432528 bytes
Database Buffers 3170893824 bytes
Redo Buffers 13844480 bytes
Database mounted.
Database opened.

Verify control files are in /u01/oradata/db1/.

SQL> select name from v$controlfile;

NAME
-----------------------------------
/u01/oradata/db1/control01.ctl
/u01/oradata/db1/control02.ctl