Skip to Main Content
  • Questions
  • Logic Behind alter table ... move tablespace

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Ravi.

Asked: April 21, 2001 - 9:38 pm UTC

Last updated: April 12, 2012 - 9:05 am UTC

Version: 816

Viewed 10K+ times! This question is

You Asked

Tom,

Could you please enlighten me in how alter table t_name move tablespace have been implemented in oracle. This can be done online and with nologging. But how the data is moved from from one tablespace to another. Should oracle has to prepare the insert statments and go through buffer cache like conventional insert or will it act like direct insert.

I have a situation like this. I would like to know which method would be fast.

Table size 2.5G
I would like to move from tablespace a to b. All the files for a and b are striped and in different disks
This table is an independent table. I mean no dependencies(triggers, constraints defined on them).


First approach:
--------------

alter table t1 t_name move tablespace b nologging;

Second approach :
-----------------

create table temp_table tablespace b as select * from t1;

alter table temp_table nologging;

insert /* APPEND */ into temp_table select * from t1;

drop table t1;

rename t1 temp_table ;

Will the second approach be faster than the first approach because of direct insert.

Which will be faster and why.
Can parallelism be implemneted in the first approach.
Will there be any appreciable difference in rollback segment and sort usage.


Your input is highly appreciated.

Thanks
Ravi




and Tom said...

Well the move can ONLY be online for an index organized table (IOT) not a conventional heap table.

You would

alter table T nologging; (to make the table be nologging)
alter table T move tablespace b;
alter table T logging; (to put it back)

The alter table t move tablespace b nologging; would move the table (with logging if that was what the table had) and then set the nologging attribute.

move does not use SQL to move the table. it is not doing inserts.

The nice thing about the move is that all of the indexes and grants and such will stay in place. You need to rebuild the indexes (but not recreate them) after the move.


The second may be able to go faster if you can take advantage of parallel inserts (make sure to use /*+ not just /* for hints.) It'll take more work on your part to accomplish. For 2.5 gig, I'm not sure it would be worth it -- you might spend more time developing the procedure to do it then it would take to just do it.



Rating

  (37 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

moving tablespace nologging

Gitte, January 18, 2002 - 5:52 am UTC

We use Oracle Enterprise Edition 8.1.7.2
I use:
alter table T move tablespace b nologging;

select table_name, logging from dba_tables where table_name='T';

table_name LOG
---------- ---
T YES

Whether it works with logging or nologging I don't know, but the table isn't set to nologging after the move.
Is there a difference to Oracle 8.1.6?
Thanks

Tom Kyte
January 19, 2002 - 9:46 am UTC

Ok, the logging/nologging parameter has two meanings depending on its context.

In the context you used it above, you requested that the move be done in a nologging fashion -- if the object allowed nologging.

If you "alter table t nologging", then you would have changed the logging/nologging attribute.

As always -- an example might help here.  We'll construct a table, move it and see how much redo that would take and go through various scenario's:

ops$tkyte@ORA8I.WORLD> create table t tablespace UTILS
  2  as
  3  select * from all_objects;

Table created.


<b>so there is the table we'll test with.  It started in the UTILS tablespace and:</b>

ops$tkyte@ORA8I.WORLD> 
ops$tkyte@ORA8I.WORLD> select table_name, logging from user_tables where table_name = 'T';

TABLE_NAME                     LOG
------------------------------ ---
T                              YES

<b>its logging mode is YES (on).  Now, we'll see how much redo our session has generated thus for and save it in a substitution variable V</b>

ops$tkyte@ORA8I.WORLD> 
ops$tkyte@ORA8I.WORLD> column value new_val V
ops$tkyte@ORA8I.WORLD> 
ops$tkyte@ORA8I.WORLD> select a.name, b.value
  2  from v$statname a, v$mystat b
  3  where a.statistic# = b.statistic#
  4  and a.name = 'redo size'
  5  and b.value > 0
  6  /

NAME                                VALUE
------------------------------ ----------
redo size                         3904956


<b>and we'll do your command. This command should be read in english as "move the table T from where it is to the users tablespace, and oh by the way -- if it is allowed, I would like this operation to be done without LOGGING".  Specifically, this command does NOT say "move the table and change the logging mode"</b>

ops$tkyte@ORA8I.WORLD> alter table t move tablespace users NOLOGGING;
Table altered.

ops$tkyte@ORA8I.WORLD> select a.name, b.value, b.value-&V diff
  2  from v$statname a, v$mystat b
  3  where a.statistic# = b.statistic#
  4  and a.name = 'redo size'
  5  and b.value > 0
  6  /
old   1: select a.name, b.value, b.value-&V diff
new   1: select a.name, b.value, b.value-   3904956 diff

NAME                                VALUE       DIFF
------------------------------ ---------- ----------
redo size                         7790212    3885256

<b>Now, here we can see this generated almost 4m of redo -- it would appear this operation was in fact logged, we can further confirm that by CHANGING the logging mode:
</b>

ops$tkyte@ORA8I.WORLD> 
ops$tkyte@ORA8I.WORLD> select table_name, logging from user_tables where table_name = 'T';

TABLE_NAME                     LOG
------------------------------ ---
T                              YES

ops$tkyte@ORA8I.WORLD> 
ops$tkyte@ORA8I.WORLD> alter table t nologging;

Table altered.

ops$tkyte@ORA8I.WORLD> 
ops$tkyte@ORA8I.WORLD> select table_name, logging from user_tables where table_name = 'T';

TABLE_NAME                     LOG
------------------------------ ---
T                              NO


#and moving that table again:</b>

ops$tkyte@ORA8I.WORLD> alter table t move tablespace UTILS NOLOGGING;
Table altered.

ops$tkyte@ORA8I.WORLD> 
ops$tkyte@ORA8I.WORLD> select a.name, b.value, b.value-&V diff
  2  from v$statname a, v$mystat b
  3  where a.statistic# = b.statistic#
  4  and a.name = 'redo size'
  5  and b.value > 0
  6  /
old   1: select a.name, b.value, b.value-&V diff
new   1: select a.name, b.value, b.value-   7790212 diff

NAME                                VALUE       DIFF
------------------------------ ---------- ----------
redo size                         7816656      26444

<b>Now we generate a measely 26k of redo -- just enough to log the data dictionary changes, not the move itself.  Here we moved the object without LOGGING all of the changes.


In fact, we'll find that you cannot simultaneously MOVE an object and alter it in any other fashion (it is a mutually exclusive option, you either MOVE it or you are altering it in some other fashion, but not both)</b>



ops$tkyte@ORA8I.WORLD> 
ops$tkyte@ORA8I.WORLD> alter table t logging move tablespace utils;
alter table t logging move tablespace utils
                      *
ERROR at line 1:
ORA-14133: ALTER TABLE MOVE cannot be combined with other operations

 

can we recover the move operation if use nologging?

A reader, January 19, 2002 - 10:02 am UTC

if our database crashes and we need to recover it since we used nologging for this moving operation, will this move operation be recoverable...? Or after recover it will be in its original tablespace?

Tom Kyte
January 19, 2002 - 10:52 am UTC

depends on the crash and circumstances.

After performaing a NON-LOGGED operation in an ARCHIVELOG mode database (as pretty much EVERY production database should be running in) it is advisable to do a hot backup of the affected tablespaces. This will allow you to perform media recovery on this tablespace.

If you do not -- AND you suffer a media failure (not a simple instance crash) after you do the nonlogged operation -- you will have lost data. We cannot recover it from the archives since it is not in the archives. You must take care when performing these non-logged operations and ensure you have the cooperation and OK of the guys responsible for backing UP the database. Otherwise you can easily lose data.

In a noarchive log mode database, since we can only restore to the point in time of the last full cold backup when you have media failure (and is the exact reason why you need to be in archivelog mode!), this concern is not a concern.

what does HEAP table mean?

A reader, January 19, 2002 - 10:03 am UTC

as subject

thank you

Tom Kyte
January 19, 2002 - 10:54 am UTC

Here is a very very short excerpt from my book on this topic, for all of the details and lots more -- get the book:


Heap Organized Table

A heap organized table is probably used 99% (or more) of the time in applications, although that might change over time with the advent of index organized tables, now that index organized tables can themselves be indexed. A heap organized table is the type of table you get by default when you issue the CREATE TABLE statement. If you want any other type of table structure, you would need to specify that in the CREATE statement itself.

A heap is a classic data structure studied in computer science. It is basically a big area of space, disk or memory (disk in the case of a database table of course), which is managed in an apparently random fashion. Data will be placed where it fits best, not in any sort of order. Many people expect data to come back out of a table in the same order it was put into it, but with a heap this is definitely not assured. In fact, rather the opposite is guaranteed ? the rows will come out in a wholly unpredictable order. This is quite easy to demonstrate. I will set up a table such that in my database I can fit one full row per block (I am using an 8k blocksize). You do not need to have the case where you only have one row per block ? I am just taking advantage of that to demonstrate a predictable sequence of events. The following behavior will be observed on tables of all sizes, in databases with any blocksize:
.......

free lists

Gitte, January 27, 2002 - 5:34 am UTC

I moved the tables in a new tablespace with extent management local and then analyzed the tables.
I wonder why NUM_FREELIST_BLOCKS=0 from dba_tables .
In all tables are some unused blocks and one block which has only a few rows .

Tom Kyte
January 27, 2002 - 10:40 am UTC

because the blocks that have NEVER had any data will be above the high water mark, not on the freelists.

Freelists only get blocks put on them after they are used, if they've never been used, they won't be on the freelist.

After a fresh rebuild like you just did, it is 100% natural to have very very FEW blocks on the freelist, if any.  It just means that all of the existing blocks with data are "packed" -- cannot accept any new inserts.  When you start updating/deleting data, some blocks will start ending up on the free lists.

Consider (system is a dictionary MT and users is a locally MT)

ops$tkyte@ORA817DEV.US.ORACLE.COM> drop table t;
Table dropped.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t tablespace system as select * from all_objects;
Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> analyze table t compute statistics;
Table analyzed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select num_freelist_blocks from dba_tables
  2  where owner = user and table_name = 'T';
NUM_FREELIST_BLOCKS
-------------------
                  0

<b>fully packed table, no blocks on freelist right now...
</b>

ops$tkyte@ORA817DEV.US.ORACLE.COM> delete from t where rownum < 100;

99 rows deleted.

ops$tkyte@ORA817DEV.US.ORACLE.COM> analyze table t compute statistics;

Table analyzed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select num_freelist_blocks from dba_tables
  2  where owner = user and table_name = 'T';

NUM_FREELIST_BLOCKS
-------------------
                  1

<b>and now there are- we put some blocks on the freelist by deleting from them</b>

ops$tkyte@ORA817DEV.US.ORACLE.COM> alter table t move tablespace users;
Table altered.

ops$tkyte@ORA817DEV.US.ORACLE.COM> analyze table t compute statistics;
Table analyzed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select num_freelist_blocks from dba_tables
  2  where owner = user and table_name = 'T';

NUM_FREELIST_BLOCKS
-------------------
                  0

<b>now, they are gone, all free blocks are above the HWM, not in the freelists</b>

ops$tkyte@ORA817DEV.US.ORACLE.COM> delete from t where rownum < 100;
99 rows deleted.

ops$tkyte@ORA817DEV.US.ORACLE.COM> analyze table t compute statistics;
Table analyzed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select num_freelist_blocks from dba_tables
  2  where owner = user and table_name = 'T';

NUM_FREELIST_BLOCKS
-------------------
                  1
<b>and here come some back, the table is not "packed" anymore, the delete freed up some room</b>
 

Moving tables in 7.3.4 Parallel Server

Irfan, January 28, 2002 - 1:50 am UTC

Hi Tom,
We have Oracle 7.3.4 Parallel Server in NCR SVR4 (raw file system). I also followed the same idea of the question (approach 2) for moving tables across tablespaces since 7.3.4 doesn't support alter table move tablespace.
I did like:

SQL> create table tempfoo tablespace ekatsdat
  2  as select * from orgfoo;

Table created.

SQL> drop table orgfoo cascade constraints;

Table dropped.

SQL> rename tempfoo to orgfoo;

Table renamed.

I created the indexes related to orgfoo again. I would like to know

a) Is it a good solution in 7.3.4? I also had your solution in asktom, which says to 
-exp the user account
-drop all of the objects of the user
-revoke unlimited tablspace from the user
-alter the users default tablespace to target tablespace
-imp the users data

But here I want to move only one large table, not all the tables. Once if I drop all the objects how can I import to two different tablespaces.

b) After renaming a table, Is that all the views to be run manually before running the application, else what will happen?

c) The allocated size of the table orgfoo (Tablespace EHISTDAT) is 250 MB. This is what I get from dba_data_files and dba_free_space before dropping table orgfoo.

SVRMGR> Connected.
SVRMGR> select fs.tablespace_name,file_name,sum(fs.bytes)/1024/1024 remaining,df.bytes
/1024/1024
Total_space from dba_free_space fs, dba_data_files df
where fs.file_id=df.file_id
group by fs.tablespace_name,file_name,df.bytes
order by fs.tablespace_name,file_name;

TABLESPACE_NAME       FILE_NAME  REMAINING TOTAL_SPAC       
-------------------------------------------------------
EHISTDAT       /dev/rdsk/c3t3d2sd  108.708984      795
EKATSDAT       /dev/rdsk/c3t3das4  391.285156      395

And quering after creating the table tempfoo in EKATSDAT and dropping the table orgfoo, I get the following result.

TABLESPACE_NAME   FILE_NAME      REMAINING TOTAL_SPAC       
-------------------------------------------------------
EHISTDAT       /dev/rdsk/c3t3d2sd  358.708984      795
EKATSDAT       /dev/rdsk/c3t3das4  281.285156      395

The number of extents and blocks also differs from dba_extents. Only tablespace EHISTDAT releases 250MB whereas tablespace EKATSDAT not taking the whole 250MB, instead taking only 110 MB. 
Can you briefly describe the terminology behind this. Also is it a good practice to save space?

Thanks really for eating up your time!

 

Tom Kyte
January 28, 2002 - 8:16 am UTC

The method you used is just fine. You could do a TABLE level export, instead of a user level export and that would work but what you did is just fine (as long as you got all of the constraints, triggers, grants, etc -- something EXP would get for you)

After renaming the table, you need do nothing. Views will fix themselves, as will any stored procedures.

As for the "size" difference -- the newly created table is freshly "compacted". It is not unusual for them to be "smaller". As for "is this a good way to save space", not in my opinion. Come back in a couple of weeks/months and you'll find the table grows back to this size again. Its like going on a diet, we lose the weight for a little bit but usually end up going back to our "comfortable" size. Re-orging tables on a recurring basis is

a) something I do not encourage
b) something I discourage (many "opps, i lost some data" errors happen when doing
this stuff)
c) only "saves" space for a day or two, everything wants to get back to its
steady state size over time anyway.



instance crash when move table with nologging

A reader, August 23, 2002 - 5:30 am UTC

hi tom

what will happen if instance crashes in middle a moving table operation with nologging? will we lose data?

isnt it dangerous?

Tom Kyte
August 23, 2002 - 7:14 am UTC

No, nologging only affects MEDIA recovery -- not instance failure.

Whilst moving the table in nologging, the table is copied from its permanent segment to a TEMPORARY segment. At the very end of the operation, the temporary segment is converted into a permanent segment -- that is when the new copy becomes the real table.

If during the move, we crash - SMON will simply clean up the temp segment and it will be as if we never touched the table(the permanent segment is in place)

If after the move, we crash -- it is OK, the data was written directly to disk and there is no need for instance recovery on it.

If after the move we update some data, commit and then crash -- it is OK, the redo for the updates is available and we can recover.

If after the move and before we BACKUP the files we just did the nologging operation into we have a DISK CRASH -- then, then "we have a problem houston". That is why in a production environment you might consider not using NOLOGGING or at least you will:

o backup the objects first
o perform the nologging operation
o backup the objects again



so no problem for instance crash!

A reader, August 23, 2002 - 7:46 am UTC

thank you for your prompt and precise reply Tom.

I have a further query since you said that during move operation the permanenet segment is untouched does that mean that the queries still reads the data from permanenet table and not the temporary table right? And can DML operations be performed on the table? Or there is an exclusive lock placed on the table :-?

Tom Kyte
August 23, 2002 - 1:54 pm UTC

Yes, during an alter table move, you can read the data.

Only if the operation is done "online" (alter index rebuild online for example, alter table move online -- only for indexed organized tables) can you also do DML.

In Oracle9i, there is a dbms_redefinition package for doing online rebuilds of most any object as well (allowing for DML whilst doing the move)

Sagi, October 04, 2002 - 9:24 am UTC

Hi Tom !

I have seen your example of moving table. In your example it generaged 4m or redo (when table was in logging) and 26K of redo log.

I was trying the same but dont find of the difference. Can you point at which stage I am doing wrong. Here is my output:

SQL> create table t 
  2  tablespace users
  3  as
  4  select * from all_objects ;

SQL> select tablespace_name, table_name, logginG
  2  from user_tables
  3  where table_name='T'

TABLESPACE_NAME       TABLE_NAME           LOG
------------------------------------------- ---
USERS                T                     YES

SQL> column value new_value v
SQL> select a.name, b.value 
  2  from v$statname a, v$mystat b
  3  where a.statistic#=b.statistic#
  4  and a.name='redo size' and 
  5  b.value > 0 ;

NAME           VALUE 
------------------------- ----------
redo size     1066084

SQL> alter table t move tablespace tools nologging ;
Table altered.

SQL> select a.name, b.value, b.value - &v diff
  2  from v$statname a, v$mystat b
  3  where a.statistic#=b.statistic#
  4  and a.name='redo size' and 
  5  b.value > 0 ;

NAME             VALUE       DIFF   
---------------- ---------- ----------
redo size        1120404      54320

SQL> select tablespace_name, table_name, logginG
  2  from user_tables
  3  where table_name='T' ;

TABLESPACE_NAME       TABLE_NAME          LOG 
---------------- ------------------------------ ---
TOOLS               T                     YES

SQL> alter table t nologging;
Table altered.

SQL> select tablespace_name, table_name, logginG
  2  from user_tables
  3  where table_name='T' ;

TABLESPACE_NAME   TABLE_NAME          LOG 
------------ ------------------------------ ---
TOOLS               T                 NO 

SQL> alter table t move tablespace users nologging ;
Table altered.

SQL> select a.name, b.value, b.value - &v diff
  2  from v$statname a, v$mystat b
  3  where a.statistic#=b.statistic#
  4  and a.name='redo size' and  
  5   b.value > 0 ;

NAME             VALUE         DIFF
------------------------------------
redo size        1174312      53908

So If you see, when the table was in Logging it 54320 Bytes of Redo and in No-Logging the redo is 53908 Bytes.

Infact it has taken 412 Bytes More.

I am using Oracle 8.1.7 on Windows 2000.

Anticipating your answer and explanation.

Regards,
Sagi 

Tom Kyte
October 04, 2002 - 6:41 pm UTC

You are in noarchivelog mode.

There is no need to generate redo in that mode for this operation so it doesn't -- regardless of the logging/nologging setting..

Parrallel?

Christo Kutrovsky, June 11, 2003 - 12:29 pm UTC

So if we need to "move" a table to another tablespace (for example moving from DICT to LOCALLY managed tablespaces) it will be faster if we use INSERT /*+ APPEND*/ and setting the table to nologging, then doing a move (with nologging again) ?

What about parralelism on Oracle 8.1.6 STANDARD ? Can we use something like:

alter table X move tablespace NEW parallel 4;

The command does work, but i don't know how to check if it is executed in pararallel ...

Please advise, all we care is performane. INSERT with APPEND nologging OR move nologging.


Tom Kyte
June 11, 2003 - 7:11 pm UTC

parallel operations are a feature of EE and PE.

http://docs.oracle.com/docs/cd/A87860_01/doc/server.817/a76962/ch4.htm#52939

so, in SE, no parallel for you.


but why did you get the impression that insert /*+ append */ would be best?

i would just make the table T nologging and then move it:


ops$tkyte@ORA920> alter table t move nologging parallel 4;
Table altered.

easier then insert append, don't lose grants, don't lose indexes.

(you can see if something is running in parallel by querying v$px_processes whilst it is running) 

Insert append..

Christo Kutrovsky, June 12, 2003 - 9:56 am UTC

Well, I did the testing, but not with pure SQLPLUS so please pardon the fact that I am not copy/pasting the "truth" .

I created 2 tablespaces. I created a table like dba_objects and insert/appended itself until it had ~1.8 m rows .. ~350 Mb in size with 16K blocksize.

Then I setted the table nologging (no parrallel).

Our testing machine is a 2 CPU machine with Oracle 8.1.6 EE edition non-raid disks.
The testing, each test ran at leaest 2 times:

alter table move takes 137 seconds.
Insert /*+ append*/ takes 125 seconds.

alter table move parallel takes 150 seconds, it spawns 4 processes.

alter table move parallel 2 takes 60 seconds
insert /*+ append parralel */ takes ~130 seconds.

If you insist, i will redo the same tests in pure sqlplus and copy/paste the results.

So, howcome insert /*+ append*/ is faster then move ?

redo generated was in the 200 to 350 K range.


Tom Kyte
June 12, 2003 - 10:30 am UTC

I would say the difference between 137 and 125 (wall clock seconds) is not relevant. 12 seconds isn't relevant -- especially on a computer where other things are going on.

But -- your one test shows -- alter table move parallel 2 -- is 2 times as fast (your first parallel move was penalized probably by the fact that it started the PQ slaves -- also, since 4 took that much longer, looks like disk contention on the source or target disks)...

I would not conclude from this at all that insert append is faster. I would say it is much harder, less functional and not the right way to do it though.

Followup

Christo Kutrovsky, June 12, 2003 - 12:00 pm UTC

It is disk contention. I was even amazed that it got so much faster with 2 slaves, as this is a plain non-raid IDE disk.

I was pretty much alone on the machine, and ran the tests one after the other, mixing them (test1, test1, test2, test2, test1, test2) and observing the same ~12% performance difference. Each run the seconds were off by 2 or 3 for each test.

Whenever I have the chance, I will do the test on a completelly idle multi-cpu machine, with a 2-3 gb table to minimize the error factor. I will update this thread with the results.

Thank you for following up the previous results.


A doubt !

A reader, June 18, 2003 - 7:52 am UTC

I was wondering, if a table was moved then its index would become unusable, then where does the index rebuild command rebuild the index? Is it from the table with new rowids (thats what i think so) or is it from the existing index (which has invalid rowids) ???

Regards

Tom Kyte
June 18, 2003 - 6:18 pm UTC

it has to hit the table to get the rowid info

Moving a table to another tablespace

H.S.Anand, June 19, 2003 - 6:56 am UTC

Hi tom,
I get an error when i move a table from tablespace t1 to t2, when the table contains a "LONG" columm.
How to move this table? Is their any specific syntax?

Regards,
H.S.Anand

Tom Kyte
June 19, 2003 - 8:04 am UTC

export it, import it.

longs have limits, clobs are better.

pctfree, pctused and row chaining.

Alvin, June 25, 2003 - 2:32 am UTC

Alter table t move tablespace users will take care of row chaining but what if i changed the pctused and pctfree then move it to another tbs ?

Will the all the blocks in its "new" tablespace use the new pctused and pctfree settings ?

the default settings are pctfree 10 pctused 40... if i change the pctused 80 and move it to another tbs will the blocks be in pctused 80 mode ?


Tom Kyte
June 25, 2003 - 11:56 am UTC

you can specify it on the move, or it'll pick it up from the table def itself:

ops$tkyte@ORA920LAP> select pct_free from user_tables where table_name = 'EMP';

  PCT_FREE
----------
        10

ops$tkyte@ORA920LAP>
ops$tkyte@ORA920LAP> alter table emp move pctfree 50 ;

Table altered.

ops$tkyte@ORA920LAP> select pct_free from user_tables where table_name = 'EMP';

  PCT_FREE
----------
        50

ops$tkyte@ORA920LAP> alter table emp pctfree 20;

Table altered.

ops$tkyte@ORA920LAP> alter table emp move;

Table altered.

ops$tkyte@ORA920LAP> select pct_free from user_tables where table_name = 'EMP';

  PCT_FREE
----------
        20

ops$tkyte@ORA920LAP> 

Thanks..

Alvin, June 25, 2003 - 10:41 pm UTC

I thought every block would have the value of the pctfree and pctused of the extent it belongs to when the extent was created.


Best way to reset pctree and pctused for existing data

Matt, June 03, 2004 - 2:05 am UTC

I don't think that existing data in a table will be "re-distributed" amongst blocks when using 'alter table move'. My guess is that only new data added to the table will be affected - See Below.

What is the most efficent means of rebuilding a table to pack rows onto blocks?

SQL> drop table t
  2  /

Table dropped.

SQL> create table t (id number, pad char(50) default 'x') pctfree 10 pctused 40
  2  /

Table created.

SQL> select table_name
  2        ,tablespace_name
  3        ,pct_free
  4        ,pct_used
  5   from user_tables
  6  where table_name ='T'
  7  /

TABLE_NAME   TABLESPACE_N   PCT_FREE   PCT_USED
------------ ------------ ---------- ----------
T            EVEDATA_DATA         10         40

SQL> insert into t(id) select rownum from all_objects where rownum < 1001
  2  /

1000 rows created.

SQL> select *
  2   from ( select dbms_rowid.ROWID_BLOCK_NUMBER(rowid), count(*)
  3            from t
  4            group by dbms_rowid.ROWID_BLOCK_NUMBER(rowid) )
  5    where rownum < 6
  6  /

DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)   COUNT(*)
------------------------------------ ----------
                              158090        122
                              158091        121
                              158092        121
                              158093        121
                              158094        121

SQL> alter table t pctfree 3 pctused 30
  2  /

Table altered.

SQL> select table_name
  2        ,tablespace_name
  3        ,pct_free
  4        ,pct_used
  5   from user_tables
  6  where table_name ='T'
  7  /

TABLE_NAME   TABLESPACE_N   PCT_FREE   PCT_USED
------------ ------------ ---------- ----------
T            EVEDATA_DATA          3         30

SQL> select *
  2   from ( select dbms_rowid.ROWID_BLOCK_NUMBER(rowid) block_num, count(*)
  3            from t
  4            group by dbms_rowid.ROWID_BLOCK_NUMBER(rowid) )
  5    where rownum < 6
  6  /

 BLOCK_NUM   COUNT(*)
---------- ----------
    158090        122
    158091        121
    158092        121
    158093        121
    158094        121

SQL>
SQL> drop table t
  2  /

Table dropped.

SQL> create table t (id number, pad char(50) default 'x') pctfree 3 pctused 30
  2  /

Table created.

SQL> select table_name
  2        ,tablespace_name
  3        ,pct_free
  4        ,pct_used
  5   from user_tables
  6  where table_name ='T'
  7  /

TABLE_NAME   TABLESPACE_N   PCT_FREE   PCT_USED
------------ ------------ ---------- ----------
T            EVEDATA_DATA          3         30

SQL> insert into t(id) select rownum from all_objects where rownum < 1001
  2  /

1000 rows created.

SQL> select *
  2   from ( select dbms_rowid.ROWID_BLOCK_NUMBER(rowid) block_num, count(*)
  3            from t
  4            group by dbms_rowid.ROWID_BLOCK_NUMBER(rowid) )
  5    where rownum < 6
  6  /

 BLOCK_NUM   COUNT(*)
---------- ----------
    158090        132
    158091        130
    158092        130
    158093        130
    158094        130
 

Tom Kyte
June 03, 2004 - 8:12 am UTC

I'm confused cause your example did not include an alter table MOVE at all?

alter table MOVE will redistribute data.  "alter table" without MOVE will not (that is what your example shows)

this shows the data is redistributed with an alter table move:


ops$tkyte@ORA9IR2> create table t (id number, pad char(50) default 'x') pctfree 10 pctused 40;
 
Table created.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> select table_name ,tablespace_name ,pct_free ,pct_used
  2    from user_tables
  3   where table_name ='T'
  4  /
 
TABLE_NAME                     TABLESPACE_NAME                  PCT_FREE
------------------------------ ------------------------------ ----------
  PCT_USED
----------
T                              USERS                                  10
 
 
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> insert into t(id) select rownum from all_objects where rownum < 1001;
 
1000 rows created.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> select min(cnt), max(cnt), avg(cnt)
  2    from (
  3  select count(*) cnt
  4    from t
  5   group by  dbms_rowid.rowid_block_number(rowid)
  6         )
  7  /
 
  MIN(CNT)   MAX(CNT)   AVG(CNT)
---------- ---------- ----------
        31        122 111.111111
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> alter table t move pctfree 3 pctused 30;
 
Table altered.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> select table_name ,tablespace_name ,pct_free ,pct_used
  2    from user_tables
  3   where table_name ='T'
  4  /
 
TABLE_NAME                     TABLESPACE_NAME                  PCT_FREE
------------------------------ ------------------------------ ----------
  PCT_USED
----------
T                              USERS                                   3
 
 
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> select min(cnt), max(cnt), avg(cnt)
  2    from (
  3  select count(*) cnt
  4    from t
  5   group by  dbms_rowid.rowid_block_number(rowid)
  6         )
  7  /
 
  MIN(CNT)   MAX(CNT)   AVG(CNT)
---------- ---------- ----------
        89        131        125
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> alter table t move pctfree 50 pctused 30;
 
Table altered.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> select table_name ,tablespace_name ,pct_free ,pct_used
  2    from user_tables
  3   where table_name ='T'
  4  /
 
TABLE_NAME                     TABLESPACE_NAME                  PCT_FREE
------------------------------ ------------------------------ ----------
  PCT_USED
----------
T                              USERS                                  50
 
 
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> select min(cnt), max(cnt), avg(cnt)
  2    from (
  3  select count(*) cnt
  4    from t
  5   group by  dbms_rowid.rowid_block_number(rowid)
  6         )
  7  /
 
  MIN(CNT)   MAX(CNT)   AVG(CNT)
---------- ---------- ----------
         7         68       62.5
 

Previous post was from 9.2.0.4.0

Matt, June 03, 2004 - 2:36 am UTC


Apologies.

Matt, June 06, 2004 - 7:03 pm UTC

You are correct. I schoolboy error on my part after a long day.

Cheers.

Recovering the database when one tablespace NOLOGGING

sPh, September 03, 2004 - 1:29 pm UTC

> After performaing a NON-LOGGED operation in an
> ARCHIVELOG mode database (as pretty much EVERY
> production database should be running in) it is
> advisable to do a hot backup of the affected
> tablespaces. This will allow you to perform
> media recovery on this tablespace.

Just to clarify on recovering the database when there is a tablespace and table set for NOLOGGING in a database that is otherwise set to archive log mode:

We have a table used for staging purposes. We do not care if we lose it, becuase we can always recreate it as needed. We want to minimize the amount of archive log creation when operations are done against this table.

We:
* created a seperate tablespace called USERNOLOG.
* set it to NOLOGGING
* moved the table to this tablespace
* ran ALTER TABLE T NOLOGGING

We run nightly hot backups. Will the existance of this nologging tablespace affect our ability to recover the database as a whole, or any portion of it other than the nologging tablespace? We realize we would not get the scratch tablespace back, which is fine, but would we be confronted with errors saying something like "sorry dude - if you have a nologging table you are out of luck"?

Should we move the indexes for the table into the same NOLOGGING tablespace?

Thanks!

Tom Kyte
September 03, 2004 - 1:48 pm UTC

only the blocks in the affected table will be "not recovered".

so, you don't really even need to put it in a special tablespace -- but, if you did, you could even skip backing up this tablespace alltogether, like temp.




Move tablespace

Arun Gupta, January 13, 2005 - 1:24 pm UTC

Tom,
We have a table which has grown big because of lot of deleted rows. My fellow DBAs did:
alter table t_big move tablespace new_tbs;
alter table t_big move tablespace original_tbs;

The size of the table did not change at all. The extent allocation in new_tbs was same as in original_tbs both before and after move. They could reclaim the wasted space by other methods.

Does this mean that Oracle moves complete extents from one tablespace to another? We are on 9ir2 with LMT, autoallcate and ASSM.

Thanks.

Tom Kyte
January 13, 2005 - 2:07 pm UTC

sorry -- it doesn't work that way.

it copies rows - it would "compact" space (putting pctfree back)

if the table is the same size after moving, it didn't have any free space to reclaim.



Follow up on original question...

Robert, March 01, 2006 - 1:56 pm UTC

Tom,

When Oracle MOVEs a table, does it copy the data row-by-row, block-by-block, or some other way?

....and how does MOVE's method of 'copying' compare with exp/imp or sqlldr?

Thanks,

Robert.

Tom Kyte
March 02, 2006 - 8:21 am UTC

think of it like a create table as select

it reads the data and rebuilds the table completely. It is a "reorg"


How does it compare to exp/imp or sqlldr?

o it is SAFE (anything that takes my data out of the database scares me)
o it doesn't lose grants
o it doesn't lose anything in fact
o it is easy
o it is fast

I would say none of the above apply to the other methods you mentioned, I would not even consider them.

Thanks, Tom!

Robert, March 02, 2006 - 9:52 am UTC


Move Tables into another tablespace.

Star Nirav, October 09, 2006 - 11:26 am UTC

AS SAID BY YOU, USING MOVE COMMAND IS VERY FAST AND USEFUL AND SAFE. MY QUESTION IS DO WE NEED TO DISABLE CONSTRAINTS ? DO WE NEED TO RECOMPILE THE OBJECTS... ? WHT WOULD BE THE DIFFERENCE BETWEEN MOVING TABLES AND EXPORT/IMPORT ? ALSO LET ME KNOW THAT DOES EXPORT/IMPORT RESET HWM AND HELPFUL FOR REMOVING FRAGMENTATION AND ORGANIZED TABLES AGAIN ? PLS. RESPOND ME IMMEDIATELY AS WE NEED TO CARRY OUT THIS ACTIVITY IN COMING 2 DAYS. DOES THIS COMMAND (MOVE TABLE) HAVE ANY IMPACT WITH DIFFERENT VERSIONS ?

THANKS
STAR DBA

Tom Kyte
October 09, 2006 - 11:37 am UTC

WE NEED TO FIND THAT CAPSLOCK KEY AND HIT IT :)

disable constraints - no, it knows the data is OK, the data alread exists after all...

recompile the objects - no, you never need to, anything that goes invalid will take care of itself all by itself.

what is the difference between export and import and move? - exp/imp would be wrong, this would be right. It is faster, safer, smarter. exp/imp is a logical data copy tool - you'll stand a good chance of "losing stuff" and going to backups. just don't do it.

stop using exp/imp, that is so 1990. Alter table move, tastes great, less filling. Superior, smarter, makes you look good in the morning.



immediately - huh, can I bill you for this immediately?


I've answered - just use move, stop thinking about exp/imp.

And - start TESTING, you'd be able to answer all of your own questions as you test this, because you are going to test this before inflicting this on your end users right?

Satisfied....

Star Nirav, October 09, 2006 - 12:37 pm UTC

Dear Tom,

Thanks a million for giving such a prompt and specific answer.

I found the capslock switch... :) jokes apart, Anyways, coming to the poing that let me quickly summarize from your answer is

1) Move command is useful and recommended and safest.
2) No need to disable constraints.
3) No need to recompile the existing objects.
4) Rebuilding index is necessary.
5) This is very useful with compare to Exp/Imp.

It seems that u might forgot to mention the following things in replying.

1) THIS COMMAND (MOVE TABLE)HAVE ANY IMPACT WITH DIFFERENT VERSIONS ?

Along with the reply, I got another questions.

1) Can I compress tables with this option ?
2) Can I reclaim the HWM ?
3) Can I move complete schema to another tablespace ?
4) Can this command help me to removing fragmentation and row-chaining ?
5) Do I need to analyze the objects again after moving to the new tablespaces ?
6) Can I have rollback plan if anything goes wrong..? Or can we have this information in any dynamic views ?

I am sincerely apologize if I asked silly questions. Pls. bear.

Regards,



Tom Kyte
October 09, 2006 - 1:43 pm UTC

so many #1's in the list..

alter table move is valid with 8i and above.


1) yes, it can compress
2) yes, it rebuilds the entire thing, of course the "hwm" is set anew.
3) an object at a time ,schemas are not tied to a single tablespace, so there is not any "move this schema", there is only "move this object"
4) laughing out loud. define fragmentation - hope you don't mean "more than one extent" because my advice will ON PURPOSE cause many extents to be allocated ( system allocated locally managed tablespace, initial 1k, next 1k, pctincrease 0). Row chaining - maybe, if the rows are MIGRATED, yes, if the row is chained because it is bigger than a block - no.
5) probably
6) it is transactional, the move either entirely succeeds or not. that is the perfection of move over exp/imp. tastes great, less filling. IT IS SAFE, this is what I meant by IT IS SAFE.

Shared Server doubts

Star Nirav, October 10, 2006 - 11:13 am UTC

Hey Tom,

I must say, your way of explaination is awesome and very specific.

I am having another question wrt Shared Server.

My organisation is having one web server, application server and Oracle 92070 which is in RAC. we are having 2 nodes with one user called admin. Clients across India are accessing this schema via application server and database with Dedicated Server configuration.
My question is do we need to switchover to shared server ? What I know is if we implement shared server then we could use Large Pool (As of now it is used by RMAN only) in effective way and we can define dedicated access to very few clients which are most important and for the rest, we could give them shared server so our resources can be utilized in proper manner.

Request you to throw some light on this.

Tom Kyte
October 10, 2006 - 7:54 pm UTC

I doubt you would want shared server, you have connection pools already, shared server is "connection pooling for client server applications"

would you "cache a cache"?
why would you "pool a pool" :)

??? What do you mean by that ???

Star Nirav, October 10, 2006 - 8:21 pm UTC

Hey Tk,

Can you explain me in detail as I am failed to understand your answer please...?

My daily sessions count is 1400 and 1400 respectively and total users connected are 700 (1600+1200/4), even load-balancing also required..

Pls. advise me...

Tom Kyte
October 10, 2006 - 8:32 pm UTC

you tell me where those numbers come from first. I cannot imagine your single application server really has 1,400 simultaneous users hitting "enter" at the same time.

From V$session

Star Nirav, October 10, 2006 - 8:39 pm UTC

from V$session for particularly instance vise and from gv$instance, can get the total sessions.

Thats the reason also i am asking about the load-balancing and shared server concepts.

Anyways thanks for the prompt response. Hope I have given you correct answer to make you understand about problem/scenario.


Waiting sir.... !!!

regards,
Star Nirav

Tom Kyte
October 10, 2006 - 8:43 pm UTC

"SHOW ME"

I don't see how your single middle tier machine would support 1,400 concurrent users hitting "enter"

what are you doing in the middle tier?
are you NOT using a connection pool??

Obviously not... It is 3-tier architecture...

Star Nirav, October 10, 2006 - 8:57 pm UTC

I already mentioned that it is having webserver, application server and database (92070). users are connected from webserver to app and internally app authenticates user to access the database for querying.

If you want then I can paste the spool file which can show you the current active sessions on day time, instance vise.

Also tell me what else information you want so in peak-hours, i will try to post that infromation / screenshots.

Tom Kyte
October 11, 2006 - 8:00 am UTC

umm, what pray tell do you mean by "obviously not"

The layout you just described almost ALWAYS uses a connection pool. Are you sure you have your facts here.




A reader, October 10, 2006 - 11:00 pm UTC

Do you see STATUS column active for 1400 sessions ? What kind of application is that ?
V


Yeah...

A reader, October 11, 2006 - 7:48 am UTC

and status is active and pls. keep in mind that I am talking abt user, not sys...

Pls. let me know if any more info required...

Regards,
Star Nirav

Tom Kyte
October 11, 2006 - 8:24 am UTC

I do not believe you have 1400 active sessions, I do not believe you are relating the true "architecture" of this system.

sorry, but we don't know the size/scope of your machines (especially your ONE application server with 1400 concurrent active users!!!)

we don't know the size/scope of your database machine (other than "2 nodes")

And I don't believe you are not using connection pooling??? what is this application, what is it written in, how could it not be using connection pooling.



A reader, October 11, 2006 - 2:37 pm UTC

Tom,
What is the benefit of using connection pooling when Oracle provided shared server configuration?
Thanks for your valuable input you always provided.
V


Tom Kyte
October 11, 2006 - 4:07 pm UTC

connection pooling cuts out the "connect" step.

you don't need to login, logout.

Move tablespace inquiry

EK, February 16, 2009 - 11:45 am UTC

We identified that for very large tables, overtime, serious memory fragmentation occurs. By building a custom rebuild script we are able to reorganize the table based on its PK. Does MOVE provide this as well?
Tom Kyte
February 16, 2009 - 12:55 pm UTC

how can a table lead to serious memory fragmentation?

describe.

Alter table and select simultaneously

Cajie, March 17, 2011 - 5:08 am UTC

Hi Tom,

Gr8 work to spread ur knowledge. Keep up the good work.

I have a question related to alter table but not specifically related to alter table.. move tablespace.
Conside the below table for the question:

CREATE TABLE TMP (
x int
);

There is a scenerio wherein there is a long running query on a above given table which contains around 10,000 rows, say the query is:

SELECT COUNT(T.x) FROM TMP T,TMP;

and while the query is executing, I fire an alter table statement from another session, say:

ALTER TABLE TMP
RENAME COLUMN x TO y;

Question is, How come the SELECT query give the output when the table has been altered?


Tom Kyte
March 17, 2011 - 8:37 am UTC

because the renaming of a column doesn't really change anything for the already running query.

Let me ask you this - why do you think it shouldn't/wouldn't work?


Alter table and select simultaneously

Cajie, March 18, 2011 - 4:34 am UTC

Sure Tom. Thanks, I got it.

I was looking at it in different perspective.. It seems that Oracle will only refer to column name at the beginning and later fetch the corresponding column's data and process it. Hope its right..

Can you refer me to something which explains the oracle working architecture of such scenerio.
Tom Kyte
March 18, 2011 - 8:04 am UTC

nope - such minutiae is not documented in any fashion, it just works as it should work.

madhukar, April 08, 2011 - 8:58 am UTC

Alter table move will make an index unusable and moreover as the rowid on the tables has changed, it has to actually scan all table blocks and then rebuild. This is different than a normal rebuild of index without any table move where without visiting table blocks it can rebuild itself. pls confirm.

That way, rebuilding an index after a table move is almost similar to dropping and recreating index. If so, will it be advisable to recreate index rather than rebuilding the same after a table move.
Tom Kyte
April 12, 2011 - 3:36 pm UTC

yes, if you move the table, you have to rebuild the indexes and the indexes have to be rebuilt from the table data - not from the existing index.

That way, rebuilding an index after a table move is almost similar to dropping
and recreating index.


IT IS NOT.

If you drop and recreate the index you

a) stand of chance of having the drop succeed and the create fail and having someone maybe not notice until they go to query the table and performance is horrible.

b) have to remember all of the settings for the index - tablespace, sizing, whatever

If you just leave them be - you

a) cannot lose them
b) do not have to do much to get them back in shape, a simple "alter index i rebuild" is all you need.



It would NOT be advisable to drop an index and recreate it over just rebuilding it after a move operation.

after move table to another tablespace

Aldo Ustariz, April 12, 2012 - 8:37 am UTC

Hi Tom,
After moving objects (tables and indexes) to another tablespace I got the following on dba_segments SEGMENT_NAME = BIN$vOHG7t3P4ujgQKjACAsEMQ==$0 where TABLESPACE_NAME = the source tablespace.
1 How can I get rid off them?
2 And most important what they are?
Tom Kyte
April 12, 2012 - 9:05 am UTC

those did not come from the alter table t move commands.

those came from people dropping tables, query dba_recyclebin and you'll see what tables they were before being dropped.

they exist do you can "undrop" a table

They are harmless

They are not wasting any space (their extents are in dba_free_space, they will be "recycled" as the space is needed by some other segment)

You can read about the PURGE command to clear out the recycle bin - but it is probably best to just leave them be, they are normal, natural and nothing to be cleared out on a regular basis.

The only time you might want to get rid of them is if you wanted to shrink a datafile and one of them occupied the "last extent" allocated in the file (preventing it from shrinking)

alter table move

RMK, September 07, 2013 - 5:26 am UTC

Hi Tom,

When we want to shrink and move tables via OEM, why the generated script doesn't include the statements to rebuild the indexes even though Oracle knows that the indexes will in invalid after the 'alter table move' command? Is there any reason behind it?

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library