-- 33 --

Oracle Internals

No book on Personal Oracle would be complete without discussing some of the internal aspects of the product. In this chapter I describe the architectural elements of the Oracle database such as the System Global Area, data dictionary, and initialization parameters. Whether you're building Oracle database applications with Personal Oracle, the Oracle Workgroup Server, or the Oracle Enterprise Server, you'll benefit from the information contained in this chapter.

The Architecture of the Oracle7 RDBMS

You can visualize an Oracle database as comprising several types of materials: operating system files, memory structures, and processes. Before an Oracle database is running, the database exists as a set of disk files. After the Oracle database has been started, a memory structure--;the System Global Area--;is allocated, and at least four background processes are activated to help Oracle perform its work. These background processes are discussed later in this chapter.

First, you need to take a closer look at the files used by Oracle.

Oracle Database Files

The files that Oracle uses for storing data are referred to as datafiles. These are the operating system files--;in the case of Personal Oracle, MS-DOS files--;assigned to a tablespace. In addition to using datafiles, Oracle also uses two other types of operating system files:



Note

Don't confuse the database control file with a SQL*Loader control file. The database control file is a binary file, whereas a SQL*Loader control file is a text file. The file extension for a Personal Oracle control file is .ora, and the file extension for a SQL*Loader control file is .ctl.


The System Global Area

The System Global Area--;or SGA--;is a shared memory structure that is allocated when an Oracle database is started. For Personal Oracle, the default size of the SGA is approximately 4MB.

Three important components of the SGA are

Oracle Background Processes

As you know, Personal Oracle for Windows 3.1 requires the installation of Microsoft's Win32 API. This layer provides Personal Oracle with the resources it needs to perform pseudo-multitasking. At a minimum, an Oracle database uses four processes.

The Oracle Data Dictionary

Oracle maintains information about the database and its operations in a set of tables called the data dictionary. The owner of these tables is a special Oracle user named SYS. You can retrieve the names of these tables by submitting the following query:

SQL> select table_name

  2  from dba_tables

  3  where

  4  owner = 'SYS';

TABLE_NAME

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

ACCESS$

ARGUMENT$

AUD$

AUDIT$

AUDIT_ACTIONS

BOOTSTRAP$

CCOL$

CDEF$

CLU$

COL$

COM$

CON$

DBMS_ALERT_INFO

DBMS_LOCK_ALLOCATED

DEF$_CALL

DEF$_CALLDEST

DEF$_DEFAULTDEST

DEF$_ERROR

DEF$_SCHEDULE

DEF$_TRAN

DEF$_TRANDEST

DEFROLE$

DEPENDENCY$

DUAL

DUC$

ERROR$

EXPACT$

FET$

FILE$

HISTOGRAM$

ICOL$

IDL_CHAR$

IDL_SB4$

IDL_UB1$

IDL_UB2$

INCEXP

INCFIL

INCVID

IND$

JOB$

LAB$

LINK$

MLOG$

OBJ$

OBJAUTH$

PENDING_SESSIONS$

PENDING_SUB_SESSIONS$

PENDING_TRANS$

PROCEDURE$

PRODUCT_PROFILE

PROFILE$

PROFNAME$

PROPS$

PSTUBTBL

RESOURCE_COST$

RESOURCE_MAP

RGCHILD$

RGROUP$

SEG$

SEQ$

SLOG$

SNAP$

SOURCE$

STMT_AUDIT_OPTION_MAP

SYN$

SYSAUTH$

SYSTEM_PRIVILEGE_MAP

TAB$

TABLE_PRIVILEGE_MAP

TRIGGER$

TRIGGERCOL$

TS$

TSQ$

UET$

UNDO$

USER$

USER_PROFILE

VIEW$

_default_auditing_options_

79 rows selected.



Warning

Never, never, never modify--;or even try to modify--;the contents or structure of any of the data dictionary tables. If you do, you stand a very good chance of corrupting the Oracle database. The contents of the data dictionary tables are modified when you use Oracle statements such as CREATE TABLE and CREATE VIEW. Directly modifying the information in a data dictionary table is akin to modifying an MS-DOS file allocation table (FAT) instead of simply issuing a DOS command to create or delete a table.


If you describe one of these tables--;for instance, TAB$, which happens to be the table of tables--;you'll see that the columns are mostly numeric.

SQL> desc sys.tab$

 Name                            Null?    Type

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

 OBJ#                            NOT NULL NUMBER

 TS#                             NOT NULL NUMBER

 FILE#                           NOT NULL NUMBER

 BLOCK#                          NOT NULL NUMBER

 CLU#                                     NUMBER

 TAB#                                     NUMBER

 COLS                            NOT NULL NUMBER

 CLUCOLS                                  NUMBER

 PCTFREE$                        NOT NULL NUMBER

 PCTUSED$                        NOT NULL NUMBER

 INITRANS                        NOT NULL NUMBER

 MAXTRANS                        NOT NULL NUMBER

 MODIFIED                        NOT NULL NUMBER

 AUDIT$                          NOT NULL VARCHAR2(32)

 ROWCNT                                   NUMBER

 BLKCNT                                   NUMBER

 EMPCNT                                   NUMBER

 AVGSPC                                   NUMBER

 CHNCNT                                   NUMBER

 AVGRLN                                   NUMBER

 SPARE1                                   NUMBER

 SPARE2                                   NUMBER

You can't really find anything useful by looking solely at TAB$; you must join TAB$ with several other tables to comprehend the table information. To simplify this operation, Oracle supplies a number of views, called data dictionary views, which join the relevant tables and return the retrieved values to appropriately named columns. Oracle has more than 150 data dictionary views, many of which fall into the following three categories:

You'll find the following views quite useful during the development and administration of an Oracle database. They are listed in logical, rather than alphabetical, order.

DBA_OBJECTS

The DBA_OBJECTS view contains primary information about all database objects such as tables and indexes. To see the types of objects that exist in the database, use the following query:

SQL> select distinct object_type

  2  from dba_objects;

OBJECT_TYPE

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

CLUSTER

FUNCTION

INDEX

PACKAGE

PACKAGE BODY

PROCEDURE

SEQUENCE

SYNONYM

TABLE

TRIGGER

VIEW

Here's how to retrieve all the indexes owned by a particular user--;for instance, SYS.

SQL> select object_name

  2  from dba_objects

  3  where

  4  owner = 'SYS' and

  5  object_type = 'INDEX'

  6  order by object_name;

OBJECT_NAME

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

DEF$_CALLS_PRIMARY

DEF$_DEFALUTDEST_PRIMARY

DEF$_ERROR_PRIMARY

DEF$_SCHEDULE_PRIMARY

DFRPC$_TRAN_PRIMARY

I_ARGUMENT1

I_AUD1

I_AUDIT

.

.

.

I_USER#

I_USER1

I_VIEW1

SYS_C00317

SYS_C00318

72 rows selected.

DBA_TABLES

The DBA_TABLES view supplies information about all the tables in an Oracle database in a form that is more usable than that supplied by TAB$. Its structure is

SQL> desc dba_tables

 Name                            Null?    Type

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

 OWNER                           NOT NULL VARCHAR2(30)

 TABLE_NAME                      NOT NULL VARCHAR2(30)

 TABLESPACE_NAME                 NOT NULL VARCHAR2(30)

 CLUSTER_NAME                             VARCHAR2(30)

 PCT_FREE                        NOT NULL NUMBER

 PCT_USED                        NOT NULL NUMBER

 INI_TRANS                       NOT NULL NUMBER

 MAX_TRANS                       NOT NULL NUMBER

 INITIAL_EXTENT                           NUMBER

 NEXT_EXTENT                              NUMBER

 MIN_EXTENTS                              NUMBER

 MAX_EXTENTS                              NUMBER

 PCT_INCREASE                             NUMBER

 BACKED_UP                                VARCHAR2(1)

 NUM_ROWS                                 NUMBER

 BLOCKS                                   NUMBER

 EMPTY_BLOCKS                             NUMBER

 AVG_SPACE                                NUMBER

 CHAIN_CNT                                NUMBER

 AVG_ROW_LEN                              NUMBER

 DEGREE                                   VARCHAR2(10)

 INSTANCES                                VARCHAR2(10)

 CACHE                                    VARCHAR2(5)

Several of the columns in DBA_TABLES return data that is computed by an ANALYZE TABLE statement (which concerns the use of the Oracle cost-based optimizer, discussed in Chapter 32, "Performance Considerations"). The columns that you would typically select from this view are OWNER, TABLE_NAME, TABLESPACE_NAME, and other columns containing the table's storage parameters.

If you wanted to see all the tables whose name contained the pattern PROD, the following query will retrieve the information you want:

SQL> select owner, table_name

  2  from dba_tables

  3  where

  4  table_name like '%PROD%'

  5  order by owner, table_name;

OWNER                          TABLE_NAME

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

DLOCKMAN                       PRODUCT

FRAYED_WIRES                   HOUSTON_PRODUCT

FRAYED_WIRES                   PORTLAND_PRODUCT

FRAYED_WIRES                   PRODUCT

FRAYED_WIRES                   SAVE_HOUSTON_PRODUCT

FRAYED_WIRES                   SAVE_PORTLAND_PRODUCT

SCOTT                          PRODUCT

SYS                            PRODUCT_PROFILE

8 rows selected.

DBA_TAB_COLUMNS

As you might have noticed, the DBA_TABLES view doesn't provide any information about a table's columns; as a separate view, DBA_TAB_COLUMNS view presents a table's structure by returning the following values:

SQL> desc dba_tab_columns

 Name                            Null?    Type

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

 OWNER                           NOT NULL VARCHAR2(30)

 TABLE_NAME                      NOT NULL VARCHAR2(30)

 COLUMN_NAME                     NOT NULL VARCHAR2(30)

 DATA_TYPE                                VARCHAR2(9)

 DATA_LENGTH                     NOT NULL NUMBER

 DATA_PRECISION                           NUMBER

 DATA_SCALE                               NUMBER

 NULLABLE                                 VARCHAR2(1)

 COLUMN_ID                       NOT NULL NUMBER

 DEFAULT_LENGTH                           NUMBER

 DATA_DEFAULT                             LONG

 NUM_DISTINCT                             NUMBER

 LOW_VALUE                                RAW(32)

 HIGH_VALUE                               RAW(32)

 DENSITY                                  NUMBER

DBA_TABLESPACES

To obtain a list of each tablespace in a database and its default storage parameters, submit the following SQL statement:

SQL> select *

  2  from dba_tablespaces;

TABLESPACE_NAME  INITIAL_EXTENT NEXT_EXTENT MIN_EXT MAX_EXT PCT_INCR STATUS

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

SYSTEM                     4096        4096       1     121        10 ONLINE

USER_DATA                  4096        4096       1     121        10 ONLINE

ROLLBACK_DATA            102400      102400       2     121        50 ONLINE

TEMPORARY_DATA             4096        4096       1     121        10 ONLINE

FRAYED_WIRES              77824       51200       1     121        15 ONLINE



DBA_DATA_FILES

The DBA_DATA_FILES data dictionary view returns the name of each datafile, its size, and its associated tablespace.

SQL> select file_name, bytes, tablespace_name

  2  from dba_data_files;

FILE_NAME                                              BYTES TABLESPACE_NAME

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

C:\ORAWIN\DBS\wdbrbs.ora                             3145728 ROLLBACK_DATA

C:\ORAWIN\DBS\wdbtemp.ora                            2097152 TEMPORARY_DATA

C:\ORAWIN\DBS\wdbuser.ora                            3145728 USER_DATA

C:\ORAWIN\DBS\wdbsys.ora                            10485760 SYSTEM

c:\orawin\dbs\wdbfray.ora                           10485760 FRAYED_WIRES

c:\orawin\dbs\wdbfray2.ora                           5242880 FRAYED_WIRES

6 rows selected.

DBA_EXTENTS

The DBA_EXTENTS view returns information about every extent that has been allocated in a database. This information includes the following:

SQL> desc dba_extents

 Name                            Null?    Type

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

 OWNER                                    VARCHAR2(30)

 SEGMENT_NAME                             VARCHAR2(81)

 SEGMENT_TYPE                             VARCHAR2(17)

 TABLESPACE_NAME                          VARCHAR2(30)

 EXTENT_ID                       NOT NULL NUMBER

 FILE_ID                         NOT NULL NUMBER

 BLOCK_ID                        NOT NULL NUMBER

 BYTES                                    NUMBER

 BLOCKS                          NOT NULL NUMBER

For example, suppose the Oracle account FRAYED_WIRES owns a table named XYZ that was created with an initial extent of 10,240 bytes. Once you've added so many rows that the first extent is filled, Oracle allocates another extent of 10,240 bytes. The extents can be seen by querying the DBA_EXTENTS view.

SQL> select segment_type, bytes

  2  from sys.dba_extents

  3  where

  4  segment_name = 'XYZ';

SEGMENT_TYPE          BYTES

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

TABLE                 10240

TABLE                 10240

DBA_SEGMENTS

In one sense, the DBA_SEGMENTS view provides a summary of the data contained in DBA_EXTENTS. Using the previous example, two rows were returned when you queried the DBA_EXTENTS view to see what extents were allocated for table XYZ. If you query the DBA_SEGMENTS view, a single row returns data about the allocation of storage for table XYZ. Notice that the value of Bytes is the sum of the bytes returned by DBA_EXTENTS for the same segment name.

SQL> select segment_name, segment_type, tablespace_name, bytes

  2  from dba_segments

  3  where

  4  segment_name = 'XYZ';

SEGMENT_NAME   SEGMENT_TYPE      TABLESPACE_NAME                    BYTES

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

XYZ            TABLE             FRAYED_WIRES                       20480

DBA_FREE_SPACE

As discussed in Chapter 27, "Managing Users and Roles," you can obtain information about the free space in a tablespace by querying the DBA_FREE_SPACE view. You can get the total number of free bytes in a tablespace with the following query:

SQL> select sum(bytes)

  2  from dba_free_space

  3  where

  4  tablespace_name = 'USER_DATA';

SUM(BYTES)

----------

   2809856

You can retrieve the size of each free extent by issuing the following statement:

SQL> select bytes

  2  from dba_free_space

  3  where

  4  tablespace_name = 'USER_DATA';

    BYTES

---------

  2801664

     8192

DBA_TRIGGERS

The DBA_TRIGGERS view provides information about each database trigger that exists in the database. You can retrieve information about all DELETE triggers with the following query:

SQL> select trigger_name, trigger_type, table_name

  2  from dba_triggers

  3  where

  4  triggering_event = 'DELETE';

TRIGGER_NAME                   TRIGGER_TYPE     TABLE_NAME

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

DELETE_INVOKE_DIS_PATIENTS     AFTER STATEMENT  INVOKE_DIS_PATIENTS

You can view the PL/SQL statements that compose a trigger by selecting the Trigger_Body column from DBA_TRIGGERS. Notice that the SQL*Plus variable long has been increased to a large number so that the entire trigger body is displayed.

SQL> set long 5000

SQL> set arraysize 1

SQL> select trigger_body

  2  from dba_triggers

  3  where

  4  trigger_name = 'DELETE_INVOKE_DIS_PATIENTS';

TRIGGER_BODY

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

begin

Dis_Patients_Normal_Temp;

end;

DBA_USERS

The DBA_USERS view contains basic information about every Oracle user. Oracle assigns each user a user ID when it is created. This user ID is also referenced in other data dictionary tables and views. Here is a simple query of DBA_USERS that returns each Oracle user (or account) and its associated user ID.

SQL> select username, user_id

  2  from dba_users;

USERNAME                         USER_ID

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

SYS                                    0

SYSTEM                                 5

SCOTT                                  8

FRAYED_WIRES                          12

DLOCKMAN                              10

ORDINARY_USER                         13

JSMITH                                14

VILLAGE_WIDGET                        15

DBA_VIEWS

If you want to see the definition of a view, you can retrieve the text of the view's query with the following SQL statement. Notice that I've set the SQL*Plus variable long to 5000 and reduced another SQL*Plus variable arraysize to 1 so that the buffer overflow error doesn't occur.

SQL> set long 5000

SQL> set arraysize 1

SQL> select text

  2  from dba_views

  3  where

  4  view_name = 'DBA_VIEWS';

TEXT

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

select u.name, o.name, v.textlength, v.text

from sys.obj$ o, sys.view$ v, sys.user$ u

where o.obj# = v.obj#

and o.owner# = u.user#

Dynamic Performance Tables

More than 50 virtual Oracle tables provide configuration and performance information about an Oracle database. By virtual, I mean that these tables don't actually use disk space to store their contents. They are born when the database is started and then die when the database is shut down. All of these tables begin with V$. In the following discussion I focus on the most useful tables.

V$LOGFILE: Information About the Redo Log Files

The only way to use a SQL statement to retrieve information about a database's redo log files is by referencing V$LOGFILE. To illustrate, the following query returns the two redo log files that exist for the Personal Oracle starter database:

SQL> select *

  2  from v$logfile;

   GROUP# STATUS  MEMBER

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

        2         C:\ORAWIN\DBS\wdblog2.ora

        1 STALE   C:\ORAWIN\DBS\wdblog1.ora

V$PARAMETER: The Initialization Parameter Value

V$PARAMETER can be quite useful. It provides the names and current values for all Oracle initialization parameters as shown:

SQL> select name, value

  2  from v$parameter

  3  order by name;

NAME                                          VALUE

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

audit_trail                                   NONE

background_dump_dest                          %RDBMS71%\trace

blank_trimming                                FALSE

cache_size_threshold                          40

checkpoint_process                            FALSE

cleanup_rollback_entries                      20

close_cached_open_cursors                     FALSE

commit_point_strength                         1

compatible

compatible_no_recovery

control_files                                 %RDBMS71_CONTROL%\ctl1.ora,

                                              %RDBMS71_ARCHIVE%\ctl1.ora

cursor_space_for_time                         FALSE

db_block_buffers                              400

db_block_checkpoint_batch                     8

db_block_lru_extended_statistics              0

db_block_lru_statistics                       FALSE

db_block_size                                 2048

db_domain                                     WORLD

db_file_multiblock_read_count                 8

db_file_simultaneous_writes                   4

db_files                                      32

db_name                                       oracle

dblink_encrypt_login                          FALSE

discrete_transactions_enabled                 FALSE

distributed_lock_timeout                      10

distributed_recovery_connection_hold_time     0

distributed_transactions                      10

dml_locks                                     100

enqueue_resources                             155

event

fixed_date

gc_rollback_segments                          20

gc_segments                                   10

gc_tablespaces                                5

global_names                                  FALSE

ifile

job_queue_interval                            60

job_queue_keep_connections                    FALSE

job_queue_processes                           0

license_max_sessions                          25

license_max_users                             0

license_sessions_warning                      0

log_archive_buffer_size                       127

log_archive_buffers                           4

log_archive_dest                              %RDBMS71_ARCHIVE%

log_archive_format                            ARC%S.%T

log_archive_start                             FALSE

log_buffer                                    65596

log_checkpoint_interval                       1000

log_checkpoint_timeout                        0

log_checkpoints_to_alert                      FALSE

log_files                                     255

log_simultaneous_copies                       0

log_small_entry_max_size                      800

max_commit_propagation_delay                  90000

max_dump_file_size                            5120

max_enabled_roles                             8

max_rollback_segments                         30

mts_dispatchers

mts_listener_address                          (address=(protocol=ipc)(key=%s))

mts_max_dispatchers                           0

mts_max_servers                               0

mts_servers                                   0

mts_service

nls_currency

nls_date_format

nls_date_language

nls_iso_currency

nls_language                                  AMERICAN

nls_numeric_characters

nls_sort

nls_territory                                 AMERICA

open_cursors                                  50

open_links                                    20

optimizer_comp_weight                         0

optimizer_mode                                CHOOSE

os_authent_prefix                             OPS$

os_roles                                      FALSE

parallel_default_max_instances                0

parallel_default_max_scans                    0

parallel_default_scansize                     100

parallel_max_servers                          5

parallel_min_servers                          0

parallel_server_idle_time                     5

pre_page_sga                                  FALSE

processes                                     50

recovery_parallelism                          0

remote_login_passwordfile                     EXCLUSIVE

remote_os_authent                             FALSE

remote_os_roles                               FALSE

resource_limit                                FALSE

rollback_segments

row_cache_cursors                             10

row_locking                                   ALWAYS

sequence_cache_entries                        10

sequence_cache_hash_buckets                   10

serializable                                  FALSE

session_cached_cursors                        0

sessions                                      60

shared_pool_size                              3500000

single_process                                FALSE

snapshot_refresh_interval                     60

snapshot_refresh_keep_connections             FALSE

snapshot_refresh_processes                    0

sort_area_retained_size                       262144

sort_area_size                                262144

sort_mts_buffer_for_fetch_size                0

sort_read_fac                                 20

sort_spacemap_size                            512

sql92_security                                FALSE

sql_trace                                     FALSE

temporary_table_locks                         60

thread                                        0

timed_statistics                              FALSE

transactions                                  66

transactions_per_rollback_segment             16

user_dump_dest                                %RDBMS71%\trace

117 rows selected.

V$SGA: Information About the SGA

The performance table V$SGA displays rudimentary data about the SGA's size, which is the same information that SQL*DBA displays when it is used to start an Oracle instance.

SQL> select *

  2  from v$sga;

NAME                     VALUE

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

Fixed Size               36432

Variable Size          3846292

Database Buffers        819200

Redo Buffers             65596

The ROWID

Like SYSDATE and USER, ROWID is a pseudocolumn that returns a unique internal storage location for a table's rows. You can select ROWID from any table. Its format is

block-number.row-number.file_number

where block-number is an eight-digit hexadecimal number that represents the relative block number in the datafile referenced by file-number; row-number is the number of the row within its block, beginning with 1; and file_number is the database file number in which block-number resides.

To illustrate, here's how you can retrieve the ROWID for the rows in the Product table:

SQL> select rowid, Product_ID, Manufacturer_ID

  2  from Product;

ROWID              PRODUCT_ID   MANUFAC

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

00000043.0000.0002 A2001        TES801

00000043.0001.0002 A504         SEN101

00000043.0002.0002 A509         SEN101

00000043.0003.0002 A903         TES801

00000043.0004.0002 B901         TES801

00000043.0005.0002 B801         SEN101

00000043.0006.0002 C2002        MIT501

00000043.0007.0002 C2005        MIT501

00000043.0008.0002 C3002        SEN101

00000043.0009.0002 B311         TES801

00000043.000A.0002 B9310        SEN101

00000043.000B.0002 B384         TES801

00000043.000C.0002 D301         SEN101

00000043.000D.0002 TR901        TES801

00000043.000E.0002 X1000        GOL201

15 rows selected.

One way to distinguish between two rows that have identical values for every column is by retrieving each row's ROWID. Suppose a table named XYZ has two columns, Column1 and Column2, which are both declared as numbers. You can insert 1,000 rows into XYZ by running the following PL/SQL script:

SQL> create table XYZ (

  2  Column1   number,

  3  Column2   number);

Table created.

SQL>

SQL> declare

  2

  2  max_records constant int := 1000;

  3  i           int := 1;

  4

  4

  4  begin

  5

  5  for i in 1..max_records loop

  6

  6    insert into XYZ

  7      (Column1, Column2)

  8    values

  9      (i, i);

 10

 10  end loop;

 11

 11  commit;

 12

 12  end;

 13  /

PL/SQL procedure successfully completed.

SQL> select count(*)

  2  from XYZ;

 COUNT(*)

---------

     1000

Next add a duplicate row to XYZ to represent a bad row that you've inherited from some legacy data:

SQL> insert into XYZ

  2  (Column1, Column2)

  3  values

  4  (1000, 1000);

1 row created.

SQL> commit;

Commit complete.

Here's a simple way to find the duplicate rows in the table:

SQL> select Column1, Column2

  2  from XYZ

  3  having count(*) > 1

  4  group by Column1, Column2;

  COLUMN1   COLUMN2

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

     1000      1000

SQL> select Column1, Column2

  2  from XYZ

  3  where

  4  Column1 = 1000 and

  5  Column2 = 1000;

  COLUMN1   COLUMN2

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

     1000      1000

     1000      1000

What can you do about these duplicate rows? Please ignore the fact that this table has only two columns for simplicity; in a real situation, you could encounter this problem with a table having more than 100 columns. You can't delete one row without deleting the other because you don't have any way to distinguish between them--;after all, they are duplicates. You can't update one of the rows to distinguish it from the other. However, you can identify these duplicate rows by their ROWIDs.

SQL> select ROWID, Column1, Column2

  2  from XYZ

  3  where

  4  Column1 = 1000 and

  5  Column2 = 1000;

ROWID                COLUMN1   COLUMN2

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

000000E1.0020.0006      1000      1000

000000E1.0021.0006      1000      1000

You can delete one of the rows--;whichever one you want--;by referencing its ROWID in this manner:

SQL> delete from XYZ

  2  where

  3  rowid = '000000E1.0020.0006';

1 row deleted.

SQL> select rowid, Column1, Column2

  2  from XYZ;

ROWID                COLUMN1   COLUMN2

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

000000E1.0021.0006      1000      1000



STRONG ROWID VALUES

In their hunger for the secrets of Oracle, some developers are elated when they learn about the ROWID pseudocolumn. The developers think they've learned a shortcut when they encounter the chapter (Chapter 13) of the Oracle7 Server Concepts manual that deals with the rule-based optimizer and read that the fastest way to access a single row is by ROWID. "Great," the clever developer thinks. "I'll add a column to all of my tables to store ROWID, and then I'll select the ROWID of each row and store the value in my new column. I'll have the fastest Oracle database on my block." The clever developer has just one problem: He or she has no guarantee that a row's ROWID will never change. For example, if you export the contents of a table, delete its rows, and import those rows back into the table, each row will probably have a different ROWID from what it had before. The only way you could be sure that you had the correct ROWIDs before using them would be to select every row's ROWID and use those ROWIDs in your query. If you did so, you'd be performing an additional query every time you wanted to retrieve a row! And that's not counting the layer of ugly complexity you'd be adding to the database. If you remember only one thing from this book, remember this: Never store ROWID as a column in a table.


Oracle Initialization Parameters

As with other components of Personal Oracle, the Oracle initialization parameters as supplied are designed to work for the majority of Personal Oracle applications. If you change the value of an initialization parameter, the change takes effect the next time the Oracle database is started. Changing an initialization parameter won't affect a database that is running. The next sections look at the procedure for changing an initialization parameter.

Changing an Initialization Parameter in Windows 95

To demonstrate how you can change an Oracle initialization parameter, I will set two parameters--;SQL_TRACE and TIMED_STATISTICS--;to TRUE. When enabled, these parameters create for each Oracle session a trace file that contains each SQL statement processed during that session. If you do set these parameters to TRUE, you will see some decrease in the performance of the database because of the extra processing associated with the trace files.

In Personal Oracle for Windows 95, these initialization parameters are stored in C:\Orawin95\Database\Initorcl.ora. To set SQL_TRACE and TIMED_STATISTICS to TRUE, simply edit the appropriate parameters in the file. For example, make sure that the following two lines exist in the file:

sql_trace =  true

timed_statistics = true

The new value for an initialization parameter will not take effect until the next time the database is started.

Changing an Initialization Parameter in Windows 3.1

In Personal Oracle for Windows 3.1, initialization parameters are changed with Database Manager. When you invoke Database Manager by double-clicking its icon in the Personal Oracle program group, you'll see a set of buttons on the right side of the screen. When you click the Config button, Database Manager brings up the Configure Initialization Parameters screen. (See Figure 33.1.)

Figure 33.1 The Configure Initialization Parameters screen.

You need to provide a configuration name so that you can save any modified initialization parameters. Click the Save As button and type initpo7. (See Figure 33.2.)

Figure 33.2 Naming and saving a configuration.

When you click the OK button to save the configuration, Database Manager displays a message to inform you that any changes to the initialization parameters won't take effect until the next time the database is started. (See Figure 33.3.)

Figure 33.3 The Database Manager message about parameter editing.

Once more, the Configure Initialization Parameters screen appears. However, this time, the configuration name is initpo7. (See Figure 33.4.)

Figure 33.4 Database Manager displays the configuration name.

Click the Advanced button to modify individual initialization parameters. Database Manager will display a warning message that indicates that changing the value of an initialization parameter can cause the database to cease to function. (See Figure 33.5.) Please take this message to heart--;it's quite accurate. If you're willing to experiment, the worst thing that might happen is that you'll need to reinstall the starter database. Be sure to export your tables before you begin experimenting.

Figure 33.5 Warning message about the danger of editing parameters.

Database Manager brings up the Advanced Parameter Editing screen. (See Figure 33.6.) Click the down arrow on the Parameter drop-down list to display a list of all parameters. Click the SQL_TRACE parameter. (See Figure 33.7.)

Figure 33.6 The Advanced Parameter Editing screen.
Figure 33.7 Displaying the value of SQL_TRACE.

In the Value field, type in the value TRUE. Click the Set button and then the OK button. (See Figure 33.8.)

Figure 33.8 Setting SQL_TRACE to TRUE.

Set the TIMED_STATISTICS parameter to TRUE by following the preceding steps. Click the Set button. (See Figure 33.9.) The next time that the Oracle instance starts, SQL_TRACE and TIMED_STATISTICS will be set to TRUE.

Figure 33.9 Setting TIMED_STATISTICS to TRUE.

At this point, you should shut down the instance and restart it for the modified initialization parameters to take effect. Once you've had practice making these changes, I recommend that you set SQL_TRACE and TIMED_STATISTICS back to FALSE if you're not interested in generating trace files for each Oracle session.

AUDIT_TRAIL

Oracle is able to audit a user's database activity. Events that can be audited are classified into these three categories:

SQL_TRACE and TIMED_STATISTICS

If you want to see the SQL statements that were processed during an Oracle session, set both the SQL_TRACE and TIMED_STATISTICS parameters to TRUE. By default, both of these parameters are FALSE. Setting these parameters to TRUE causes Oracle to generate a trace file for each Oracle session, which can then be processed by TKPROF, an Oracle utility. This utility is described in detail in Chapter 32.

ROLLBACK_SEGMENTS

The ROLLBACK_SEGMENTS parameter contains the names of existing rollback segments, if any, that have should be activated during the startup of the Oracle database. See Chapter 26, "Managing Space," for more information on creating rollback segments.

CONTROL_FILES

If you have created a copy of the control file when the database was cold (not running), the only way for Oracle to use the new control file--;the copy you made--;is by referencing it with the CONTROL_FILES initialization parameter. The reason for having multiple control files is to protect against a single point of failure. By having a second control file on another disk drive, you've added some redundancy to the database.

Initialization Parameters That Have No Effect After Database Creation

DB_BLOCK_SIZE and DB_FILES are two Oracle initialization parameters whose values can't be changed after a database has been created.

DB_BLOCK_SIZE

DB_BLOCK_SIZE determines the size of an Oracle block. By default, DB_BLOCK_SIZE is set to 2,048 bytes. Increasing the size of an Oracle block generally reduces the disk blocks that must be read to process a query. When the block is bigger, the header portion of each Oracle block represents a smaller percentage of the block. If you decide to create an Oracle database with a larger block size, remember to decrease the number of block buffers so that the overall size of the SGA is not too large for the available memory on your PC.

DB_FILES

MAXDATAFILES specifies the maximum number of datafiles that can exist in a database. It is specified in the CREATE DATABASE statement that creates an Oracle database. (See the online Oracle7 Server SQL Language Reference Manual, which can be accessed via the Oracle7 Documentation icon in the Personal Oracle7 program group.) If MAXDATAFILES isn't specified in the CREATE DATABASE statement, the initialization parameter DB_FILES determines the maximum number of datafiles that can ever exist in the database. By default, DB_FILES is set to 20. When you install the Personal Oracle database, it automatically creates 4 datafiles, which means that you can add only another 16 files to the database. Accordingly, unless you want to re-create the database with a larger number for MAXDATAFILES, be judicious in expanding a tablespace with Database Expander or the ALTER TABLESPACE ADD statement. When you add a datafile to an existing tablespace or create a new tablespace, always add more space than you think you'll need.

Initialization Parameters That Can Be Ignored

A number of initialization parameters have no effect on a Personal Oracle database and can therefore be ignored. These include any parameter whose name begins with the following:

Summary

In this introduction to Oracle internals, you learned the following: