2009년 12월 23일 수요일

ORACLE_TIP : How to add and drop online redo log members and groups?

원본 링크 : 클릭! 요새 계속 퍼오기만 하는군요!

 

 

How to add and drop online redo log members and groups?




By Vigyan Kaushik
Dec 08, 2002

Digg! digg!     Print    email to friend Email to Friend

Note: This article was written for educational purpose only. Please refer to the related vendor documentation for detail.




How to add and drop online redo log members and groups?

Redo log Files: The Oracle server maintains online redo log files to minimize the loss of data in the database. The redo log files record all changes made to data in the database buffer cache with some exceptions; for example, in the case of direct writes.

Redo log files are used in a situation such as an instance failure to recover committed data that has not been written to the data files. The redo log files are only used for recovery.

What are online Redo Log Groups?

� A set of identical copies of online redo log files is called an online redo log group.

� The background process LGWR concurrently writes the same information to all online redo log files in a group.

� The Oracle server needs a minimum of two online redo log file groups for the normal operation of a database. Oracle suggests keeping three groups.

What are online Redo Log Members?

� Each online redo log file in a group is called a member.

� Each member in a group has identical log sequence number and the same size. The log sequence number is assigned each time the server starts writing to a log group to identify each redo log file uniquely. The current log sequence number is stored in the control file and in the header of all data files.

How to obtain Information about Groups and Members? The following query returns information about the online redo log file from the control file:

SQL> select group#, sequence#, bytes, members, status from v$log;

GROUP# SEQUENCE# BYTES MEMBERS STATUS

1

215

104857600

1

INACTIVE

2

216

104857600

1

 CURRENT

3

214

104857600

1

INACTIVE

 3 rows selected.

The following query returns information about all members of a group:

SVRMGR> select * from v$logfile;

 

GROUP# STATUS TYPE MEMBER ---------- ------- ------- ---------------------------------------- 3 ONLINE /u02/ORADATA/VTEST/REDO03.LOG 2 ONLINE /u03/ORADATA/VTEST/REDO02.LOG 1 ONLINE /u03/ORADATA/VTEST/REDO01.LOG 3 rows selected.

Adding Online Redo Log Groups : In some cases you might need to create additional log file groups. For example, adding groups can solve availability problems. To create a new group of online redo log files use the following command:

ALTER DATABASE ADD LOGFILE ('/DISK1/log3a.rdo','/DISK2/log3b.rdo') size 1M;

Adding Online Redo Log Members:You can add new member to an existing redo log file group using the following command:

ALTER DATABASE ADD LOGFILE MEMBER
 /DISK2/log1b.rdo' TO GROUP 1,
'/DISK2/log2b.rdo' TO GROUP 2;

Dropping Online Redo Log Groups :To drop a group of online redo log files use the following command:

ALTER DATABASE DROP LOGFILE GROUP 3;

Dropping Online Redo Log Members: To drop a member of an online redo log group use the following command:

ALTER DATABASE DROP LOGFILE MEMBER
'/DISK2/log2b.dbf';

Please note when dropping redo log groups and redo log files, there must be at least two redo log groups and each redo log group must have at least one log member.

 

 
About author:

Vigyan Kaushik is an Oracle certified professional serving IT industry for more than 11 years as an Oracle DBA and System Administrator. He has expertise in Database Designing, Administration, Networking, Tuning, Implementation, Maintenance with web deployment activities on different Unix flavors as well as on Windows Operating Systems.

 

2009년 12월 17일 목요일

아침잠이 많은 사람들을 위한 글!!

야후에서 아침잠을 이겨내는 좋은 생활방법에 대해 나와 있길래 무단으로 펌질 해옵니다. ' ';

원본은 여기를 클릭하세요~

 

1. 매일 같은 시각에 일어납시다
주말의 밤샘으로 아무래도 일요일은 보통 때보다 늦게 일어나기 쉽상입니다만 이것이 월요일병의 원인이 됩니다 늦게 일어나면 그 만큼 체온 리듬이 늦게 올라오게 됩니다. 자연히 일요일의 밤에 체온이 내리지 않아 졸음이 오지 않아 늦게 잠을 자서 그 결과로 월요일은 좀 더 리듬이 어긋나 월요일 아침에는 쉽게 일어 날 수 없습니다.

2. 일어나면 5분내에 밖으로 나옵시다.
아침에 일어 났을 때 괴롭다. 혹은 빨리 눈을 뜨고 싶다는 것이 많은 사람들이 매일 아침 원하는 것입니다. 사실은 제일 좋은 자명종은 태양의 빛입니다. 태양의 빛에는 강한 각성 작용이 있으며 그 메카니즘은 , 빛의 신호로 체내시계를 작동시켜 뇌가 깨고 그 후 시원기분으로 눈을 뜨게 됩니다. 그리고 한층 더 입을 크게 벌려 심호흡을 크게 해 보세요. 뇌가 한층 더 활성화 되어 심신 모두 건강해지며 스트레스도 해소되어, 적극적인 하루를 보낼 수 있습니다

3. 아침 밥을 반드시 먹읍시다.
아침 식사를 드는 것은 , 음식을 씹는 것으로 뇌가 자극을 받아 활동 레벨 높일 수 있어 몸이 확실하게 눈을 뜹니다. 특히 달걀, 생선, 육고기등의 단백질은 몸 속을 따뜻하게 해서 활동 하기 쉬워집니다. 반대로 아침 식사를 거르면, 하루의 활동이 늦어지고, 그 때문에 늦은 저녁식사가 되어 잠 들기도 나빠지며 ,이튿날 아침 일어나는 것이 괴로워집니다. 어떤 사정으로 아침 식사를 들지 않는 사람들은 당분을 포함한 음료라도 마시면 좋습니다.

4. 잠을 위해서  저녁에 운동량을 늘립시다.
가벼운 죠깅,, 워킹(쇼핑) 등 조금 땀을 흘리는 정도의 운동을 매일 30분 이상 계속하면, 푹 잘 수 있습니다. 다만 자기 직전이나 너무 심한 운동을 하면, 몸 전체의 기능을 높여 그 흥분으로 오히려 깨어 버리므로 ,운동은 자기 2시간 전에는 끝내는 것이 포인트입니다

5. 저녁식사 후 곧바로 자는 것은 좋지 않다
질이 좋은 잠을 위해서는 , 저녁식사의 시각에도 배려한다. 배가 불러 만복인 상태로 잠에 들면 , 소화를 위해서 교감신경이 활발하게 작용하기 때문에 잘 수 없게 됩니다. 물론 다이어트에도 좋지 않습니다. 만복이 될 때까지 먹고 싶다면  적어도 2시간의 소화 시간이 필요합니다.

6. 목욕은 적당히 더운 물로
취침 시 뇌를 쿨 다운시켜 가는 것은 매우 중요합니다. 방법은 적당히 더운 물에 천천히 몸을 담구어 릴렉스 시키면, 몸의 긴장이 풀려 자연스럽게 잠으로 들어갈 수 있습니다. 그것은 , 목욕 후에 높아지고 있던 체온(심부)이 서서히 내리는 일로 자기 쉬워지기 때문입니다. 너무 뜨거운 물은 체온을 올려 교감신경을 자극해 뇌와 몸의 잠을 방해하므로 오히려 역효과가 됩니다

7. 자기 전에 30분 이상 편안한 시간을 갖자
우리의 몸을 조절하는 자율 신경에는 활동 중에 작용하는 교감신경과 주로 수면 중에 작용하는 부교감 신경이 있어 ,기분 좋게 잠에 들어가기 위해서는 , 부교감 신경을 작용하지 않게 되면 안됩니다. 밤 늦게까지 PC앞에 있거나 ,집에서도 일을 하고 있으면 이부자리에 들어가도 얼마간 교감신경의 긴장 상태가 계속되므로 잠들기 힘들어집니다. 자기 전은 좋아하는 음악을 듣거나 만화를 읽거나 가볍게 스트렛치를 하는 등 자신에게 맞은 방법으로 심신 모두 릴렉스를 합시다.

8. 이부자리에 들어가면  모든 것을 잊어 버리자
어떤 연구 결과에 의하면 자기 전에 공포영화를 보았을 때와 해피 엔드의 영화를 보았을 때 다음날 아침에 타액으로부터 면역 물질을 검사하면  공포영화를 보았을 때는 매우 적고 해피 엔드의 영화를 보았을 때는 배 이상으로 증가하였다고 합니다. 자기 전에 고민해도 아무것도 바뀌지 않습니다. 그것보다 하루를 어떻게든 보내 이부자리에 무사히 들어가는 것에 감사하면서 잠에 드는 것이 좋은 수면을 취할 수 있고 내일을 건강하게 활동할 수 있어 어려운 상황을 타개할 수 있습니다. 반드시 자기 전에 좋은 상황을 마음 속에 그리면서 자도록 합시다. 그것이 내일의 활력으로 연결됩니다.

2009년 12월 16일 수요일

ORACLE_TIP : The Secrets of Oracle Row Chaining and Migration(영문)

원본링크

Overview

If you notice poor performance in your Oracle database Row Chaining and Migration may be one of several reasons, but we can prevent some of them by properly designing and/or diagnosing the database.

Row Migration & Row Chaining are two potential problems that can be prevented. By suitably diagnosing, we can improve database performance. The main considerations are:

  • What is Row Migration & Row Chaining ?
  • How to identify Row Migration & Row Chaining ?
  • How to avoid Row Migration & Row Chaining ?

Migrated rows affect OLTP systems which use indexed reads to read singleton rows. In the worst case, you can add an extra I/O to all reads which would be really bad. Truly chained rows affect index reads and full table scans.

Oracle Block

The Operating System Block size is the minimum unit of operation (read /write) by the OS and is a property of the OS file system. While creating an Oracle database we have to choose the «Data Base Block Size» as a multiple of the Operating System Block size. The minimum unit of operation (read /write) by the Oracle database would be this «Oracle block», and not the OS block. Once set, the «Data Base Block Size» cannot be changed during the life of the database (except in case of Oracle 9i). To decide on a suitable block size for the database, we take into consideration factors like the size of the database and the concurrent number of transactions expected.

The database block has the following structure (within the whole database structure)

 Header

Header contains the general information about the data i.e. block address, and type of segments (table, index etc). It Also contains the information about table and the actual row (address) which that holds the data.

Free Space

Space allocated for future update/insert operations. Generally affected by the values of PCTFREE and PCTUSED parameters.

Data

 Actual row data.

FREELIST, PCTFREE and PCTUSED

While creating / altering any table/index, Oracle used two storage parameters for space control.

  • PCTFREE - The percentage of space reserved for future update of existing data.
     
  • PCTUSED - The percentage of minimum space used for insertion of new row data.
    This value determines when the block gets back into the FREELISTS structure.
     
  • FREELIST - Structure where Oracle maintains a list of all free available blocks.

Oracle will first search for a free block in the FREELIST and then the data is inserted into that block. The availability of the block in the FREELIST is decided by the PCTFREE value. Initially an empty block will be listed in the FREELIST structure, and it will continue to remain there until the free space reaches the PCTFREE value.

When the free space reach the PCTFREE value the block is removed from the FREELIST, and it is re-listed in the FREELIST table when the volume of data in the block comes below the PCTUSED value.

Oracle use FREELIST to increase the performance. So for every insert operation, oracle needs to search for the free blocks only from the FREELIST structure instead of searching all blocks.

Row Migration

We will migrate a row when an update to that row would cause it to not fit on the block anymore (with all of the other data that exists there currently).  A migration means that the entire row will move and we just leave behind the «forwarding address». So, the original block just has the rowid of the new block and the entire row is moved.

Full Table Scans are not affected by migrated rows

The forwarding addresses are ignored. We know that as we continue the full scan, we'll eventually get to that row so we can ignore the forwarding address and just process the row when we get there.  Hence, in a full scan migrated rows don't cause us to really do any extra work -- they are meaningless.

Index Read will cause additional IO's on migrated rows

When we Index Read into a table, then a migrated row will cause additional IO's. That is because the index will tell us «goto file X, block Y, slot Z to find this row». But when we get there we find a message that says «well, really goto file A, block B, slot C to find this row». We have to do another IO (logical or physical) to find the row.

Row Chaining

A row is too large to fit into a single database block. For example, if you use a 4KB blocksize for your database, and you need to insert a row of 8KB into it, Oracle will use 3 blocks and store the row in pieces. Some conditions that will cause row chaining are: Tables whose rowsize exceeds the blocksize. Tables with LONG and LONG RAW columns are prone to having chained rows. Tables with more then 255 columns will have chained rows as Oracle break wide tables up into pieces. So, instead of just having a forwarding address on one block and the data on another we have data on two or more blocks.

Chained rows affect us differently. Here, it depends on the data we need. If we had a row with two columns that was spread over two blocks, the query:

SELECT column1 FROM table

where column1 is in Block 1, would not cause any «table fetch continued row». It would not actually have to get column2, it would not follow the chained row all of the way out. On the other hand, if we ask for:

SELECT column2 FROM table

and column2 is in Block 2 due to row chaining, then you would in fact see a «table fetch continued row»

Example

The following example was published by Tom Kyte, it will show row migration and chaining. We are using an 4k block size:

SELECT name,value
  FROM v$parameter
 WHERE name = 'db_block_size';

NAME                 VALUE
--------------      ------
db_block_size         4096

Create the following table with CHAR fixed columns:

CREATE TABLE row_mig_chain_demo (
  x int
PRIMARY KEY,
  a CHAR(1000),
  b CHAR(1000),
  c CHAR(1000),
  d CHAR(1000),
  e CHAR(1000)
);

That is our table. The CHAR(1000)'s will let us easily cause rows to migrate or chain. We used 5 columns a,b,c,d,e so that the total rowsize can grow to about 5K, bigger than one block, ensuring we can truly chain a row.

INSERT INTO row_mig_chain_demo (x) VALUES (1);
INSERT INTO row_mig_chain_demo (x) VALUES (2);
INSERT INTO row_mig_chain_demo (x) VALUES (3);
COMMIT;

We are not interested about seeing a,b,c,d,e - just fetching them. They are really wide so we'll surpress their display.

column a noprint
column b noprint
column c noprint
column d noprint
column e noprint

SELECT * FROM row_mig_chain_demo;

         X
----------
         1
         2
         3

Check for chained rows:

SELECT a.name, b.value
  FROM v$statname a, v$mystat b
 WHERE a.statistic# = b.statistic#
   AND lower(a.name) = 'table fetch continued row';
NAME                                                                  VALUE
---------------------------------------------------------------- ----------
table fetch continued row                                                 0

Now that is to be expected, the rows came out in the order we put them in (Oracle full scanned this query, it processed the data as it found it). Also expected is the table fetch continued row is zero. This data is so small right now, we know that all three rows fit on a single block. No chaining.

Demonstration of the Row Migration

Now, lets do some updates in a specific way. We want to demonstrate the row migration issue and how it affects the full scan:

UPDATE row_mig_chain_demo SET a = 'z1', b = 'z2', c = 'z3' WHERE x = 3;
COMMIT;
UPDATE row_mig_chain_demo SET a = 'y1', b = 'y2', c = 'y3' WHERE x = 2;
COMMIT;
UPDATE row_mig_chain_demo SET a = 'w1', b = 'w2', c = 'w3' WHERE x = 1;
COMMIT;

Note the order of updates, we did last row first, first row last.

SELECT * FROM row_mig_chain_demo;

         X
----------
         3
         2
         1

SELECT a.name, b.value
  FROM v$statname a, v$mystat b
 WHERE a.statistic# = b.statistic#
   AND lower(a.name) = 'table fetch continued row';

NAME                                                                  VALUE
---------------------------------------------------------------- ----------
table fetch continued row                                                 0

Interesting, the rows came out «backwards» now. That is because we updated row 3 first. It did not have to migrate, but it filled up block 1. We then updated row 2. It migrated to block 2 with row 3 hogging all of the space, it had to. We then updated row 1, it migrated to block 3. We migrated rows 2 and 1, leaving 3 where it started.

So, when Oracle full scanned the table, it found row 3 on block 1 first, row 2 on block 2 second and row 1 on block 3 third. It ignored the head rowid piece on block 1 for rows 1 and 2 and just found the rows as it scanned the table. That is why the table fetch continued row is still zero. No chaining.

So, lets see a migrated row affecting the «table fetch continued row»:

SELECT * FROM row_mig_chain_demo WHERE x = 3;

         X
----------
         3

SELECT a.name, b.value
  FROM v$statname a, v$mystat b
 WHERE a.statistic# = b.statistic#
   AND lower(a.name) = 'table fetch continued row';

NAME                                                                  VALUE
---------------------------------------------------------------- ----------
table fetch continued row                                                 0

This was an index range scan / table access by rowid using the primary key.  We didn't increment the «table fetch continued row» yet since row 3 isn't migrated.

SELECT * FROM row_mig_chain_demo WHERE x = 1;

 
        X
----------
         1

SELECT a.name, b.value
  FROM v$statname a, v$mystat b
 WHERE a.statistic# = b.statistic#
   AND lower(a.name) = 'table fetch continued row';

NAME                                                                  VALUE
---------------------------------------------------------------- ----------
table fetch continued row                                                 1

Row 1 is migrated, using the primary key index, we forced a «table fetch continued row».

Demonstration of the Row Chaining

UPDATE row_mig_chain_demo SET d = 'z4', e = 'z5' WHERE x = 3;
COMMIT;

Row 3 no longer fits on block 1. With d and e set, the rowsize is about 5k, it is truly chained.

SELECT x,a FROM row_mig_chain_demo WHERE x = 3;

         X
----------
         3

SELECT a.name, b.value
  FROM v$statname a, v$mystat b
 WHERE a.statistic# = b.statistic#
   AND lower(a.name) = 'table fetch continued row';

NAME                                                                  VALUE
---------------------------------------------------------------- ----------
table fetch continued row                                                 1

We fetched column «x» and «a» from row 3 which are located on the «head» of the row, it will not cause a «table fetch continued row». No extra I/O to get it.

SELECT x,d,e FROM row_mig_chain_demo WHERE x = 3;

SELECT a.name, b.value
  FROM v$statname a, v$mystat b
 WHERE a.statistic# = b.statistic#
   AND lower(a.name) = 'table fetch continued row';

NAME                                                                  VALUE
---------------------------------------------------------------- ----------
table fetch continued row                                                 2

Now we fetch from the «tail» of the row via the primary key index. This increments the «table fetch continued row» by one to put the row back together from its head to its tail to get that data.

Now let's see a full table scan - it is affected as well:

SELECT * FROM row_mig_chain_demo;

         X
----------
         3
         2
         1

SELECT a.name, b.value
  FROM v$statname a, v$mystat b
 WHERE a.statistic# = b.statistic#
   AND lower(a.name) = 'table fetch continued row';

NAME                                                                  VALUE
---------------------------------------------------------------- ----------
table fetch continued row                                                 3

The «table fetch continued row» was incremented here because of Row 3, we had to assemble it to get the trailing columns.  Rows 1 and 2, even though they are migrated don't increment the «table fetch continued row» since we full scanned.

SELECT x,a FROM row_mig_chain_demo;

         X
----------
         3
         2
         1

SELECT a.name, b.value
  FROM v$statname a, v$mystat b
 WHERE a.statistic# = b.statistic#
   AND lower(a.name) = 'table fetch continued row';

NAME                                                                  VALUE
---------------------------------------------------------------- ----------
table fetch continued row                                                 3

No «table fetch continued row» since we didn't have to assemble Row 3, we just needed the first two columns.

SELECT x,e FROM row_mig_chain_demo;

         X
----------
         3
         2
         1

SELECT a.name, b.value
  FROM v$statname a, v$mystat b
 WHERE a.statistic# = b.statistic#
   AND lower(a.name) = 'table fetch continued row';

NAME                                                                  VALUE
---------------------------------------------------------------- ----------
table fetch continued row                                                 4

But by fetching for d and e, we incemented the «table fetch continued row». We most likely have only migrated rows but even if they are truly chained, the columns you are selecting are at the front of the table.

So, how can you decide if you have migrated or truly chained?

Count the last column in that table. That'll force to construct the entire row.

SELECT count(e) FROM row_mig_chain_demo;

  COUNT(E)
----------
         1

SELECT a.name, b.value
  FROM v$statname a, v$mystat b
 WHERE a.statistic# = b.statistic#
   AND lower(a.name) = 'table fetch continued row';

NAME                                                                  VALUE
---------------------------------------------------------------- ----------
table fetch continued row                                                 5

Analyse the table to verify the chain count of the table:

ANALYZE TABLE row_mig_chain_demo COMPUTE STATISTICS;

SELECT chain_cnt
  FROM user_tables
 WHERE table_name = 'ROW_MIG_CHAIN_DEMO';

 CHAIN_CNT
----------
         3

Three rows that are chained. Apparently, 2 of them are migrated (Rows 1 and 2) and one is truly chained (Row 3).

Total Number of «table fetch continued row» since instance startup?

The V$SYSSTAT view tells you how many times, since the system (database) was started you did a «table fetch continued row» over all tables.

sqlplus system/<password>

SELECT 'Chained or Migrated Rows = '||value
  FROM v$sysstat
 WHERE name = 'table fetch continued row';

Chained or Migrated Rows = 31637

You could have 1 table with 1 chained row that was fetched 31'637 times. You could have 31'637 tables, each with a chained row, each of which was fetched once. You could have any combination of the above -- any combo.

Also, 31'637 - maybe that's good, maybe that's bad. it is a function of

  • how long has the database has been up
  • how many rows is this as a percentage of total fetched rows.
    For example if 0.001% of your fetched are table fetch continued row, who cares!

Therefore, always compare the total fetched rows against the continued rows.

SELECT name,value FROM v$sysstat WHERE name like '%table%';

NAME                                                                  VALUE
---------------------------------------------------------------- ----------
table scans (short tables)                                           124338
table scans (long tables)                                              1485
table scans (rowid ranges)                                                0
table scans (cache partitions)                                           10
table scans (direct read)                                                 0
table scan rows gotten                                             20164484
table scan blocks gotten                                            1658293
table fetch by rowid                                                1883112
table fetch continued row                                             31637table lookup prefetch client count                                        0

How many Rows in a Table are chained?

The USER_TABLES tells you immediately after an ANALYZE (will be null otherwise) how many rows in the table are chained.

ANALYZE TABLE row_mig_chain_demo COMPUTE STATISTICS;
SELECT chain_cnt,
       round(chain_cnt/num_rows*100,2) pct_chained,
       avg_row_len, pct_free , pct_used
  FROM user_tables
WHERE table_name = 'ROW_MIG_CHAIN_DEMO';
 CHAIN_CNT PCT_CHAINED AVG_ROW_LEN   PCT_FREE   PCT_USED
---------- ----------- ----------- ---------- ----------
         3         100        3691         10         40

PCT_CHAINED shows 100% which means all rows are chained or migrated.

List Chained Rows

You can look at the chained and migrated rows of a table using the ANALYZE statement with the LIST CHAINED ROWS clause. The results of this statement are stored in a specified table created explicitly to accept the information returned by the LIST CHAINED ROWS clause. These results are useful in determining whether you have enough room for updates to rows.

Creating a CHAINED_ROWS Table

To create the table to accept data returned by an ANALYZE ... LIST CHAINED ROWS statement, execute the UTLCHAIN.SQL or UTLCHN1.SQL script in $ORACLE_HOME/rdbms/admin. These scripts are provided by the database. They create a table named CHAINED_ROWS in the schema of the user submitting the script.

create table CHAINED_ROWS (
  owner_name         varchar2(30),
  table_name         varchar2(30),
  cluster_name       varchar2(30),
  partition_name     varchar2(30),
  subpartition_name  varchar2(30),
  head_rowid         rowid,
  analyze_timestamp  date
);

After a CHAINED_ROWS table is created, you specify it in the INTO clause of the ANALYZE statement.

ANALYZE TABLE row_mig_chain_demo LIST CHAINED ROWS;

SELECT owner_name,
       table_name,
       head_rowid
 FROM chained_rows
OWNER_NAME                     TABLE_NAME                     HEAD_ROWID
------------------------------ ------------------------------ ------------------
SCOTT                          ROW_MIG_CHAIN_DEMO             AAAPVIAAFAAAAkiAAA
SCOTT                          ROW_MIG_CHAIN_DEMO             AAAPVIAAFAAAAkiAAB

How to avoid Chained and Migrated Rows?

Increasing PCTFREE can help to avoid migrated rows. If you leave more free space available in the block, then the row has room to grow. You can also reorganize or re-create tables and indexes that have high deletion rates. If tables frequently have rows deleted, then data blocks can have partially free space in them. If rows are inserted and later expanded, then the inserted rows might land in blocks with deleted rows but still not have enough room to expand. Reorganizing the table ensures that the main free space is totally empty blocks.

The ALTER TABLE ... MOVE statement enables you to relocate data of a nonpartitioned table or of a partition of a partitioned table into a new segment, and optionally into a different tablespace for which you have quota. This statement also lets you modify any of the storage attributes of the table or partition, including those which cannot be modified using ALTER TABLE. You can also use the ALTER TABLE ... MOVE statement with the COMPRESS keyword to store the new segment using table compression.

  1. ALTER TABLE MOVE

    First count the number of Rows per Block before the ALTER TABLE MOVE

    SELECT dbms_rowid.rowid_block_number(rowid) "Block-Nr", count(*) "Rows"
      FROM row_mig_chain_demo
    GROUP BY dbms_rowid.rowid_block_number(rowid) order by 1;
     Block-Nr        Rows
    ---------- ----------
          2066          3

    Now, de-chain the table, the ALTER TABLE MOVE rebuilds the row_mig_chain_demo table in a new segment, specifying new storage parameters:

    ALTER TABLE row_mig_chain_demo MOVE
       PCTFREE 20
       PCTUSED 40
       STORAGE (INITIAL 20K
                NEXT 40K
                MINEXTENTS 2
                MAXEXTENTS 20
                PCTINCREASE 0);
    Table altered.

    Again count the number of Rows per Block after the ALTER TABLE MOVE

    SELECT dbms_rowid.rowid_block_number(rowid) "Block-Nr", count(*) "Rows"
      FROM row_mig_chain_demo
    GROUP BY dbms_rowid.rowid_block_number(rowid) order by 1;

     Block-Nr        Rows
    ---------- ----------
          2322          1
          2324          1
          2325          1

     
  2. Rebuild the Indexes for the Table
    Moving a table changes the rowids of the rows in the table. This causes indexes on the table to be marked UNUSABLE, and DML accessing the table using these indexes will receive an ORA-01502 error. The indexes on the table must be dropped or rebuilt. Likewise, any statistics for the table become invalid and new statistics should be collected after moving the table.

    ANALYZE TABLE row_mig_chain_demo COMPUTE STATISTICS;

    ERROR at line 1:
    ORA-01502: index 'SCOTT.SYS_C003228' or partition of such index is in unusable
    state

    This is the primary key of the table which must be rebuilt.

    ALTER INDEX SYS_C003228 REBUILD;Index altered.

    ANALYZE TABLE row_mig_chain_demo COMPUTE STATISTICS;Table analyzed.

    SELECT chain_cnt,
           round(chain_cnt/num_rows*100,2) pct_chained,
           avg_row_len, pct_free , pct_used
      FROM user_tables
     WHERE table_name = 'ROW_MIG_CHAIN_DEMO';

     CHAIN_CNT PCT_CHAINED AVG_ROW_LEN   PCT_FREE   PCT_USED
    ---------- ----------- ----------- ---------- ----------
             1       33.33        3687         20         40

    If the table includes LOB column(s), this statement can be used to move the table along with LOB data and LOB index segments (associated with this table) which the user explicitly specifies. If not specified, the default is to not move the LOB data and LOB index segments.

Detect all Tables with Chained and Migrated Rows

Using the CHAINED_ROWS table, you can find out the tables with chained or migrated rows.

  1. Create the CHAINED_ROWS table

    cd $ORACLE_HOME/rdbms/admin
    sqlplus scott/tiger
    @utlchain.sql
     
  2. Analyse all or only your Tables

    SELECT 'ANALYZE TABLE '||table_name||' LIST CHAINED ROWS INTO CHAINED_ROWS;'
      FROM user_tables
    /


    ANALYZE TABLE ROW_MIG_CHAIN_DEMO LIST CHAINED ROWS INTO CHAINED_ROWS;
    ANALYZE TABLE DEPT LIST CHAINED ROWS INTO CHAINED_ROWS;
    ANALYZE TABLE EMP LIST CHAINED ROWS INTO CHAINED_ROWS;
    ANALYZE TABLE BONUS LIST CHAINED ROWS INTO CHAINED_ROWS;
    ANALYZE TABLE SALGRADE LIST CHAINED ROWS INTO CHAINED_ROWS;
    ANALYZE TABLE DUMMY LIST CHAINED ROWS INTO CHAINED_ROWS;
    Table analyzed.
     
  3. Show the RowIDs for all chained rows

    This will allow you to quickly see how much of a problem chaining is in each table. If chaining is prevalent in a table, then that table should be rebuild with a higher value for PCTFREE

    SELECT owner_name,
           table_name,
           count(head_rowid) row_count
      FROM chained_rows
    GROUP BY owner_name,table_name
    /


    OWNER_NAME                     TABLE_NAME                      ROW_COUNT
    ------------------------------ ------------------------------ ----------
    SCOTT                          ROW_MIG_CHAIN_DEMO                      1

Conclusion

Migrated rows affect OLTP systems which use indexed reads to read singleton rows. In the worst case, you can add an extra I/O to all reads which would be really bad. Truly chained rows affect index reads and full table scans.

  • Row migration is typically caused by UPDATE operation

  • Row chaining is typically caused by INSERT operation.

  • SQL statements which are creating/querying these chained/migrated rows will degrade the performance due to more I/O work.

  • To diagnose chained/migrated rows use ANALYZE command , query V$SYSSTAT view

  • To remove chained/migrated rows use higher PCTFREE using ALTER TABLE MOVE.

2009년 12월 9일 수요일

ORACLE_TIP : DYNAMIC SGA

OTN Discussion Forums 에서 SGA에 관한 문서를 긁어옵니다. 원본여기를 클릭하세요~

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

 

PURPOSE



Oracle 9i의 새 기능인 동적으로 SGA 파라미터들을 변경하는 방법에
대하여 알아보기로 한다.

Explanation



Oracle 8i까지는 Buffer Cache, Shared Pool, Large Pool 등과 같은 SGA
파라미터들에 대해 그 크기를 동적으로, db가 운영 중인 상태에서는 변경할
수가 없었다.
즉, 이러한 파라미터들을 변경하려면 db를 shutdown하고 initSID.ora 화일에
서 그 크기를 다시 설정하고, 이 파라미터를 이용해서 db 인스턴스를 restart
해야만 했었다.

Oracle 9i에서는 DBA가 ALTER SYSTEM 명령을 이용해서 SGA 파라미터의 크기
를 동적으로 변경할 수 있게 되었다. 이 특정을 'Dynamic SGA'라고 부른다.

SGA 전체의 최대 크기(SGA_MAX_SIZE)를 정의하고 그 한도 내에서 파라미터의
크기를 변경할 수 있는 것이다. 데이타베이스를 shutdown/startup 없이 작업
이 가능하기 때문에 'Planned Downtime'을 줄이는 한 방법으로도 이해할 수
있다.

이 글에서는 SGA에 할당할 수 있는 최소 단위인 'Granule'의 개념을 살펴보
고, 이 granule이 어떠한 방법에 의해 동적으로 할당되는지에 대해 알아보고
자 한다.
또한 Buffer Cache 파라미터 중 새로운 것과 이전 버전에 비해 달라진 내용
을 소개하기로 한다.

1. Granule

Granule은 가상 메모리 상의 연속된 공간으로, dynamic SGA 모델에서 할당할
수 있는 최소 단위이다. 이 granule의 크기는 SGA 전체의 추정값
(SGA_MAX_SIZE)에 따라 다음과 같이 구분된다.

4MB if estimated SGA size is < 128M
16MB otherwise

SGA의 Buffer Cache, Shared Pool, Large Pool 등의 파라미터는 이 granule
단위로 늘어나거나 줄어들 수 있다. (현재 dynamic SGA를 사용할 수 있는
SGA 관련 파라미터는 Buffer Cache, Shared Pool, Large Pool 세 가지이다.)

2. Dynamic SGA(DB_CACHE_SIZE, SHARED_POOL_SIZE)

DBA는 ALTER SYSTEM 명령을 통해 initSID.ora 화일에 정의된 SGA 관련 파라미
터 값을 동적으로 변경할 수 있다. SGA 파라미터의 크기를 늘려주기 위해서
는 필요한 만큼의 free granule이 존재해야만 하며, 현재 사용하고 있는 SGA
의 크기가 SGA_MAX_SIZE보다 작아야 한다. Free granule이 없다고 해서 다른
파라미터로부터 granule을 free시켜서 그 granule을 이용할 수 있는 것은 아
니다.
반드시 DBA가 명시적으로 free/allocate해야 한다.

다음의 예를 살펴보자. 설명을 단순화하기 위해 이 경우는 SGA가 Buffer
Cache와 Shared Pool로만 구성되었다고만 하자.

예) initSID.ora
SGA_MAX_SIZE = 128M
DB_CACHE_SIZE = 96M
SHARED_POOL_SIZE = 32M

Note : DB_CACHE_SIZE는 Oracle 9i에 새롭게 도입된 파라미터이다.

위와 같은 상태일 때 동적으로 SHARED_POOL_SIZE를 64M로 늘리면 에러가 발생
한다.

SQL> ALTER SYSTEM SET SHARED_POOL_SIZE=64M;
(insufficient memory error message)

이 에러는 SHARED_POOL_SIZE를 늘림으로써 전체 SGA의 크기가 SGA_MAX_SIZE
보다 커지기 때문에 발생한다. (96M + 64M > 128M)

이를 해결하기 위해서는 DB_CACHE_SIZE를 줄인 후, SHARED_POOL_SIZE를 늘린다.

SQL> ALTER SYSTEM SET DB_CACHE_SIZE=64M;
SQL> ALTER SYSTEM SET SHARED_POOL_SIZE=64M;

Note : DB_CACHE_SIZE가 shrink되는 동안에
ALTER SYSTEM SET SHARED_POOL_SIZE=64M;
를 하면 insufficient error가 발생할 수도 있다.
이 경우는 DB_CACHE_SIZE가 shrink된 후 다시 수행하면 정상적으로
수행이 된다.

Note : 위 예제의 경우 estimated SGA 크기가 128M 이상이므로, granule의
단위는 16M이다. 따라서 SGA 파라미터의 크기를 16M의 정수배로 했다.
16M의 정수배가 아닌 경우는 지정한 값보다 큰 값에 대해 16M의
정수배 중 가장 가까운 값을 택하게 된다.

즉, 아래 두 문장의 결과는 똑같다.

SQL> ALTER SYSTEM SET SHARED_POOL_SIZE=64M;

SQL> ALTER SYSTEM SET SHARED_POOL_SIZE=49M;


Note : LARGE_POOL_SIZE 와 JAVA_POOL_SIZE 파라미터는 동적으로 변경하는
것이 불가능하다.

1) Dynamic Shared Pool

인스턴스 start 후, Shared Pool의 크기는 다음과 같은 명령에 의해 동적으
로 변경(grow or shrink)될 수 있다.

ALTER SYSTEM SET SHARED_POOL_SIZE=64M;

다음과 같은 제약 사항이 있다.

- 실제 할당되는 크기는 16M의 정수배가 된다.
- 전체 SGA의 크기는 SGA_MAX_SIZE를 초과할 수는 없다.


2) Dynamic Buffer Cache

인스턴스 start 후, Buffer Cache의 크기는 다음과 같은 명령에 의해 동적으
로 변경(grow or shrink)될 수 있다.

ALTER SYSTEM SET DB_CACHE_SIZE=96M;

다음과 같은 제약 사항이 있다.

- 실제 할당되는 크기는 16M의 정수배가 된다.
- 전체 SGA의 크기는 SGA_MAX_SIZE를 초과할 수는 없다.
- DB_CACHE_SIZE는 0이 될 수 없다.

3. Buffer Cache 파라미터의 변경된 내용

여기서는 Buffer Cache 파라미터와 관련하여 Oracle 9i에 의미가 없어진 파라
미터와 새롭게 추가된 파라미터, 그리고 dynamic SGA 중 Buffer Cache와 관련
이 있는 부분에 대해 기술하고자 한다.

1) Deprecated Buffer Cache Parameters

다음의 세 가지 파라미터는 backward compatibility를 위해 존재하는 것으
로, 차후 의미가 없어진다.

- DB_BLOCK_BUFFERS
- BUFFER_POOL_KEEP
- BUFFER_POOL_RECYCLE

위의 파라미터들이 정의되어 있으면 이 값들을 사용하게 될 것이다. 하지만,
다음에 나올 새로운 파라미터들을 사용하는 것이 좋으며, 만일 위 파라미터
(DB_BLOCK_BUFFERS, BUFFER_POOL_KEEP, BUFFER_POOL_RECYCLE) 값들을 사용
한다면 이 글에서 설명한 dynamic SGA 특징을 사용할 수는 없다. 또한
initSID.ora 화일에 위 파라미터들과 새로운 파라미터를 동시에 기술한다면
에러가 발생한다.

2) New Buffer Cache Sizing Parameters

다음의 세 파라미터가 추가되었다. 이 파라미터들은 primary block size에
대한 buffer cache 정보를 다루고 있다.

- DB_CACHE_SIZE
- DB_KEEP_CACHE_SIZE
- DB_RECYCLE_CACHE_SIZE

DB_CACHE_SIZE 파라미터에 지정된 값은 primary block size에 대한 default
Buffer Pool의 크기를 의미한다. 또한 이전 버전과 마찬가지로 KEEP과
RECYCLE buffer pool을 둘 수 있는데, 이는 DB_KEEP_CACHE_SIZE,
DB_RECYCLE_CACHE_SIZE 라는 파라미터를 이용한다.

이전 버전과 다른 점은 이전 버전의 경우 각각의 파라미터
(DB_BLOCK_BUFFERS, BUFFER_POOL_KEEP,BUFFER_POOL_RECYCLE)에 정의된 값들
이 buffer 갯수(즉, 실제 메모리 크기를 구하려면 db_block_size를 곱했어야
했다. )였는데 반해 이제는 구체적인 메모리 크기이다.

또한 이전에는 DB_BLOCK_BUFFERS가 BUFFER_POOL_KEEP, BUFFER_POOL_RECYCLE
의 값을 포함하고 있었지만, 이제는 DB_CACHE_SIZE가 DB_KEEP_CACHE_SIZE,
DB_RECYCLE_CACHE_SIZE를 포함하고 있지 않다.
즉, 각각의 파라미터들은 독립적이다.

Note : Oracle 9i부터는 multiple block size(2K, 4K, 8K, 16K, 32K)를 지원한다.
위에서 언급한 primary block size는 DB_BLOCK_SIZE에 의해 정해진 block
size를 의미한다. (SYSTEM tablespace는 이 block size를 이용한다.)

3) Dynamic Buffer Cache Size Parameters

바로 위에서 언급한 세 파라미터는 아래와 같이 ALTER SYSTEM 명령에 의해
동적으로 변경 가능하다.

SQL> ALTER SYSTEM SET DB_CACHE_SIZE=96M;
SQL> ALTER SYSTEM SET DB_KEEP_CACHE_SIZE=16M;
SQL> ALTER SYSTEM SET DB_RECYCLE_CACHE_SIZE=16M;

Example


none

Reference Documents


<Note:148495.1>