Oracle SQL Material

December 23, 2016 | Author: writesmd | Category: N/A
Share Embed Donate


Short Description

Download Oracle SQL Material...

Description

1

PL-SQL Functions

Comparison Operators Select Operators Single Row Functions for Numbers, Chars and Dates Conversion Functions Miscellaneous Single Row Functions Aggregate Functions Analytical Functions Object Reference Functions Date Format Models Date Prefixes and Suffixes Number Format Models Comparison Operators Table 1-1. Comparison Operators Operator

What it does

=

true if two expressions are equal

!= ^= -=

logically equivalent—true if two expressions are not equal

>

True if left expression is greater than right expression

>=

True if left expression is greater than or equal to right expression

<

True if left expression is less than right expression

10 or emp_cursor%NOTFOUND; DBMS_OUTPUT.PUT_LINE(INITCAP(v_ename)||' ['||v_empno||']'); END LOOP; CLOSE emp_cursor; END; / Records and %ROWTYPE Instead of fetching values into a collection of variables, you could fetch the entire row into a record like so. DECLARE CURSOR emp_cursor IS SELECT empno, ename, sal, job, deptno FROM emp WHERE deptno=30; -- This creates a record named emp_row -- based on the structure of the cursor emp_cur emp_row emp_cursor%ROWTYPE; BEGIN OPEN emp_cursor; LOOP FETCH emp_cursor INTO emp_row; EXIT WHEN emp_cursor%NOTFOUND; DBMS_OUTPUT.PUT_LINE(emp_row.ename||' [' ||emp_row.empno||'] makes '||TO_CHAR(emp_row.sal*12,'$99,990.00')); END LOOP; END; / You can reference the fields of a record using the syntax record_name.field_name. In addition to basing a record on a cursor, you can also define records based on tables like so. DECLARE CURSOR emp_cursor IS SELECT * FROM emp WHERE deptno=30; emp_row emp%ROWTYPE; -- This creates a record named EMP_ROW -- based on the structure of the EMP table BEGIN OPEN emp_cursor; LOOP FETCH emp_cursor INTO emp_row;

25

EXIT WHEN emp_cursor%NOTFOUND; DBMS_OUTPUT.PUT_LINE(emp_row.ename||' ['||emp_row.empno ||'] makes '||TO_CHAR(emp_row.sal*12,'$99,990.00')); END LOOP; END; /

Oracle data types

====== DDL ====== Type ----------------NUMBER FLOAT SMALLINT

Storage ---------16 16 16

Range/Length -------------40 digit floating point 40 digit floating point 40 digit floating point

Comments -------------------

NUMBER(a,b) FLOAT(a,b)

varies varies

a digits, b precision a digits, b precision

DECIMAL

16

40 digit

INTEGER INTEGER(a)

16 varies

40 digits a digits

CHAR(a) VARCHAR(a) VARCHAR2(a)

a varies varies

a=(1-255) 1 - 255 1 - 2000

DATE

8

1/1/4217BC - 12/31/4712AD

precision to minutes

LONG LONG RAW

varies varies

0 - 2 GB 0 - 2 GB

stored inline, obsolete * stored inline, obsolete *

LONG VARCHAR

varies

0 - 2 GB

stored inline, obsolete *

26

BLOB CLOB NCLOB

varies varies varies

0 - 4 GB 0 - 4 GB 0 - 4 GB

stored separate from table stored separate from table stored separate from table

BFILE

??

??

pointer to O/S file

ROWID

8

n/a

row identifier within block

* Long datatypes are discouraged in Oracle 8. Note that are long and blob datatypes are incompatible. ====== PL-SQL data types (differences) ====== Type Storage Range/Length Comments ----------------- ---------- -------------- ---------------------------NUMERIC VARCHAR VARCHAR2 BLOB CLOB NCLOB

must be read in 32k chunks

Creating a table PCTFREE = Amount of space to leave in block during insert operations. Allows room for records to grow within the same area. PCUSED = The threshold at which the block is placed back on the free block list. INITIAL/NEXT = The initial disk allocated, and the next extent size. LOGGING = Indicates whether operations are written to the redo logs. CREATE TABLE EMPLOYEE ( EMP_ID NUMBER(8), LNAME VARCHAR2(30), FNAME VARCHAR2(15), HIRE_DT DATE, SALARY NUMBER(8,2) ) PCTFREE 20 PCTUSED 50 STORAGE ( INITIAL 200K NEXT 200K PCTINCREASE 0 MAXEXTENTS 50 ) TABLESPACE ts01 LOGGING ;

/* Free table unallocated table blocks */ ALTER TABLE COMPANY DEALLOCATE UNUSED ;

27

Creating indexes

CREATE UNIQUE INDEX EMP_IDX ON EMPLOYEE (EMP_ID) ; /* index create - table has sorted data */ CREATE UNIQUE INDEX IDX_INVOICE_ITEMS ON INVOICE_ITEMS (INVOICE_ID,YEAR,FREQ_CODE,FREQ_NUMBER,FIELD_NUMBER,RECORD_SEQ) TABLESPACE TS_07 NOLOGGING NOSORT ; /* create index - constraint */ ALTER TABLE INVOICE_FORMAT ADD CONSTRAINT PK_INVOICE_FORMAT PRIMARY KEY(INVOICE_ID) USING INDEX TABLESPACE PROD_IDX_01;

Creating constraints

/* primary key constraint */ ALTER TABLE EMPLOYEE ( CONSTRAINT EMP_PK PRIMARY KEY (EMP_ID) ); ALTER TABLE REPORT_FORMAT ADD CONSTRAINT PK_REPORT_FORMAT PRIMARY KEY(REPORT_ID) USING INDEX TABLESPACE PROD_IDX_01; /* foreign key constraint */ ALTER TABLE EMPLOYEE ADD ( CONSTRAINT EMP_LOC_ASSIGN_FK FOREIGN KEY (EMP_ID, LOC_CD) REFERENCES LOC_REGISTRY ( EMP_ID, LOC_CD) );

Creating and using a sequence

/* create a sequence for employee ids */

28

CREATE SEQUENCE EMP_ID_SEQ INCREMENT BY 1 NOMINVALUE NOMAXVALUE NOCYCLE CACHE 20 NOORDER ; / * use the next emp id, and increment the sequence */ INSERT INTO EMPLOYEE(EMP_ID, LNAME, FNAME) VALUES (EMP_ID_SEQ.NEXTVAL, 'SMITH', 'JIM') ; /* get the current value of the sequence */ INSERT INTO EMPLOYEE(EMP_ID, LNAME, FNAME) VALUES (EMP_ID_SEQ.CURRVAL, 'SMITH', 'JIM') ;

Creating triggers The example below illustrates versioning of the EMP_RESUME table, which contains a blob field. CREATE OR REPLACE TRIGGER EMP_RES_INS_TR AFTER INSERT ON EMP_RES FOR EACH ROW DECLARE VER1 NUMBER ; EBLOB BLOB ; VBLOB BLOB ; BEGIN EBLOB := EMPTY_BLOB(); SELECT (COUNT(*) + 1) INTO VER1 FROM VEMP_RES WHERE EMP_ID =:NEW.EMP_ID ; VBLOB := :NEW.RESUME ; INSERT INTO VEMP_RES ( EMP_ID, DOC_URL, A_USERID, D_MODIFIED, VER_NO, RESUME) VALUES ( :NEW.EMP_ID, :NEW.DOC_URL, USER, SYSDATE, VER1, EBLOB ) ; SELECT RESUME INTO EBLOB FROM VEMP_RES WHERE EMP_ID =:NEW.EMP_ID AND VER_NO = VER1

29

FOR UPDATE ; UPDATE VEMP_RES SET RESUME = VBLOB WHERE EMP_ID =:NEW.EMP_ID AND VER_NO = VER1 ; END;

Renaming a table

RENAME COMPANY TO CORPORATION ;

Synonyms and Database Links

-- Synonym Creation GRANT SELECT ON USER5.COMPANY TO USER6 ; CREATE SYNONYM USER6.COMPANY5 FOR USER5.COMPANY ;

-- Database Link CREATE DATABASE LINK ARCHIVE_DATA CONNECT TO USER5 IDENTIFIED BY TIGER USING 'SERVER5' ; /* user within this system can now reference tables using ARCHIVE_DATA.tablename */

Changing a column's type ALTER TABLE CORPORATION MODIFY (COMPANY_NM VARCHAR2(100)); Moving a table ALTER TABLE COMPANY MOVE STORAGE ( INITIAL 200K NEXT 200K PCTINCREASE 0 MAXEXTENTS 50 ) TABLESPACE TS_01 ; Using SQL-Plus

30

SQL-Plus is a query / command line utility which has some powerful formatting capabilities. Getting Started ; Command line terminator / Execute the current batch of commands SET SERVEROUTPUT ON Allow messages from PL-SQL to be displayed SHOW ERRORS Show errors from last batch EDIT Run editor, and load buffer CLEAR BUFFER Clear buffer commands & Prompt for value @ Run commands in @filename /**** Examples ****/ /* prompt for process id, and kill */ alter system kill session '&Victim' /

Creating a stored procedure Below is a simple stored procedure which deletes an invoice. Note: - variable declaration placement - the syntax for comments /* --- */ - ALL select statements must have an into statement for the result set. Oracle stored procedures must use "out" variables to return results to client programs. - the declaration of INV_ID1 uses the column def as a prototype CREATE OR REPLACE PROCEDURE PROC_DELETE_INVOICE ( USERID1 VARCHAR2, INV_ID1 INVOICE.INV_ID%TYPE ) AS INV_COUNT NUMBER ; BEGIN INV_COUNT := 0; /* check if invoice exists */ SELECT COUNT(*) INTO INV_COUNT FROM INVOICE WHERE INV_ID = INV_ID1 ; IF INV_COUNT > 0 THEN DELETE FROM INVOICE WHERE INV_ID = INV_ID1 ; COMMIT ; END IF ; END ;

Displaying output

31

All SELECT statements in PL-SQL must have an INTO clause; therefore another method is needed to display output to the console. DBMS_OUTPUT.PUT_LINE('TEST OUTPUT'); salary := 24000; dbms_output.put_line(salary);

Output variables Output variables are used to return data to another procedure, or to an external application which has invoked the stored procedure. /* sample procedure header using output variables */ TYPE INV_ARRAY IS TABLE OF NUMBER(8) INDEX BY BINARY_INTEGER ; CREATE OR REPLACE PROCEDURE PROC_GET_INV_NOS ( USERID1 IN VARCHAR2, INV_IDS OUT INV_ARRAY) AS ... Arrays and structures Arrays and structures are implemented thought the use of "tables" and "records" in PL-SQL. /* EXAMPLE OF A SIMPLE RECORD TYPE */ TYPE INVOICE_REC_TYPE IS RECORD (INV_ID INVOICE.INV_ID%TYPE, INV_DT INVOICE.INV_DT%TYPE ) ; /* ARRAY DECLARATION */ TYPE NAME_TABLE_TYPE IS TABLE OF VARCHAR2(20) INDEX BY BINARY_INTEGER ; NAME_TABLE

NAME_TABLE_TYPE ;

/* ARRAY SUBSCRIPTING */ I := I + 1; NAME_TABLE(I) := 'JSMITH'; Conditionals

32

Sample formats of conditional branching are given below: IF THEN ; IF THEN ; END IF; /* sample statement, note the pipes for concatenation */ IF (COUNT1 = 0) AND (COUNT2 > 0) THEN RETMSG := 'Security attributes have not been assigned, ' || 'you are restricted.'; ELSE RETMSG := 'You are OK'; END IF; Looping WHILE (I < 10) LOOP /* ... SOME CMDS ... */ I = I + 1; END LOOP;

Cursors The first example depicts dbase-style row processing ; the second a more traditional "fetch" approach. PROCEDURE PROC_SCAN_INVOICES (EXPIRE_DT IN DATE) IS CURSOR INVOICE_CUR IS SELECT INV_ID, INV_DT FROM INVOICE ; TYPE INVOICE_REC_TYPE IS RECORD (INV_ID INVOICE.INV_ID%TYPE, INV_DT INVOICE.INV_DT%TYPE ) ; INVOICE_REC

INVOICE_REC_TYPE ;

BEGIN FOR INVOICE_REC1 IN INVOICE_CUR LOOP IF INVOICE_REC.INV_DT < EXPIRE_DT THEN DELETE FROM INVOICE WHERE INV_ID = INV_REC.INV_ID ; DBMS_OUTPUT.PUT_LINE('INVOICE DELETETED:'); DBMS_OUTPUT.PUT_LINE(INV_REC.INV_ID); END

33

END LOOP; END;

/* ======================================= */ CREATE OR REPLACE PROCEDURE PROC_DOCEXPIRE_RPT ( RPT_BODY OUT LONG RAW ) IS RPT_LINE VARCHAR2(1900); RPT_PART VARCHAR2(1900); RPT_LEAD VARCHAR2(200); GLIB_ID1 NUMBER ; GLIB_ID2 VARCHAR(12); ORIG_LOC_CD1 VARCHAR2(12); AUTHOR_ID1 VARCHAR2(30); CONTRIBUTORS1 VARCHAR2(80); TOPIC1 VARCHAR2(80); NBR_ACCESS1 NUMBER ; NBR_ACCESS2 VARCHAR2(12); TOT_EXPIRED1 NUMBER ; TOT_EXPIRED2 VARCHAR2(12); COUNT1 NUMBER ; RPT_BODY_PART LONG ; CURSOR CUR1 IS SELECT GLIB_ID, ORIG_LOC_CD, AUTHOR_ID, CONTRIBUTORS, TOPIC, NBR_ACCESS FROM GEN_DOC WHERE EXPIRE_DT < (SYSDATE + 30) ORDER BY ORIG_LOC_CD, GLIB_ID ; BEGIN SELECT COUNT(*) INTO TOT_EXPIRED1 FROM GEN_DOC WHERE STAT_CD='90'; TOT_EXPIRED2 := TO_CHAR(TOT_EXPIRED1); RPT_LEAD := 'TOTAL EXPIRED DOCUMENT COUNT TO DATE: ... ' || TOT_EXPIRED2 || '' ; RPT_LINE := '' || 'ABC Corporation' || 'Gen Doc System - Documents Expiring Within 30 Days' || RPT_LEAD ;

34

COUNT1 := 0; OPEN CUR1; RPT_LINE := RPT_LINE || '' || 'No. Accesses' || 'Document #' || 'Topic' || 'Author' ; RPT_BODY := UTL_RAW.CAST_TO_RAW(RPT_LINE); RPT_LINE := ''; LOOP COUNT1 := COUNT1 + 1; EXIT WHEN (COUNT1 > 500); EXIT WHEN (UTL_RAW.LENGTH(RPT_BODY) > 32000); FETCH CUR1 INTO GLIB_ID1, ORIG_LOC_CD1, AUTHOR_ID1, CONTRIBUTORS1, TOPIC1, NBR_ACCESS1 ; EXIT WHEN CUR1%NOTFOUND ; RPT_PART := ''; NBR_ACCESS2 := TO_CHAR(NBR_ACCESS1); RPT_PART := CONCAT(RPT_PART,NBR_ACCESS2); RPT_PART := CONCAT(RPT_PART,''); GLIB_ID2 := TO_CHAR(GLIB_ID1); RPT_PART := RPT_PART || ORIG_LOC_CD1 || '-' || GLIB_ID2 || '' || TOPIC1 || '' || AUTHOR_ID1 || '' ; RPT_LINE := CONCAT(RPT_LINE, RPT_PART); RPT_BODY_PART := UTL_RAW.CAST_TO_RAW(RPT_LINE); RPT_BODY := UTL_RAW.CONCAT(RPT_BODY,RPT_BODY_PART); -- RPT_BODY := RPT_BODY || RPT_LINE; RPT_LINE := ''; END LOOP; CLOSE CUR1 ; RPT_LINE := ''; RPT_BODY_PART := UTL_RAW.CAST_TO_RAW(RPT_LINE); RPT_BODY := UTL_RAW.CONCAT(RPT_BODY, RPT_BODY_PART); EXCEPTION WHEN OTHERS THEN BEGIN DBMS_OUTPUT.PUT_LINE('ERROR: PROC_DOCSTAT_RPT'); GLIB_ID1 := UTL_RAW.LENGTH(RPT_BODY); DBMS_OUTPUT.PUT_LINE(GLIB_ID1); END; END;

35

Packages A package is a construct which bounds related procedures and functions together. Variables declared in the declaration section of a package can be shared among the procedures/functions in the body of the package. /* package */ CREATE OR REPLACE PACKAGE INVPACK IS FUNCTION COUNTINV (SALESREP IN VARCHAR2) RETURN INTEGER; PROCEDURE PURGEINV (INV_ID IN INTEGER) ; END INVPACK; /* package body */ CREATE OR REPLACE PACKAGE BODY INVPACK IS COUNT1 NUMBER; FUNCTION COUNTINV (SALESREP IN VARCHAR2) RETURN INTEGER IS BEGIN SELECT COUNT(*) INTO COUNT1 FROM INVOICE WHERE SALES_REP_ID = SALESREP ; RETURN COUNT1 ; END COUNTINV; PROCEDURE PURGEINV (INV_ID1 IN INTEGER) IS BEGIN DELETE FROM INVOICE WHERE INV_ID = INV_ID1

36

END PURGEINV; /* initialization section for package */ BEGIN COUNT1 := 0 ; END INVPACK;

Exception Handling The following block could appear at the end of a stored procedure: EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('End of data !!); WHEN OTHERS THEN BEGIN DBMS_OUTPUT.PUT_LINE('OTHER CONDITION OCCURRED !'); END; Using Blobs Blob variables require special handling in PL-SQL. When reading from a file to a blob, only one statement is required. When reading from a blob field to a PL-SQL variable, only 32k blocks can be processed, thus necessitating a loop construct. /*---------------------------------------*/ /* Read a blob from a file, and write */ /* it to the database. */ /*---------------------------------------*/ set serveroutput on size 500000 ; truncate table image_test ; create or replace directory image_dir as '/apps/temp/images' ; create or replace procedure proc_imp_jpg (fname1 in varchar2, image_id1 in numeric) is file1 bfile ; lblob blob ; len int ; e_blob blob ; begin file1 := bfilename('IMAGE_DIR',fname1); e_blob := empty_blob(); insert into image_test (image_id, image_data) values (image_id1, e_blob )

37

returning image_data into lblob ; dbms_lob.fileopen(file1); len := dbms_lob.getlength(file1) ; dbms_lob.loadfromfile(lblob,file1,len); dbms_lob.filecloseall(); commit; exception when others then begin dbms_output.put_line(sqlerrm); dbms_lob.filecloseall(); commit; end; end ; / call proc_imp_jpg('jada.jpg',101) / /*-----------------------------*/ /* determine the length of */ /* a blob field */ /* by reading it */ /*-----------------------------*/ CREATE OR REPLACE PROCEDURE PROC_BLOB_LENGTH (PART_ID1 NUMBER) IS SRC_LOB BLOB; BUFFER RAW(100); AMT BINARY_INTEGER := 100; POS INTEGER := 1; COUNTER INTEGER :=0; BEGIN SELECT PART_PHOTO INTO SCR_LOB FROM PARTS WHERE PART_ID=PART_ID1 ; IF (SRC_LOB IS NOT NULL) THEN LOOP DBMS_LOB.READ (SRC_LOB, AMT, POS, BUFFER); POS := POS + AMT; COUNTER:=COUNTER+1; END LOOP; ELSE DBMS_OUTPUT.PUT_LINE('** Source is null'); END IF; EXCEPTION WHEN NO_DATA_FOUND THEN

38

DBMS_OUTPUT.PUT_LINE('End of data, total bytes:'); DBMS_OUTPUT.PUT_LINE(POS); END; /* ============ Other blob length examples ====== */ /**** Note ! These functions may return null, if the column is null ... an Oracle bug */ X := UTL_RAW.LENGTH(RPT_BODY) ; Y := DBMS_LOB.GETLENGTH(LONG_RAW_COL); Using the Context cartridge Managing Context is an arduous task. The best approach is to use the command line utility as much as possible. Below is a code sample which creates a policy (a policy is a construct which informs context which column on what table to scan during a search operation). The next example illustrates how to perform a search, and stored the result keys in a table. /* create a policy, on the emp_resume table */ ctx_svc.clear_all_errors; dbms_output.put_line('Creating Policy ...'); ctx_ddl.create_policy( POLICY_NAME => 'EMP_RES_POLICY', COLSPEC => 'EMP_RES.RESUME', SOURCE_POLICY => 'CTXSYS.DEFAULT_POLICY', DESCRIPTION => 'EMP Policy', TEXTKEY => 'EMP_ID', DSTORE_PREF => 'CTXSYS.DEFAULT_DIRECT_DATASTORE', FILTER_PREF => 'CTXSYS.HTML_FILTER', LEXER_PREF => 'CTXSYS.DEFAULT_LEXER' ); dbms_output.put_line('Indexing Policy ...'); ctx_ddl.create_index('EMP_POLICY'); /* Run a Context query, place the result key values in a table */ /* first, this table needs to be created */ CREATE TABLE EMP_CTX_RESULTS( TEXTKEY VARCHAR2(64), TEXTKEY2 VARCHAR2(64), SCORE NUMBER, CONID NUMBER ); /* this code can go in a stored proc */ POLICY1 := 'EMP_POLICY'; TABLE1 := 'EMP_CTX_RESULTS'; ID1 := 100 ; QUERY1 := 'COBOL|FORTRAN'; CTX_QUERY.CONTAINS(POLICY1, QUERY1, TABLE1, 1, ID1); /* the table will contain records with a CONID of 100 */ /* ... you can use ampersand or pipe as the conditional */

39

Sleep and Wait Sometimes it is necessary to delay the execution of commands, for debugging, or batch runs. /* Sleep 60 seconds */ execute dbms_lock.sleep(60); /* Sleep one hour */ execute dbms_lock.sleep(3600); Date Manipulation /* display current time */ select to_char(sysdate, 'Dy DD-Mon-YYYY HH24:MI:SS') as "SYSDATE" from dual; /* insert specific date/time into table */ insert into game_schedule ( sched_id, location, game_date ) values(2982, 'Chicago', to_date('2001/10/31:03:00:00PM', 'yyyy/mm/dd:hh:mi:ssam')) ;

40

Version information

SELECT * FROM product_component_version ;

List free and used space in database SELECT sum(bytes)/1024 "free space in KB" FROM dba_free_space; SELECT sum(bytes)/1024 "used space in KB" FROM dba_segments;

List session information SELECT * FROM V$SESSION ;

List names and default storage parameters for all tablespaces SELECT TABLESPACE_NAME, INITIAL_EXTENT, NEXT_EXTENT, MAX_EXTENTS, PCT_INCREASE, MIN_EXTLEN FROM DBA_TABLESPACES;

Tablespace types, and availability of data files SELECT TABLESPACE_NAME, CONTENTS, STATUS FROM DBA_TABLESPACES;

List information about tablespace to which datafiles belong SELECT FILE_NAME,TABLESPACE_NAME,BYTES,AUTOEXTENSIBLE, MAXBYTES,INCREMENT_BY FROM DBA_DATA_FILES;

List data file information

41

SELECT FILE#,T1.NAME,STATUS,ENABLED,BYTES,CREATE_BYTES,T2.NAME FROM V$DATAFILE T1, V$TABLESPACE T2 WHERE T1.TS# = T2.TS# ;

List tablespace fragmentation information SELECT tablespace_name,COUNT(*) AS fragments, SUM(bytes) AS total, MAX(bytes) AS largest FROM dba_free_space GROUP BY tablespace_name;

Check the current number of extents and blocks allocated to a segment SELECT SEGMENT_NAME,TABLESPACE_NAME,EXTENTS,BLOCKS FROM DBA_SEGMENTS;

Check the extents for a given segment SELECT TABLESPACE_NAME, COUNT(*), MAX(BLOCKS), SUM(BLOCKS) FROM DBA_FREE_SPACE GROUP BY TABLESPACE_NUMBER ;

Extent information SELECT segment_name, extent_id, blocks, bytes FROM dba_extents WHERE segment_name = TNAME ;

Extent information for a table SELECT segment_name, extent_id, blocks, bytes FROM dba_extents WHERE segment_name = TNAME ;

List segments with fewer than 5 extents remaining SELECT segment_name,segment_type, max_extents, extents FROM dba_segments WHERE extents+5 > max_extents AND segment_type'CACHE';

42

List segments reaching extent limits SELECT s.segment_name,s.segment_type,s.tablespace_name,s.next_extent FROM dba_segments s WHERE NOT EXISTS (SELECT 1 FROM dba_free_space f WHERE s.tablespace_name=f.tablespace_name HAVING max(f.bytes) > s.next_extent); List table blocks, empty blocks, extent count, and chain block count SELECT blocks as BLOCKS_USED, empty_blocks FROM dba_tables WHERE table_name=TNAME; SELECT chain_cnt AS CHAINED_BLOCKS FROM dba_tables WHERE table_name=TNAME; SELECT COUNT(*) AS EXTENT_COUNT FROM dba_extents WHERE segment_name=TNAME; Information about all rollback segments in the database SELECT SEGMENT_NAME,TABLESPACE_NAME,OWNER,STATUS FROM DBA_ROLLBACK_SEGS; /* General Rollback Segment Information */ SELECT t1.name, t2.extents, t2.rssize, t2.optsize, t2.hwmsize, t2.xacts, t2.status FROM v$rollname t1, v$rollstat t2 WHERE t2.usn = t1.usn ; /* Rollback Segment Information - Active Sessions */ select t2.username, t1.xidusn, t1.ubafil, t1.ubablk, t2.used_ublk from v$session t2, v$transaction t1 where t2.saddr = t1.ses_addr

Statistics of the rollback segments currently used by instance SELECT T1.NAME, T2.EXTENTS, T2.RSSIZE, T2.OPTSIZE, T2.HWMSIZE, T2.XACTS, T2.STATUS FROM V$ROLLNAME T1, V$ROLLSTAT T2 WHERE T1.USN = T2.USN AND T1.NAME LIKE '%RBS%';

43

List sessions with active transactions SELECT s.sid, s.serial# FROM v$session s WHERE s.saddr in (SELECT t.ses_addr FROM V$transaction t, dba_rollback_segs r WHERE t.xidusn=r.segment_id AND r.tablespace_name='RBS'); Active sorts in instance SELECT T1.USERNAME, T2.TABLESPACE, T2.CONTENTS, T2.EXTENTS, T2.BLOCKS FROM V$SESSION T1, V$SORT_USAGE T2 WHERE T1.SADDR = T2.SESSION_ADDR ; Index & constraint information SELECT index_name,table_name,uniqueness FROM dba_indexes WHERE index_name in (SELECT constraint_name FROM dba_constraints WHERE table_name = TNAME AND constraint_type in ('P','U')) ; Updating statistics for a table or schema EXEC DBMS_STATS.GATHER_TABLE_STATS('SCHEMA1','COMPANY'); EXEC DBMS_STATS.GATHER_SCHEMA_STATS('SCHEMA1'); ANALYZE TABLE COMPANY COMPUTE STATISTICS ; List tables and synonyms

set pagesize 0; select 'TABLE:',table_name,'current' from user_tables union select 'SYNONYM:',synonym_name,table_owner from user_synonyms order by 1,2 ;

Constraint columns SELECT constraint_name,table_name, column_name FROM dba_cons_columns WHERE table_name = TNAME ORDER BY table_name, constraint_name, position END IF;

44

Constraint listing SELECT constraint_name, table_name, constraint_type, validated, status FROM dba_constraints; Indexed column listing select b.uniqueness, a.index_name, a.table_name, a.column_name from user_ind_columns a, user_indexes b where a.index_name=b.index_name order by a.table_name, a.index_name, a.column_position;

Trigger listing SELECT trigger_name, status FROM dba_triggers ;

Tuning: library cache Glossary: pins = # of time an item in the library cache was executed reloads = # of library cache misses on execution Goal: get hitratio to be less than 1 Tuning parm: adjust SHARED_POOL_SIZE in the initxx.ora file, increasing by small increments SELECT SUM(PINS) EXECS, SUM(RELOADS)MISSES, SUM(RELOADS)/SUM(PINS) HITRATIO FROM V$LIBRARYCACHE ;

Tuning: data dictionary cache Glossary: gets = # of requests for the item getmisses = # of requests for items in cache which missed Goal: get rcratio to be less than 1 Tuning parm: adjust SHARED_POOL_SIZE in the initxx.ora file, increasing by small increments SELECT SUM(GETS) HITS, SUM(GETMISSES) LIBMISS, SUM(GETMISSES)/SUM(GETS) RCRATIO FROM V$ROWCACHE ;

Tuning: buffer cache

45

Calculation: buffer cache hit ratio = 1 - (phy reads/(db_block_gets + consistent_gets)) Goal: get hit ratio in the range 85 - 90% Tuning parm: adjust DB_BLOCK_BUFFERS in the initxx.ora file, increasing by small increments SELECT NAME, VALUE FROM V$SYSSTAT WHERE NAME IN ('DB BLOCK GETS','CONSISTENT GETS','PHYSICAL READS'); Tuning: sorts Goal: Increase number of memory sorts vs disk sorts Tuning parm: adjust SORT_AREA_SIZE in the initxx.ora file, increasing by small increments SELECT NAME, VALUE FROM V$SYSTAT WHERE NAME LIKE '%SORT%';

Tuning: dynamic extension An informational query. SELECT NAME, VALUE FROM V$SYSSTAT WHERE NAME='RECURSIVE CALLS' ;

Tuning: rollback segments Goal: Try to avoid increasing 'undo header' counts Tuning method: Create more rollback segments, try to reduce counts SELECT CLASS,COUNT FROM V$WAITSTAT WHERE CLASS LIKE '%UNDO%' ; Tuning: physical file placement Informational in checking relative usages of the physical data files. SELECT NAME, PHYRDS,PHYWRTS FROM V$DATAFILE DF, V$FILESTAT FS WHERE DF.FILE#=FS.FILE# ;

Killing Sessions Runaway processes can be killed on the UNIX side, or within server manager.

46

/* Kill a session, specified by the returned sess-id / serial number */ SELECT sid, serial#, username from v$session ALTER SYSTEM KILL SESSION 'sessid,ser#'

Archive Log Mode Status

/* Status of Archive Log Subsystem */ ARCHIVE LOG LIST /* log mode of databases */ SELECT name, log_mode FROM v$database; /* log mode of instance */ SELECT archiver FROM v$instance;

Recovering an Instance An incomplete recovery is the only option if backups are run periodically on a cold instance. Complete recovery is possible if archive logging is enabled, and backups are run while the database is active. /* diagnose data file problem */ select * from v$recover_file ; /* diagnose data file problem, by displaying tablespace info */ select file_id, file_name, tablespace_name, status from dba_data_files ; /* find archive log files */ select * from v$recovery_log ; /* incomplete recovery #1 */ svrmgrl> shutdown abort [[ In Unix copy data files from backup area to data directory(s). ]] svrmgrl> connect; svrmgrl> startup; /* incomplete recovery #2 */ svrmgrl> shutdown abort; svrmgrl> connect;

47

svrmgrl> startup mount; svrmgrl> alter database rename file '/data2/ts05.dbf' to '/backups/ts05.dbf' svrmgrl> alter database open; /* incomplete recovery #3, for user error (i.e. drop table ) */ Note: archive logs must exist in LOG_ARCHIVE_DEST svrmgrl> shutdown abort [[ backup all files ]] [[ restore required data file(s), using OS commands ]] svrmgrl> svrmgrl> svrmgrl> svrmgrl>

connect; startup mount; recover database until time '2002-03-04:15:00:00' ; alter database open resetlogs;

/* complete recovery #1, for major recovery operations, closed instance */ Note: archive logs must exist in LOG_ARCHIVE_DEST svrmgrl> shutdown abort [[ backup all files ]] svrmgrl> svrmgrl> svrmgrl> < or > svrmgrl> svrmgrl>

connect; startup mount; recover database ; recover datafile '/data4/ts03.dbf' startup open;

/* complete recovery #2, for major/minor recovery operations, open instance */ Note: archive logs must exist in LOG_ARCHIVE_DEST svrmgrl> shutdown abort [[ backup all files ]] [[ restore corrupted data files, using OS commands ]] svrmgrl> svrmgrl> svrmgrl> svrmgrl> < or > svrmgrl> svrmgrl>

connect; startup mount; set autorecovery on ; recover tablespace ts03 ; recover datafile 4 ; startup open;

List log file information These queries list the status / locations of the redo log files. select group#, member, status from v$logfile ;

48

select group#,thread#,archived,status from v$log ;

A Simple Monitoring Tool This tool loops a specified number of times, displaying memory usage along with user process counts for a specific username. --================================================= --- proc_ora_monitor --- parm1: username to count -- parm2: number of loops, 5 sec duration ----================================================= set serveroutput on ; create or replace procedure proc_ora_monitor ( user1 in varchar, reps1 in integer ) is i number ; usercount1 number ; memory1 number ; date1 varchar(20) ; msg varchar(99) ; begin i := 0 ; while ( i < reps1 ) loop msg := '=> ' || to_char(SYSDATE, 'HH:MM:SS PM'); select count(1) into usercount1 from sys.v_$session where username = user1 ; msg := msg || ', ' || user1 || ': ' || usercount1 ; select round(sum(bytes)/1024/1024 ,2) into memory1 from sys.v_$sgastat where pool = 'shared pool' and name = 'free memory' ; msg := msg || ', free mb = ' || memory1 ; select round(sum(bytes)/1024/1024 ,2) into memory1 from sys.v_$sgastat

49

where pool = 'shared pool' and name = 'processes' ; msg := msg || ', processes mb = ' || memory1 ; dbms_output.put_line(msg) ; dbms_lock.sleep(5) ; i := i + 1 ; end loop ; end; / show errors ; execute proc_ora_monitor('SILVERUSER',2) ; exit

Connection Errors ------------------------------------------------------ORA-01034: ORACLE not available ------------------------------------------------------TNS-12564: TNS:connection refused ------------------------------------------------------TNS-12530: Unable to start a dedicated server process

50

------------------------------------------------------Connection errors can crop up out of nowhere ; the error message tend to be vague, and not useful at all. Here's a plan of attack which will solve many connection issues. Try each step, and proceed if the problem persists. 1) Check your environment ; verify the variables depicted below are set. ( NT: check the registry ) The example below details a Solaris/CSH environment. Note the TWO_TASK setting ... setenv ORACLE_BASE /apps/oracle setenv ORACLE_HOME ${ORACLE_BASE} setenv ORACLE_SID db22 setenv TWO_TASK $ORACLE_SID setenv LD_LIBRARY_PATH $ORACLE_HOME/lib:/usr/lib/X11 setenv ORACLE_PATH $ORACLE_HOME/bin:/usr/bin:/usr/local/bin setenv ORA_CLIENT_LIB shared set path = ($ORACLE_HOME/bin /bin /usr/bin /usr/local/bin /sbin /usr/sbin /usr/bin/X11 .) 2) Try to ping the instance: tnsping db22 If there's an error, check $ORACLE_HOME/network/admin/tnsnames.ora 3) Restart the TNS service. Solaris: 1) kill the process, running the tnslsnr binary 2) nohup $ORACLE_HOME/bin/tnslsnr start & NT: 1) restart the service, in the control panel 4) SQL-Plus / ServerMgr Try using this syntax:

sqlplus user/password@instance

5) Solaris, shell change Try switching the oracle user to the Bourne or Csh shell ; make a script for SQL-Plus as follow: #!/usr/bin/csh setenv ORACLE_BASE /apps/oracle setenv ORACLE_HOME ${ORACLE_BASE} setenv ORACLE_SID db22 setenv LD_LIBRARY_PATH $ORACLE_HOME/lib:/usr/lib/X11 setenv ORACLE_PATH $ORACLE_HOME/bin:/usr/bin:/usr/local/bin setenv ORA_CLIENT_LIB shared setenv TWO_TASK $ORACLE_SID set path = ($ORACLE_HOME/bin /bin /usr/bin /usr/local/bin /sbin /usr/sbin /usr/bin/X11 .)

51

sqlplus $1 $2 $3 # OR #sqlplus $1@$ORACLE_SID Also verify the oracle user owns the oracle directory tree.

6) Check the pfile, verify the settings detailed below. For this example, the machine should have at least 512mb of memory, to handle the OS and other processes. # 100 MB shared pool memory shared_pool_size = 104857600 # 65 processes need 130 MB of additional memory processes = 65 sessions = 65 Solaris: check the "shared memory" and "semaphores" settings also, in the /etc/system file.

7) Look at sqlnet.log ; also check the alert log in $ORACLE_HOME/admin/$ORACLE_SID/bdump

8) Verify the Oracle version, SQLNet version, and patched OS are all compatible.

9) If the problem is still a mystery, the server may need to be restarted.

Explain Plan: syntax Below is sample syntax for explain plan ( getting output from the optimizer ) delete from plan_table where statement_id = '9999'; commit;

52

COL operation FORMAT A30 COL options FORMAT A15 COL object_name FORMAT A20 /* ------ Your SQL here ------*/ EXPLAIN PLAN set statement_id = '9999' for select count(1) from asia_monthly_pricing_data where order_id > 5000 / /*----------------------------*/

select operation, options, object_name from plan_table where statement_id = '9999' start with id = 0 connect by prior id=parent_id and prior statement_id = statement_id; exit /

Oracle 9i Articles • • • •

Oracle9i Oracle9i Oracle9i Oracle9i

Database: New Features For Administrators OCP Exam Articles Database Release 2: New Features Installation Articles XML Articles

53

• • •

Oracle9i Web Articles Oracle9i Miscellaneous Articles Oracle9i Application Server Articles

Oracle9i Database: New Features For Administrators OCP Exam Articles Oracle9i: New Features For Administrators Exam Tips - Some tips on what to expect when upgrading your OCP to Oracle9i. ANSI ISO SQL Support In Oracle9i - Check out the new SQL enhancements to bring Oracle in line with the ANSI/ISO SQL: 1999 standards. Automatic Segment Free Space Management - Reduce segment header contention and wasted space within blocks by switching from using FreeLists to Automatic Segment Free Space Management. Automatic Undo Management - Replace you existing rollback segments with self-tuning undo segments. Bitmap Join Indexes - Increase the performance and reduce the size of your data warehouse. Character Semantics And Globalization - Prevent storage problems associated with mutlibyte character sets by using character semantics when defining table columns. Data Guard - Oracle9i Data Guard is the new name for Oracle8i Standby Database incorporating a large number of new features. This article discusses those relevant to the Oracle9i Database: New Features For Administrators OCP exam. Export And Import Enhancements In Oracle9i - See what new functionality has been incorporated into the Export and Import utilities in Oracle9i. Flashback Query - Get a consistent view of the your data at a previous point in time. High Availability Enhancements in Oracle9i - Reduce downtime for users by using the new high availability features of Oracle9i. Index Organized Table (IOT) Enhancements in Oracle9i - Better support for secondary indexes and improved online maintenance make IOTs nearly as flexible as heap tables. Index Skip Scanning - See how Oracle9i uses composite indexes even when the leading edge is not referenced. LOB Enhancements In Oracle9i - Kickstart the conversion from LONG and RAW columns to CLOB and BLOB columns. Logminer Enhancements In Oracle9i - A summary of the new features introduced in Oracle9i. Memory Management In Oracle9i - See how easy memory management has become in Oracle9i. Metadata API - Extract DDL or XML definitions of all database objects using this simple API. Multiple Block Sizes - Improve efficiency by having multiple block sizes that relate more closely to the operations that are being performed. Oracle Managed Files - Let Oracle manage operating system level file placement, naming and cleanup. Partitioning Enhancements In Oracle9i - Check out the additions and enhancements to partitioning in Oracle9i.

54

Performance Enhancements In Oracle9i - Read about some of the new performance features in Oracle9i. Persistent Initialization Parameters - Make database parameter changes persist between shutdowns. Real Application Clusters - A brief introduction to the Oracle9i replacement for Oracle Parallel Server. Recovery Enhancements In Oracle9i - Reduce unplanned downtime by using the new crash, instance and media recovery features of Oracle9i. Recovery Manager (RMAN) Enhancements In Oracle9i - Use the latest RMAN features which make backup and recovery quicker and more reliable. Resource Manager Enhancements In Oracle9i - Manage system resources more precisely using the Resource Manager enhancements in Oracle9i. Resumable Space Allocation - Make long running operations suspend rather than abort if they encounter space errors. Scalable Session Management - Learn about the new session management features in Oracle9i. Security Enhancements In Oracle9i - A run through the new security features available in Oracle9i, focusing on those relevant for the Oracle9i Database: New Features For Administrators OCP exam. SQL New Features In Oracle9i - Check out the new SQL features with emphasis on those relevant for the Oracle9i Database: New Features For Administrators OCP exam. Workspace Management In Oracle9i - Allow multiple transactionally consistent environments to exist within one database. Oracle9i Database Release 2: New Features Associative Arrays - Oracle9i Release 2 allows you to index-by string values using this renamed collection. Bulk Binds and Record Processing in Oracle9i Release 2 - Take advantage of bulk binds for performance improvements whilst using record structures. DBNEWID Utility - Change the internal DBID and the database name using this new utility without rebuilding your controlfile. DBMS_XPLAN - Easily format the output of an explain plan with this replacement for the utlxpls.sql script. Export BLOB Contents Using UTL_FILE - Use the new UTL_FILE functionality to write binary data to files. FTP From PL/SQL - A description of two methods for triggering FTP jobs directly from PL/SQL. InterMedia - Import-Export Of Images - Use Oracle interMedia to store and retrieve images without using Java stored procedures. Renaming Columns And Constraints - Oracle9i Release 2 now allows the renaming of columns and constraints. Check out the syntax here. SQL/XML - Oracle9i Release 2 includes functionality to support the emerging SQL/XML standard to simplify XML generation from SQL queries. STATISTICS_LEVEL - Let Oracle9i Release 2 control the collection of statistics and advisories with a single parameter. Streams - Based on Advanced Queuing and LogMinor, Oracle Streams form a distributed messaging

55

technology that can be used for a variety of tasks including messaging, replication and ETL processes. UTL_FILE Enhancements - Oracle9i Release 2 includes some long overdue enhancements including basic file handling and support for NCHAR and RAW data. UTL_FILE - Random Access of Files - Use the UTL_FILE package for random access of files from PL/SQL. XML DB - Store and retrieve XML documents from the Oracle XML DB repository using HTTP, FTP and WebDAV in seconds. XMLSEQUENCE - Use this operator to split multi-value results from XMLTYPE queries into multiple rows.

Oracle9i Installation Articles Oracle9i (9.2.0.4.0) Installation On Fedora Core 1 Linux - A brief guide to installing Oracle9i (9.2.0.4.0) on Fedora Core 1 Linux. Oracle9i (9.2.0.1.0) Installation On RedHat 8.0 Linux - A brief guide to installing Oracle9i (9.2.0.1.0) on RedHat 8.0 Linux.

56

Oracle9i (9.2.0.1.0) Installation On RedHat 9.0 Linux - A brief guide to installing Oracle9i (9.2.0.1.0) on RedHat 9.0 Linux. Oracle9i (9.2.0.4.0) Installation On RedHat Advanced Server 2.1 Linux - A brief guide to installing Oracle9i (9.2.0.4.0) on RedHat Advanced Server 2.1 Linux. Oracle9i (9.2.0.4.0) Installation On RedHat Advanced Server 3.0 Linux - A brief guide to installing Oracle9i (9.2.0.4.0) on RedHat Advanced Server 3.0 Linux. Oracle9i (9.2.0.1.0) Installation On Tru64 5.1b - A brief guide to installing Oracle9i (9.2.0.1.0) on Tru64 5.1b. Oracle9i RAC Installation On Tru64 - A brief guide to installing Oracle9i (9.2.0.4.0) Real Application Clusters (RAC) on Tru64 5.1b. Manual Oracle Uninstall - Having trouble removing all Oracle software using the OUI? Try these methods. Oracle9i XML Articles Load XMLTYPE From File - A simple method to load XMLTYPE data from a file. Parse XML Documents - Explode unstructured XML documents into relational tables using the new integrated XDB packages. XML DB - Store and retrieve XML documents from the Oracle XML DB repository using HTTP, FTP and WebDAV in seconds. SQL/XML - Oracle9i Release 2 includes functionality to support the emerging SQL/XML standard to simplify XML generation from SQL queries. XMLSEQUENCE - Use this operator to split multi-value results from XMLTYPE queries into multiple rows. XMLType Datatype - Store XML documents in tables and query them using SQL. XML Generation In Oracle9i Using DBMS_XMLQuery, DBMS_XMLGen, Sys_XMLGen And Sys_XMLAgg Generate XML and perform XSL transformations with ease using the new XML features of Oracle9i. XML-Over-HTTP - XML-over-HTTP was the precursor to web services allowing easy access to XML via HTTP GETs and POSTs. XSQL Servlet and XSQL Pages - Publish dynamic XML documents through HTTP using the XSQL Servlet utility. Oracle9i Web Articles Consuming Web Services - Access web services directly from PL/SQL using this simple API. Email From PL/SQL In Oracle9i - Email from PL/SQL rather than using external procedures or Java. File Upload and Download Procedures - Upload and download files directly from the database using Database Access Descriptors. FTP From PL/SQL - A description of two methods for triggering FTP jobs directly from PL/SQL. Images from Oracle Over HTTP - Retrieve images directly from the database over HTTP.

57

Java Server Pages - Use Java as a scripting language to interact with the database from web pages. PL/SQL Server Pages - Use PL/SQL as a scripting language to generate web pages directly from the database. PL/SQL Web Toolkit - Generate web pages directly from the database using this simple toolkit. SQL*Plus Web Reports - Generate HTML reports directly from SQL*Plus. Stateless Locking Methods - Learn how to avoid data loss in stateless environments. Oracle9i Miscellaneous Articles Advanced Queuing In Oracle9i - Get to grips with the basics of advanced queuing in Oracle9i. Archivelog Mode On RAC - The differences between resetting the archive log mode on a single node instance and a Real Application Cluster (RAC). CASE Expressions And Statements - Learn how to use CASE expressions in both SQL and PL/SQL. In addition, learn how to use the CASE statement in PL/SQL. Complete Data Audit - A simple and generic solution for auditing before and after snapshots of data. Compressed Tables - Compress whole tables or individual table partitions to reduce disk space requirements. Duplicate a Database Using RMAN - Use RMAN to create a duplicate, or clone, of a database from a recent backup. DBMS_LDAP - Accessing LDAP From PL/SQL - Use the DBMS_LDAP package to query and modify LDAP entries from PL/SQL. DBMS_LIBCACHE - Warm up the library cache of an instance by compiling the SQL and PL/SQL statements from the library cache of another instance. DBMS_PROFILER - Profile the run-time behaviour of PL/SQL code to identify potential bottlenecks. DBMS_TRACE - Trace the run-time behaviour of PL/SQL code to identify potential bottlenecks. Dynamic Binds Using Contexts - Simplify dynamic variable binds within dynamic SQL using contexts. External Tables - Query the contents of flat files as if they were regular tables. Full Text Indexing using Oracle Text - Efficiently query free text and produce document classification applications using Oracle Text. Generating CSV Files - A simple example of using the UTL_FILE package to generate CSV extract files. Heterogeneous Services - Generic Connectivity In Oracle9i - Query non-Oracle datasources using ODBC. Java Native Compilation - Improve the performance of Java procedural code by compiling it to native shared libraries. Mutating Table Exceptions - A simple method to prevent triggers producing mutating table exceptions. Oracle Internet Directory - Use the Oracle Internet Directory to replace local Oracle Net configuration files and Oracle Names Server.

58

Oracle Label Security - Configure row-level security with this out-of-the-box solution. Pipelined Table Functions - Improve performance of ETL processes by pipelining all transformation functions. PL/SQL Native Compilation - Improve the performance of PL/SQL procedural code by compiling it to native shared libraries. RANK, DENSE_RANK, FIRST and LAST Analytic Functions - Simple examples of how to use these analytic functions. Recovery Manager (RMAN) - Explanation of RMANs basic backup, recovery and reporting functionality. Storing Passwords In The Database - Store passwords securely in the database using this simple hashing technique. Transportable Tablespaces - Copy tablespaces to new instances in the time it takes to copy the datafiles. Unregister a Database From RMAN - A step-by-step guide to unregistering unwanted databases from the RMAN catalog. Universal Unique Identifier (UUID) - Reduce data migration and replication issues by replacing sequence generated IDs with UUIDs. Useful Procedures And Functions - Procedures and functions you may have overlooked which can come in useful during development. Oracle9i Application Server Articles Oracle9iAS Backup and Recovery - Simplify backup and recovery of Oracle9i Application Server using this Oracle supplied Perl utility. Oracle9iAS dcmctl Utility - Speed up 9iAS administration by avoiding Enterprise Manager. Oracle9iAS (9.0.3.0.0) Installation On RedHat Advanced Server 2.1 - A brief guide to installing Oracle9iAS (9.0.3.0.0) on RedHat Advanced Server 2.1. Oracle9iAS (9.0.2.0.1) Portal Installation On Tru64 5.1b - A brief guide to installing Oracle9iAS (9.0.2.0.1) Portal on Tru64 5.1b. Oracle9iAS (9.0.2.0.1) Portal Installation On Windows 2000 - A brief guide to installing Oracle9iAS (9.0.2.0.1) Portal on Windows 2000.

SQL*Loader Maximazing SQL*Loader Performance Use Direct Path Loads - The conventional path loader essentially loads the data by using standard insert statements. The direct path loader (direct=true) loads directly into the Oracle data files and creates blocks in Oracle database block format. There are certain cases, however, in which direct path loads

59

cannot be used (clustered tables). To prepare the database for direct path loads, the script $ORACLE_HOME/rdbms/admin/catldr.sql.sql must be executed. Disable Indexes and Constraints. For conventional data loads only, the disabling of indexes and constraints can greatly enhance the performance. Use a Larger Bind Array. For conventional data loads only, larger bind arrays limit the number of calls to the database and increase performance. The size of the bind array is specified using the bindsize parameter. The bind array's size is equivalent to the number of rows it contains (rows=) times the maximum length of each row. Use ROWS=n to Commit Less Frequently. For conventional data loads only, the rows parameter specifies the number of rows per commit. Issuing fewer commits will enhance performance. Use Parallel Loads. Available with direct path data loads only, this option allows multiple SQL*Loader jobs to execute concurrently. $ sqlldr control=first.ctl parallel=true direct=true $ sqlldr control=second.ctl parallel=true direct=true

Use Fixed Width Data. Fixed width data format saves Oracle some processing when parsing the data. The savings can be tremendous. Disable Archiving During Load. While this may not be feasible in certain environments, disabling database archiving can increase performance considerably. Use unrecoverable. The unrecoverable option (unrecoverable load data) disables the writing of the data to the redo logs. This option is available for direct path loads only. Using the table table_with_one_million_rows, the following benchmark tests were performed with the various SQL*Loader options. The table was truncated after each test. SQL*Loader Option direct=false rows=64 direct=false bindsize=512000 rows=10000 direct=false bindsize=512000 rows=10000 database in noarchivelog direct=true direct=true unrecoverable direct=true unrecoverable fixed width data

Elapsed Time (Seconds) 135

Time Reduction

92

32%

85

37%

47 41

65% 70%

41

70%

-

The results above indicate that conventional path loads take the longest. However, the bindsize and rows parameters can aid the performance under these loads. The test involving the conventional load didn’t come close to the performance of the direct path load with the unrecoverable option specified.

60

It is also worth noting that the fastest import time achieved for this table (earlier) was 67 seconds, compared to 41 for SQL*Loader direct path – a 39% reduction in execution time. This proves that SQL*Loader can load the same data faster than import. These tests did not compensate for indexes. All database load operations will execute faster when indexes are disabled. SQL*Loader Control File The control file is a text file written in a language that SQL*Loader understands. The control file describes the task that the SQL*Loader is to carry out. The control file tells SQL*Loader where to find the data, how to parse and interpret the data, where to insert the data, and more. See Chapter 4, "SQL*Loader Case Studies" for example control files. Although not precisely defined, a control file can be said to have three sections: 1. The first section contains session-wide information, for example: o global options such as bindsize, rows, records to skip, etc. o INFILE clauses to specify where the input data is located o data character set specification 2. The second section consists of one or more "INTO TABLE" blocks. Each of these blocks contains information about the table into which the data is to be loadedsuch as the table name and the columns of the table. 3. The third section is optional and, if present, contains input data. Examples Case 1: Loading Variable-Length Data Loads stream format records in which the fields are delimited by commas and may be enclosed by quotation marks. The data is found at the end of the control file. Case 2: Loading Fixed-Format Fields: Loads a datafile with fixed-length fields, stream-format records, all records the same length. Case 3: Loading a Delimited, Free-Format File Loads data from stream format records with delimited fields and sequence numbers. The data is found at the end of the control file. Case 4: Loading Combined Physical Records Combines multiple physical records into one logical record corresponding to one database row Case 5: Loading Data into Multiple Tables Loads data into multiple tables in one run Case 6: Loading Using the Direct Path Load Method Loads data using the direct path load method Case 7: Extracting Data from a Formatted Report Extracts data from a formatted report Case 8: Loading Partitioned Tables Loads partitioned tables. Case 9: Loading LOBFILEs (CLOBs) Adds a CLOB column called RESUME to the table emp, uses a FILLER field (RES_FILE), and loads multiple LOBFILEs into the emp table.

61

Case 10: How to use TRIM, TO_NUMBER, TO_CHAR, User Defined Functions with SQL*Loader How to use the functions TRIM, TO_CHAR/TO_NUMBER, and user defined functions in connection with SQL*Loader Case 11: Calling Stored Functions How to call a Function from SQL*Loader OPTIONS Clause Continue Interrupted Load Identifying Data Files Loading into Non-Empty Tables Loading into Multiple Tables

Case 1: Loading Variable-Length Data • • •

A simple control file identifying one table and three columns to be loaded. Including data to be loaded from the control file itself, so there is no separate datafile. Loading data in stream format, with both types of delimited fields -- terminated and enclosed.

Control File 1) LOAD DATA 2) INFILE * 3) INTO TABLE dept 4) FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' 5) (deptno, dname, loc) 6) BEGINDATA 12,RESEARCH,"SARATOGA" 10,"ACCOUNTING",CLEVELAND 11,"ART",SALEM 13,FINANCE,"BOSTON" 21,"SALES",PHILA. 22,"SALES",ROCHESTER 42,"INT'L","SAN FRAN"

Notes: 1. The LOAD DATA statement is required at the beginning of the control file. 2. INFILE * specifies that the data is found in the control file and not in an external file. 3. The INTO TABLE statement is required to identify the table to be loaded (DEPT) into. By default, SQL*Loader requires the table to be empty before it inserts any records. 4. FIELDS TERMINATED BY specifies that the data is terminated by commas, but may also be enclosed by quotation marks. Datatypes for all fields default to CHAR. 5. Specifies that the names of columns to load are enclosed in parentheses. Since no datatype is specified, the default is a character of length 255.

62

BEGINDATA specifies the beginning of the data. Invoking SQL*Loader To run this example, invoke SQL*Loader with the command: sqlldr userid=scott/tiger control=ulcase1.ctl log=ulcase1.log

Case 2: Loading Fixed-Format Fields • •

A separate datafile. Data conversions.

In this case, the field positions and datatypes are specified explicitly. Control File 1) LOAD DATA 2) INFILE 'ulcase2.dat' 3) INTO TABLE emp 4) (empno POSITION(01:04) INTEGER EXTERNAL, ename POSITION(06:15) CHAR, job POSITION(17:25) CHAR, mgr POSITION(27:30) INTEGER EXTERNAL, sal POSITION(32:39) DECIMAL EXTERNAL, comm POSITION(41:48) DECIMAL EXTERNAL, 5) deptno POSITION(50:51) INTEGER EXTERNAL, 6) modifieddate "SYSDATE", 7) customerid constant "0" ) Notes: 1. 2. 3. 4.

The LOAD DATA statement is required at the beginning of the control file. The name of the file containing data follows the keyword INFILE. The INTO TABLE statement is required to identify the table to be loaded into. Lines 4 and 5 identify a column name and the location of the data in the datafile to be loaded into that column. EMPNO, ENAME, JOB, and so on are names of columns in table EMP. The datatypes (INTEGER EXTERNAL, CHAR, DECIMAL EXTERNAL) identify the datatype of data fields in the file, not of corresponding columns in the EMP table. 5. Note that the set of column specifications is enclosed in parentheses. 6. This statement let me insert the current sysdate in this field 7. This statement let me put a constant value

Datafile Below are a few sample data lines from the file ULCASE2.DAT. Blank fields are set to null automatically. 7782 7839 7934 7566 7499 7654 . Case

CLARK KING MILLER JONES ALLEN MARTIN

MANAGER PRESIDENT CLERK MANAGER SALESMAN SALESMAN

7839 2572.50 5500.00 7782 920.00 7839 3123.75 7698 1600.00 7698 1312.50

300.00 1400.00

3: Loading a Delimited, Free Format File

10 10 10 20 30 30

63

• • • • • •

Loading data (enclosed and terminated) in stream format Loading dates using the datatype DATE Using SEQUENCE numbers to generate unique keys for loaded data Using APPEND to indicate that the table need not be empty before inserting new records Using Comments in the control file set off by double dashes Overriding general specifications with declarations for individual fields

In this case, the field positions and datatypes are specified explicitly. Control File This control file loads the same table as in Case 2, but it loads three additional columns (HIREDATE, PROJNO, LOADSEQ). The demonstration table EMP does not have columns PROJNO and LOADSEQ. So if you want to test this control file, add these columns to the EMP table with the command: ALTER TABLE EMP ADD (PROJNO NUMBER, LOADSEQ NUMBER) The data is in a different format than in Case 2. Some data is enclosed in quotation marks, some is set off by commas, and the values for DEPTNO and PROJNO are separated by a colon. 1) -- Variable-length, delimited and enclosed data format LOAD DATA 2) INFILE * 3) APPEND INTO TABLE emp 4) FIELDS TERMINATED BY "," OPTIONALLY ENCLOSED BY '"' (empno, ename, job, mgr, 5) hiredate DATE(20) "DD-Month-YYYY", sal, comm, deptno CHAR TERMINATED BY ':', projno, 6) loadseq SEQUENCE(MAX,1)) 7) BEGINDATA 8) 7782, "Clark", "Manager", 7839, 09-June-1981, 2572.50,, 10:101 7839, "King", "President", , 17-November-1981,5500.00,,10:102 7934, "Miller", "Clerk", 7782, 23-January-1982, 920.00,, 10:102 7566, "Jones", "Manager", 7839, 02-April-1981, 3123.75,, 20:101 7499, "Allen", "Salesman", 7698, 20-February-1981, 1600.00, (same line continued) 300.00, 30:103 7654, "Martin", "Salesman", 7698, 28-September-1981, 1312.50, (same line continued) 1400.00, 3:103 7658, "Chan", "Analyst", 7566, 03-May-1982, 3450,, 20:101 Notes: 1. Comments may appear anywhere in the command lines of the file, but they should not appear in data. They are preceded with a double dash that may appear anywhere on a line. 2. INFILE * specifies that the data is found at the end of the control file. 3. Specifies that the data can be loaded even if the table already contains rows. That is, the table need not be empty. 4. The default terminator for the data fields is a comma, and some fields may be enclosed by double quotation marks ("). 5. The data to be loaded into column HIREDATE appears in the format DD-Month-YYYY. The length of the date field is a maximum of 20. If a length is not specified, the length is a maximum of 20. If a length is not specified, then the length depends on the length of the date mask. 6. The SEQUENCE function generates a unique value in the column LOADSEQ. This function finds the current maximum value in column LOADSEQ and adds the increment (1) to it to obtain the value for LOADSEQ for each row inserted. 7. BEGINDATA specifies the end of the control information and the beginning of the data. 8. Although each physical record equals one logical record, the fields vary in length so that some records are longer than others. Note also that several rows have null values for COMM.

64

Case 4: Loading Combined Physical Records • • • • • •

Combining multiple physical records to form one logical record with CONTINUEIF Inserting negative numbers. Indicating with REPLACE that the table should be emptied before the new data is inserted Specifying a discard file in the control file using DISCARDFILE Specifying a maximum number of discards using DISCARDMAX Rejecting records due to duplicate values in a unique index or due to invalid data values

Control File LOAD DATA INFILE 'ulcase4.dat' 1) DISCARDFILE 'ulcase4.dsc' 2) DISCARDMAX 999 3) REPLACE 4) CONTINUEIF THIS (1) = '*' INTO TABLE emp (empno POSITION(1:4) ename POSITION(6:15) job POSITION(17:25) mgr POSITION(27:30) sal POSITION(32:39) comm POSITION(41:48) deptno POSITION(50:51) hiredate POSITION(52:60) Notes: • • • •

INTEGER CHAR, CHAR, INTEGER DECIMAL DECIMAL INTEGER INTEGER

EXTERNAL, EXTERNAL, EXTERNAL, EXTERNAL, EXTERNAL, EXTERNAL)

DISCARDFILE specifies a discard file named ULCASE4.DSC. DISCARDMAX specifies a maximum of 999 discards allowed before terminating the run (for all practical purposes, this allows all discards). REPLACE specifies that if there is data in the table being loaded, then SQL*Loader should delete that data before loading new data. CONTINUEIF THIS specifies that if an asterisk is found in column 1 of the current record, then the next physical record after that record should be appended to it to from the logical record. Note that column 1 in each physical record should then contain either an asterisk or a non-data value.

Data File The datafile for this case, ULCASE4.DAT, is listed below. Note the asterisks in the first position and, though not visible, a new line indicator is in position 20 (following "MA", "PR", and so on). Note that CLARK's commission is -10, and SQL*Loader loads the value converting it to a negative number.

*7782 *7839 *7934 *7566 *7499 *7654 *7658 * *7658

CLARK KING MILLER JONES ALLEN MARTIN CHAN CHEN CHIN

MANAGER PRESIDENT CLERK MANAGER SALESMAN SALESMAN ANALYST ANALYST ANALYST

Rejected Records

7839 2572.50 5500.00 7782 920.00 7839 3123.75 7698 1600.00 7698 1312.50 7566 3450.00 7566 3450.00 7566 3450.00

-10

300.00 1400.00

2512-NOV-85 2505-APR-83 2508-MAY-80 2517-JUL-85 25 3-JUN-84 2521-DEC-85 2516-FEB-84 2516-FEB-84 2516-FEB-84

65

The last two records are rejected, given two assumptions. If there is a unique index created on column EMPNO, then the record for CHIN will be rejected because his EMPNO is identical to CHAN's. If EMPNO is defined as NOT NULL, then CHEN's record will be rejected because it has no value for EMPNO. Case 5: Loading Data in Multiple Tables • • • • •

Loading multiple tables Using SQL*Loader to break down repeating groups in a flat file and load the data into normalized tables -- one file record may generate multiple database rows Deriving multiple logical records from each physical record Using a WHEN clause Loading the same field (EMPNO) into multiple tables

Control File -- Loads EMP records from first 23 characters -- Creates and loads PROJ records for each PROJNO listed -- for each employee LOAD DATA INFILE 'ulcase5.dat' BADFILE 'ulcase5.bad' DISCARDFILE 'ulcase5.dsc' 1) REPLACE 2) INTO TABLE emp (empno POSITION(1:4) INTEGER EXTERNAL, ename POSITION(6:15) CHAR, deptno POSITION(17:18) CHAR, mgr POSITION(20:23) INTEGER EXTERNAL) 2) INTO TABLE proj -- PROJ has two columns, both not null: EMPNO and PROJNO 3) WHEN projno != ' ' (empno POSITION(1:4) INTEGER EXTERNAL, 3) projno POSITION(25:27) INTEGER EXTERNAL) -- 1st proj 3) INTO TABLE proj 4) WHEN projno != ' ' (empno POSITION(1:4) INTEGER EXTERNAL, 4) projno POSITION(29:31 INTEGER EXTERNAL) -- 2nd proj 2) INTO TABLE proj 5) WHEN projno != ' ' (empno POSITION(1:4) INTEGER EXTERNAL, 5) projno POSITION(33:35) INTEGER EXTERNAL) -- 3rd proj Notes: • • • • •

REPLACE specifies that if there is data in the tables to be loaded (EMP and PROJ), SQL*loader should delete the data before loading new rows. Multiple INTO clauses load two tables, EMP and PROJ. The same set of records is processed three times, using different combinations of columns each time to load table PROJ. WHEN loads only rows with non-blank project numbers. When PROJNO is defined as columns 25...27, rows are inserted into PROJ only if there is a value in those columns. When PROJNO is defined as columns 29...31, rows are inserted into PROJ only if there is a value in those columns. When PROJNO is defined as columns 33...35, rows are inserted into PROJ only if there is a value in those columns.

Data File 1234 BAKER

10 9999 101 102 103

66

1234 2664 5321 2134 2414 6542 2849 4532 1244 123 1453

JOKER YOUNG OTOOLE FARMER LITTLE LEE EDDS PERKINS HUNT DOOLITTLE MACDONALD

10 20 10 20 20 10 xx 10 11 12 25

9999 2893 9999 4555 5634 4532 4555 9999 3452 9940 5532

777 425 321 236 236 102

888 999 abc 102 55 40 456 456 40 321 14 294 40

40 665 133 456 132 200

Case 6: Loading Using the direct Path Load Method • • • • •

Use of the direct path load method to load and index data How to specify the indexes for which the data is pre-sorted. Loading all-blank numeric fields as null The NULLIF clause Note: Specify the name of the table into which you want to load data; otherwise, you will see LDR927. Specifying DIRECT=TRUE as a command-line parameter is not an option when loading into a synonym for a table.

In this example, field positions and datatypes are specified explicitly. Control File LOAD DATA INFILE 'ulcase6.dat' INSERT INTO TABLE emp 1) SORTED INDEXES (empix) 2)(empno POSITION(01:04) INTEGER EXTERNAL NULLIF empno=BLANKS, ename POSITION(06:15) CHAR, job POSITION(17:25) CHAR, mgr POSITION(27:30) INTEGER EXTERNAL NULLIF mgr=BLANKS, sal POSITION(32:39) DECIMAL EXTERNAL NULLIF sal=BLANKS, comm POSITION(41:48) DECIMAL EXTERNAL NULLIF comm=BLANKS, deptno POSITION(50:51) INTEGER EXTERNAL NULLIF deptno=BLANKS) Notes: •



The SORTED INDEXES clause identifies indexes:presorting data:case study the indexes on which the data is sorted. This clause indicates that the datafile is sorted on the columns in the EMPIX index. This clause allows SQL*Loader to optimize index creation by eliminating the sort phase for this data when using the direct path load method. The NULLIF...BLANKS clause specifies that the column should be loaded as NULL if the field in the datafile consists of all blanks

Case 7: Extracting Data from a formatted Report • • • • • •

Using SQL*Loader with an INSERT trigger Use of the SQL string to manipulate data Different initial and trailing delimiters Use of SYSDATE Use of the TRAILING NULLCOLS clause Ambiguous field length warnings

67

Note: This example creates a trigger that uses the last value of unspecified fields. Data File The following listing of the report shows the data to be loaded: Today's Newly Hired Employees Dept Job Manager MgrNo Emp Name EmpNo Salary (Comm) ---- -------- -------- ----- -------- ----- --------- -----20 Salesman Blake 7698 Shepard 8061 $1,600.00 (3%) Falstaff 8066 $1,250.00 (5%) Major 8064 $1,250.00 (14%) 30 Clerk Scott 7788 Conrad 8062 $1,100.00 Ford 7369 DeSilva 8063 $800.00 Manager King 7839 Provo 8065 $2,975.00 Insert Trigger In this case, a BEFORE INSERT trigger is required to fill in department number, job name, and manager's number when these fields are not present on a data line. When values are present, they should be saved in a global variable. When values are not present, the global variables are used. The INSERT trigger and the package defining the global variables is: CREATE OR REPLACE PACKAGE uldemo7 AS -- Global Package Variables last_deptno NUMBER(2); last_job VARCHAR2(9); last_mgr NUMBER(4); END uldemo7; / CREATE OR REPLACE TRIGGER uldemo7_emp_insert BEFORE INSERT ON emp FOR EACH ROW BEGIN IF :new.deptno IS NOT NULL THEN uldemo7.last_deptno := :new.deptno; -- save value for later ELSE :new.deptno := uldemo7.last_deptno; -- use last valid value END IF; IF :new.job IS NOT NULL THEN uldemo7.last_job := :new.job; ELSE :new.job := uldemo7.last_job; END IF; IF :new.mgr IS NOT NULL THEN uldemo7.last_mgr := :new.mgr; ELSE :new.mgr := uldemo7.last_mgr; END IF; END; / Note: The phrase FOR EACH ROW is important. If it was not specified, the INSERT trigger would only fire once for each array of inserts because SQL*Loader uses the array interface. Control File LOAD DATA INFILE 'ULCASE7.DAT' APPEND INTO TABLE emp

68

1) 2) 3) 4) 5)

WHEN (57) = '.' TRAILING NULLCOLS (hiredate SYSDATE, deptno POSITION(1:2) INTEGER EXTERNAL(3) NULLIF deptno=BLANKS, job POSITION(7:14) CHAR TERMINATED BY WHITESPACE NULLIF job=BLANKS "UPPER(:job)", mgr POSITION(28:31) INTEGER EXTERNAL TERMINATED BY WHITESPACE, NULLIF mgr=BLANKS, ename POSITION(34:41) CHAR TERMINATED BY WHITESPACE "UPPER(:ename)", empno POSITION(45) INTEGER EXTERNAL TERMINATED BY WHITESPACE, sal POSITION(51) CHAR TERMINATED BY WHITESPACE "TO_NUMBER(:sal,'$99,999.99')", comm INTEGER EXTERNAL ENCLOSED BY '(' AND '%' ":comm * 100"

6) 7)

8) 9)

) Notes: • •

• • • • •

• •

The decimal point in column 57 (the salary field) identifies a line with data on it. All other lines in the report are discarded. The TRAILING NULLCOLS clause causes SQL*Loader to treat any fields that are missing at the end of a record as null. Because the commission field is not present for every record, this clause says to load a null commission instead of rejecting the record when only six fields are found instead of the expected seven. Employee's hire date is filled in using the current system date. This specification generates a warning message because the specified length does not agree with the length determined by the field's position. The specified length (3) is used. Because the report only shows department number, job, and manager when the value changes, these fields may be blank. This control file causes them to be loaded as null, and an RDBMS insert trigger fills in the last valid value. The SQL string changes the job name to uppercase letters. It is necessary to specify starting position here. If the job field and the manager field were both blank, then the job field's TERMINATED BY BLANKS clause would cause SQL*Loader to scan forward to the employee name field. Without the POSITION clause, the employee name field would be mistakenly interpreted as the manager field. Here, the SQL string translates the field from a formatted character string into a number. The numeric value takes less space and can be printed with a variety of formatting options. In this case, different initial and trailing delimiters pick the numeric value out of a formatted field. The SQL string then converts the value to its stored form.

Case 8: Loading Partitioned Tables • • •

Partitioning of data Explicitly defined field positions and datatypes. Loading using the fixed record length option

Control File LOAD DATA 1) INFILE 'ulcase10.dat' "fix 129" BADFILE 'ulcase10.bad' TRUNCATE INTO TABLE lineitem PARTITION (ship_q1) 2) (l_orderkey position

(1:6) char,

69

l_partkey l_suppkey l_linenumber l_quantity l_extendedprice l_discount l_tax l_returnflag l_linestatus l_shipdate l_commitdate l_receiptdate l_shipinstruct l_shipmode l_comment Notes: • •

position (7:11) position (12:15) position (16:16) position (17:18) position (19:26) position (27:29) position (30:32) position (33:33) position (34:34) position (35:43) position (44:52) position (53:61) position (62:78) position (79:85) position (86:128)

char, char, char, char, char, char, char, char, char, char, char, char, char, char, char)

Specifies that each record in the datafile is of fixed length (129 characters in this example). See Input Data and Datafiles. Identifies the column name and location of the data in the datafile to be loaded into each column.

Table Creation In order to partition the data the lineitem table is created using four (4) partitions according to the shipment date: Create table lineitem (l_orderkey number, l_partkey number, l_suppkey number, l_linenumber number, l_quantity number, l_extendedprice number, l_discount number, l_tax number, l_returnflag char, l_linestatus char, l_shipdate date, l_commitdate date, l_receiptdate date, l_shipinstruct char(17), l_shipmode char(7), l_comment char(43) ) partition by range (l_shipdate) ( partition ship_q1 values less than (TO_DATE('01-APR-1996', 'DD-MON-YYYY')) tablespace p01, partition ship_q2 values less than (TO_DATE('01-JUL-1996', 'DD-MON-YYYY')) tablespace p02, partition ship_q3 values less than (TO_DATE('01-OCT-1996', 'DD-MON-YYYY')) tablespace p03, partition ship_q4 values less than (TO_DATE('01-JAN-1997', 'DD-MON-YYYY')) tablespace p04 ) Input Data File The datafile for this case, ULCASE8.DAT, is listed below. Each record is 129 characters in length. Note that five(5) blanks precede each record in the file. 1 151978511724386.60 7.04.0NO09-SEP-6412-FEB-9622-MAR-96DELIVER IN PERSONTRUCK iPBw4mMm7w7kQ zNPL i261OPP

70

1 2731 73223658958.28.09.06NO12-FEB-9628-FEB-9620-APR-96TAKE BACK RETURN MAIL 5wM04SNyl0AnghCP2nx lAi 1 3370 3713 810210.96 .1.02NO29-MAR-9605-MAR-9631-JAN-96TAKE BACK RETURN REG AIRSQC2C 5PNCy4mM 1 5214 46542831197.88.09.06NO21-APR-9630-MAR-9616-MAY-96NONE AIR Om0L65CSAwSj5k6k 1 6564 6763246897.92.07.02NO30-MAY-9607-FEB-9603-FEB-96DELIVER IN PERSONMAIL CB0SnyOL PQ32B70wB75k 6Aw10m0wh 1 7403 160524 31329.6 .1.04NO30-JUN-9614-MAR-9601 APR-96NONE FOB C2gOQj OB6RLk1BS15 igN 2 8819 82012441659.44 0.08NO05-AUG-9609-FEB-9711-MAR-97COLLECT COD AIR O52M70MRgRNnmm476mNm 3 9451 721230 41113.5.05.01AF05-SEP-9629-DEC-9318-FEB-94TAKE BACK RETURN FOB 6wQnO0Llg6y 3 9717 1834440788.44.07.03RF09-NOV-9623-DEC-9315-FEB-94TAKE BACK RETURN SHIP LhiA7wygz0k4g4zRhMLBAM 3 9844 1955 6 8066.64.04.01RF28-DEC-9615-DEC-9314-FEB-94TAKE BACK RETURN REG AIR6nmBmjQkgiCyzCQBkxPPOx5j4hB 0lRywgniP1297

Case 9: Loading LOB Files (CLOBs) • • •

Adding a CLOB column called RESUME to the table emp. Using a FILLER field (RES_FILE). Loading multiple LOBFILEs into the emp table.

Control File LOAD DATA INFILE * INTO TABLE EMP REPLACE FIELDS TERMINATED BY ',' ( EMPNO INTEGER EXTERNAL, ENAME CHAR, JOB CHAR, MGR INTEGER EXTERNAL, SAL DECIMAL EXTERNAL, COMM DECIMAL EXTERNAL, DEPTNO INTEGER EXTERNAL, 1) RES_FILE FILLER CHAR, 2) "RESUME" LOBFILE (RES_FILE) TERMINATED BY EOF NULLIF RES_FILE = 'NONE' ) BEGINDATA 7782,CLARK,MANAGER,7839,2572.50,,10,ulcase91.dat 7839,KING,PRESIDENT,,5500.00,,10,ulcase92.dat 7934,MILLER,CLERK,7782,920.00,,10,ulcase93.dat 7566,JONES,MANAGER,7839,3123.75,,20,ulcase94.dat 7499,ALLEN,SALESMAN,7698,1600.00,300.00,30,ulcase95.dat 7654,MARTIN,SALESMAN,7698,1312.50,1400.00,30,ulcase96.dat 7658,CHAN,ANALYST,7566,3450.00,,20,NONE Notes: • •

This is a filler field. The filler field is assigned values from the datafield to which it is mapped. RESUME is loaded as a CLOB. The LOBFILE function is used to specify the name of the field that specifies name of the file which contains the data for the LOB field.

71

Case 10: How to use TRIM, TO_NUMBER, TO_CHAR with SQL*Loader This note explains how to use the functions TRIM, TO_CHAR/TO_NUMBER, and user defined functions in connection with SQL*Loader using the following example: -- Create the table DROP TABLE TEST; CREATE TABLE TEST ( ID NUMBER PRIMARY KEY, FIRST_NAME VARCHAR2(20), LAST_NAME VARCHAR2(20) NOT NULL, DEPARTMENT VARCHAR2(20) NOT NULL, SALARY NUMBER(10,2) NOT NULL, BONUS NUMBER(10,2), DESCRIPTION VARCHAR2(50), TOTAL NUMBER(10,2) ); -- Create the user defined functions (used by SQL*Loader) CREATE OR REPLACE FUNCTION GET_BONUS (dept IN VARCHAR2) RETURN NUMBER AS retval NUMBER(10,2); BEGIN retval := NULL; if upper (dept) in ('CLERK', 'SALESMAN') then if to_char (sysdate, 'YYYY') = '2002' then retval := 9.2; else retval := 7.88; end if; elsif upper (dept) = 'ANALYST' then retval := 18.7; elsif upper (dept) = 'MANAGER' then retval := -5.92; end if; return (retval); END; / CREATE OR REPLACE FUNCTION CALC_SAL (sal IN NUMBER, bon IN NUMBER) RETURN NUMBER AS retval NUMBER(10,2); BEGIN if bon is null then retval := sal; else retval := round (sal + (sal * bon / 100), 2); end if; return (retval); END; /

The table TEST will be loaded with this control file: LOAD DATA INFILE * INTO TABLE TEST TRUNCATE

72

FIELDS TERMINATED BY ';' OPTIONALLY ENCLOSED BY '"' TRAILING NULLCOLS ( ID SEQUENCE, FIRST_NAME "TRIM (:FIRST_NAME)", -LAST_NAME "TRIM ('x' FROM :LAST_NAME)", -DEPARTMENT, SALARY "TO_NUMBER (:SALARY, '99999D99', -'NLS_NUMERIC_CHARACTERS='',.''')", BONUS "GET_BONUS (:DEPARTMENT)", -DESCRIPTION "'Salary: '||:SALARY||' -> '|| -DECODE (GET_BONUS (:DEPARTMENT), NULL, 'No bonus', 'Bonus: '||TO_CHAR (GET_BONUS (:DEPARTMENT), 'S09D90'))", TOTAL "CALC_SAL (TO_NUMBER (:SALARY, '99999D99', -'NLS_NUMERIC_CHARACTERS='',.'''), GET_BONUS (:DEPARTMENT))" ) BEGINDATA " Martin " David " Brad " Marvin " Dean " John " Clark " Scott " Ralph " Tina " Bryan " Jesse " John " John

1) 2) 3) 4) 5) 6)

";"xxxxxxxSmithxxx";CLERK;2459,25 ";"xxxxxxxAllenxxx";SALESMAN;4563,9 ";"xxxxxxxWardxxxx";SALESMAN;4815,81 ";"xxxxxxxJonesxxx";MANAGER;9765,33 ";"xxxxxxxMartinxx";SALESMAN;4214,56 ";"xxxxxxxBlakexxx";MANAGER;10333,87 ";"xxxxxxxGablexxx";MANAGER;11011,11 ";"xxxxxxxTigerxxx";ANALYST;6865,88 ";"xxxxxxxKingxxxx";PRESIDENT;18955,45 ";"xxxxxxxTurnerxx";SALESMAN;5324,44 ";"xxxxxxxAdamsxxx";CLERK;1899,48 ";"xxxxxxxJamesxxx";CLERK;2288,99 ";"xxxxxxxFordxxxx";ANALYST;7564,83 ";"xxxxxxxMillerxx";CLERK;1865,93

1) TRIM deletes the leading/trailing blanks in the column FIRST_NAME (i.e. " Martin " becomes "Martin") 2) TRIM deletes the leading/trailing 'x' characters in the column LAST_NAME (i.e. "xxxxxxxSmithxxx" becomes "Smith") 3) TO_NUMBER shows that the format of the numbers in the column SALARY is in the form: 99999D99. That means max. 5 digits integer with max. 2 digit post-decimal positions. The decimal separator is ','. If the format is not specified, then the records are not loaded (ORA-1722 invalid number, if NLS_NUMERIC_CHARACTERS = '.,') 4) The column BONUS is calculated with the user defined function GET_BONUS. The Function expects an input parameter, DEPARTMENT (VARCHAR2), and returns the value, BONUS (NUMBER(2,2)) 5) The column DESCRIPTION is a composition of the information from the previous columns. The Function DECODE checks if a bonus is available to the department. If no bonus is available, then the message 'No bonus' will be printed. The new thing here is the function TO_CHAR. This function modifies the format of the BONUS in this form: sign, 2 integer digits with leading zeros, decimal separator, 2 post-decimal positions with trailing zeros. 6) The column TOTAL is calculated with the user defined function CALC_SAL (the BONUS, if available, is applied to the SALARY) The result after the loading procedure looks like this in the table TEST: SQL> select * from test; ID FIRST_NAME LAST_NAME DEPARTMENT SALARY ---------- -------------------- -------------------- -------------------- ---------1 Martin Smith CLERK 2459.25 2 David Allen SALESMAN 4563.9

73

3 Brad 4 Marvin 5 Dean 6 John 7 Clark 8 Scott 9 Ralph 10 Tina 11 Bryan 12 Jesse 13 John 14 John

Ward Jones Martin Blake Gable Tiger King Turner Adams James Ford Miller

SALESMAN MANAGER SALESMAN MANAGER MANAGER ANALYST PRESIDENT SALESMAN CLERK CLERK ANALYST CLERK

4815.81 9765.33 4214.56 10333.87 11011.11 6865.88 18955.45 5324.44 1899.48 2288.99 7564.83 1865.93

Case 11: Calling a Stored Function from SQL*Loader This small example shows how to call a stored function. It is possible to call any built-in or user-defined function during load process. Usually it's done for date columns, when non-default date format must be used, however user-defined function(s) may be called to perform some application logic. The syntax for such calls is quite simple: LOAD DATA INFILE * APPEND INTO TABLE dept ( deptno POSITION(01:02) INTEGER EXTERNAL, dname POSITION(03:16) CHAR "LDR_PCK.NAME(:dname, :deptno)", loc POSITION(17:29) CHAR ) BEGINDATA 21Dep Loc 22Dep Loc Here LDR_PCK.NAME is name of package and function, :dnname and :deptno are parameters. When calling user-defined functions we must remember that only conventional path may be used. An attempt to use direct path will cause an error: SQL*Loader-00417 SQL String (on column column_name) not allowed in direct path.

The OPTIONS Clause The OPTIONS clause is useful when you usually invoke a control file with the same set of options, or when the command line and all its arguments becomes very long. This clause allows you to specify runtime arguments in the control file rather than on the command line.

SKIP = n -- Number of logical records to skip (DEFAULT 0) LOAD = n -- Number of logical records to load (DEFAULT all) ERRORS = n -- Number of errors to allow (DEFAULT 50) ROWS = n -- Number of rows in conventional path bind array (DEFAULT 64) BINDSIZE = n -- Size of conventional path bind array in bytes SILENT = {HEADER | FEEDBACK | ERROR | DISCARDS | ALL } -- Suppress messages during run

74

For example: OPTIONS (BINDSIZE=10000, SILENT=(ERRORS, FEEDBACK) ) Values specified on the command line override values specified in the control file. With this precedence, the OPTIONS keyword in the control file established default values that are easily changed from the command line. Continuing Interrupted Loads If SQL*Loader runs out of space for data rows or index entries, the load is discontinued. (For example, the table might reach its maximum number of extents.) Discontinued loads can be continued after more space is made available. When a load is discontinued, any data already loaded remains in the tables, and the tables are left in a valid state. SQL*Loader's log file tells you the state of the tables and indexes and the number of logical records already read from the input data file. Use this information to resume the load where it left off. For example: SQLLOAD / CONTROL=FAST1.CTL SKIP=345 CONTINUE\_LOAD DATA statement is used to continue a discontinued direct path load involving multiple tables with a varying number of records to skip. For more information on this command, see chapter 6 of ``ORACLE7 Server Utilities Users Guide''.

Identifying Data Files To specify the file containing the data to be loaded, use the INFILE or INDDN keyword, followed by the filename. A filename specified on the command line overrides the first INFILE or INDDN statement in the control file. If no filename is specified, the filename defaults to the control filename with an extension or filetype of DAT. Loading into Non-Empty Database Tables SQL*Loader does not update existing records, even if they have null columns. If the tables you are loading already contain data, you have three choices for how SQL*Loader should proceed: INSERT - This is the default option. It requires the table to be empty before loading. SQL*Loader terminates with an error if the table contains rows. APPEND - If data already exists in the table, SQL*Loader appends the new rows to it; if data doesn't already exist, the new rows are simply loaded. REPLACE - All rows in the table are deleted and the new data is loaded. This option requires DELETE privileges on the table. You can create one logical record from multiple physical records using CONCATENATE and CONTINUEIF. See chapter 6 of ``ORACLE7 Server Utilities Users Guide''. Loading Logical Records into Tables

75

The INTO TABLE clause allows you to tell which table you want to load data into. To load multiple tables, you would include one INTO TABLE clause for each table you wish to load. The INTO TABLE clause may continue with some options for loading that table. For example, you may specify different options (INSERT, APPEND, REPLACE) for each table in order to tell SQL*Loader what to do if data already exists in the table. The WHEN clause appears after the table name and is followed by one or more field conditions. For example, the following clause indicates that any record with the value ``q'' in the fifth column position should be loaded: WHEN (5) = 'q' A WHEN clause can contain several comparisons as long as each is preceded by AND. Parentheses are optional but should be used for clarity with multiple comparisons joined by AND. For example: WHEN (DEPTNO = '10') AND (JOB = 'SALES') To evaluate the WHEN clause, SQL*Loader first determines the values of all the fields in the record. Then the WHEN clause is evaluated. A row is inserted into the table only if the WHEN clause is true. When the control file specifies more fields for a record than are present in the record, SQL*Loader must determine whether the remaining (specified) columns should be considered null, or whether an error should be generated. TRAILING NULLCOLS clause tells SQL*Loader to treat any relatively positioned columns that are not present in the record as null columns. For example, if the following data 10 Accounting is read with the following control file INTO TABLE dept TRAILING NULLCOLS ( deptno CHAR TERMINATED BY " ", dname CHAR TERMINATED BY WHITESPACE, loc CHAR TERMINATED BY WHITESPACE ) and the record ends after DNAME, then the remaining LOC field is set to null. Without the TRAILING NULLCOLS clause, an error would be generated, due to missing data.

Oracle datatypes Datatype summary for Oracle 7, 8 & 9

76

Datatype

Description

Max Size: Oracle 7

Max Size: Oracle 8

Max Size: Oracle 9

VARCHAR2(size)

Variable length character string having maximum length size bytes. You must specify size

2000 bytes 4000 bytes 4000 bytes minimum is minimum is minimum is 1 1 1

NVARCHAR2(size)

Variable length national character set string having N/A maximum length size bytes. You must specify size

4000 bytes 4000 bytes minimum is minimum is 1 1

VARCHAR

Now deprecated - VARCHAR is a synonym for VARCHAR2 but this usage may change in future versions.

-

CHAR(size)

Fixed length character data of length size bytes. This should be used for fixed length data. Such as codes A100, B102...

NCHAR(size)

Fixed length national character set data of length size bytes. This should be N/A used for fixed length data. Such as codes A100, B102...

M P

3 m

3 m

-

255 bytes 2000 bytes 3 Default and Default and 2000 bytes D minimum minimum Default and minimum size is m size is 1 size is 1 1 byte. 1 byte. byte.

2000 bytes 3 Default and 2000 bytes D minimum Default and minimum size is m size is 1 1 byte. 1 byte.

M 1 1

NUMBER(p,s)

Number having precision p and scale s.

The precision p can range from 1 to 38.

The precision p can range The precision p can range from 1 to from 1 to 38. 38.

The scale s can range from -84 to 127.

The scale s can range from The scale s -84 to 127. can range from -84 to 127.

m p b w e d

T r t

F p s

R m p b w e d PLS_INTEGER

signed integers PL/SQL PLS_INTEGER values require only less storage and provide better performance than

PL/SQL only

PL/SQL only

m r 2

77

NUMBER values. So use PLS_INTEGER where you can! BINARY_INTEGER

LONG

signed integers (older slower version of PLS_INTEGER)

m r 2

Character data of variable 2 length (A bigger version the Gigabytes VARCHAR2 datatype)

3 N s t w c

2 Gigabytes

2 Gigabytes - but now deprecated

from January 1, 4712 BC to December 31, 4712 AD.

from f January 1, 4 4712 BC to from January 1, 4712 BC to D December December 31, 9999 AD. 9 31, 9999 ( AD. 4

the number of digits in the TIMESTAMP fractional part of the (fractional_seconds_precision) SECOND datetime field.

-

-

Accepted values of fractional_seconds_precision are 0 to 9. (default = 6)

TIMESTAMP As above with time zone (fractional_seconds_precision) displacement value WITH {LOCAL} TIMEZONE

-

-

Accepted values of fractional_seconds_precision are 0 to 9. (default = 6)

Time in years and months, where year_precision is the number of digits in the YEAR datetime field.

-

Accepted values are 0 to 9. (default = 2)

DATE

INTERVAL YEAR (year_precision) TO MONTH

Valid date range

Time in days, hours, minutes, and seconds. day_precision is the INTERVAL DAY (day_precision) maximum number of digits TO SECOND in 'DAY' (fractional_seconds_precision) fractional_seconds_precision is the max number of fractional digits in the SECOND field. RAW(size)

LONG RAW

ROWID

Raw binary data of length size bytes. You must specify size for a RAW value. Raw binary data of variable length. (not intrepreted by PL/SQL) Hexadecimal string representing the unique address of a row in its table. (primarily for values

day_precision may be 0 to 9. (default = 2) fractional_seconds_precision may be 0 to 9. (default = 6)

Maximum Maximum size is 255 size is Maximum size is 2000 bytes 3 bytes. 2000 bytes

2 2 2 Gigabytes - but now Gigabytes. Gigabytes. deprecated

3 N s t w R

H s r u

78

returned by the ROWID pseudocolumn.)

o t ( v b p

UROWID

Hex string representing the logical address of a row of an index-organized table

u r l o i t p o O

MLSLABEL

Binary format of an operating system label.This datatype is used with Trusted Oracle7.

CLOB

Character Large Object

NCLOB BLOB

BFILE

N/A

The maximum The maximum size and size and default is 4000 bytes default is 4000 bytes

4Gigabytes 4Gigabytes 4Gigabytes

4

National Character Large Object

4Gigabytes 4Gigabytes

4

Binary Large Object

4Gigabytes 4Gigabytes

4

4Gigabytes 4Gigabytes

T B d c f ( b

pointer to binary file on disk

Notes (pro's & cons) INTEGER This ANSI datatype will be accepted by Oracle - it is actually a synonym for NUMBER(38) VARCHAR2: Storing character data as Varchar2 will save space: Store 'SMITH' not 'SMITH

'

CHAR: Over time, when varchar2 columns are updated they will sometimes create chained rows - because CHAR columns are fixed width they are not affected by this - so less DBA effort is required to maintain performance. NUMBER When retrieving data for a NUMBER column, consider (if you can) using the PL/SQL datatype: PLS_INTEGER for better performance. LONG You should start using BLOB instead of LONG

79

Comparison with other RDBMS's int10

int6

int1

char(n)

blob

Oracle 8

NUMBER(10)

NUMBER(6)

NUMBER(1)

VARCHAR2(n)

BLOB

Sybase system 10

NUMERIC(10)

NUMERIC(6)

NUMERIC(1)

VARCHAR(n)

IMAGE

MS Access 97

Long Int or Double

Single

Byte

TEXT(n)

LONGBINARY

TERADATA

INTEGER

DECIMAL(6)

DECIMAL(1)

VARCHAR(n)

VARBYTE(20480)

DB2

INTEGER

DECIMAL(6)

DECIMAL(1)

VARCHAR(n)

VARCHAR(255)

RDB

INTEGER

DECIMAL(6)

DECIMAL(1)

VARCHAR(n)

LONG VARCHAR

INFORMIX

INTEGER

DECIMAL(6)

DECIMAL(1)

VARCHAR(n)

BYTE

SYBASE

NUMERIC(10)

NUMERIC(6)

NUMERIC(1)

VARCHAR(n)

IMAGE

MS SQL Server 6.0

NUMERIC(10)

NUMERIC(6)

NUMERIC(1)

VARCHAR(n)

IMAGE

RedBrick

integer

int

int

char(n)

char(1024)

INGRES

INTEGER

INTEGER

INTEGER

VARCHAR(n)

VARCHAR(1500)

Type of Indexes Oracle8i also allows you to rebuild your indexes while online. In the past, creating or rebuilding the index required a full lock on the table. On a large table, this could mean that an application is unusable for several hours. Now, however, Oracle allows you to create or rebuild the index while users can still perform the full range of data processes. To do this, Oracle creates the index structure before populating it. While populating, all changes to the table are recorded in a journal table. As the index is completed, the journal table changes are then built in. Brief table locks are made while the index structure is made and the journal table bought into the index. To build an index on line, you use the following syntax: CREATE INDEX my_index ON my_table (my_field) ONLINE;

The importance of PCTFREE For a B-Tree index, PCTFREE determines the extent of a leaf-split. In other words, PCTFREE indicates the amount of free-space within a block for “future updates”. However in the case of an index (unlike a table), these updates do not make sense, since an update anyway forces a delete and subsequent insert. In the case of indexes, PCTFREE plays a role mostly at the time of index-creation. A non-zero value specifies the block-splitting ratio. If PCTFREE is set to 20, during index-creation, up to 80% of the leaf may contain keyinformation. However the remaining 20% should be available for future inserts of key-information into that leaf-block. This ensures that during run-time inserts, there is minimal overhead in terms of incurring leaf-block splits. Even though a higher PCTFREE may cause index-creation time to increase, it prevents the performance-hit from being deferred to actual usage time. So, the end-user, who is waiting for a row to be inserted, does not incur the performance penalty associated with a leaf-block split. Based on this information, the following points emerge: PCTFREE for an index is used primarily during creation. It is ignored during actual usage. Specify  a higher PCTFREE for OLTP applications, if the table is a popular one, incurring a lot of DML changes (via interactive user-screens); If the index-creation time is critical specify a lower PCTFREE. This will pack in more rows per leafblock, thereby avoiding the need for further splitting at creation-time. This is of paramount significance to shops that have “24x7” availability requirements. Index-creation in most cases requires considerable downtime (especially if the table is a multi-million row table). Lesser the amount of index-creation time,

80

smaller can be the maintenance-window. I have seen this tiny, often unnoticed parameter save around 20% of index-creation time. At a high-availability site, an index on a table containing around 11 million rows took me about 80 minutes to build using PCTFREE of 30 and a parallel degree of 4. The same index on the same table, with 13.5 million rows took me around 90 minutes to create with a PCTFREE of 0 (without any hardware/software enhancements). Nologging (minimal redo) was on during both creations. For any column where the values are constantly increasing, it is probably a good idea to set a very low PCTFREE (even, zero). This is because only the rightmost leaf-block will always be inserted into. This will make the tree grow towards the right. The leftmost leaves would remain static. So, there is no sense in leaving any part of those blocks empty with a non-zero PCTFREE. 1- Partitioned Indexes Like tables, indexes can also be partitioned; but with indexes you have a more options because the underlying table might or might not also be partitioned. The objective of this type of index is to separate the index into smaller partitions, just as we do now for a database table. There are essentially two different types of partitioned indexes available: •Global indexes--These are created in a manner different from the underlying partitioning of the table that is indexed. •Local indexes--These are partitioned in the same manner as the underlying table partitioning. Global Indexes To create a global partitioned index, use the CREATE INDEX parameter GLOBAL. This specifies that the index will be a global index. Further partitioning of the index is accomplished by using the following parameters: •GLOBAL--This parameter specifies a global partitioned index.

•PARTITION part_name--This parameter is used to identify the partition. If you do not specify the

partition name, a default name will be provided. It is not usually necessary to provide the partition name. •VALUES LESS THAT--This parameter is used to specify the range that is allocated for that particular partition in the same way as the partition was specified in the CREATE TABLE statement (discussed yesterday). NOTE: The last partition should contain the keyword MAXVALUE for its range.

Creating a partitioned index. CREATE INDEX "ETW".dogs_ix1 ON DOGS (ID) PARTITION BY RANGE (ID) PARTITION pt1 VALUES LESS THAN (`1000') TABLESPACE ts1, PARTITION pt2 VALUES LESS THAN (MAXVALUE) TABLESPACE ts2); ANLYSIS: This create two partitions, the first holding values of ID that are less than 1,000, the second holding the remaining values of ID. If you do not specify the partition name, as is the case here, a default name will be provided. While this does offer a great deal of flexibility, it is not without cost. Since global partitioned indexes are not directly related to any single table partition, operations that affect any partition in the table can render all global partitioned indexes unusable. Specifically the operations: ADD (HASH) - COALESCE (HASH) – DROP – EXCHANGE – MERGE - MOVE -SPLIT - TRUNCATE

Local Indexes

81

In contrast to the global index, a local partitioned index is individually created on each partition. If you specify a local partitioned index, Oracle automatically maintains the index's partitioning along with that of the underlying table. Local partitioned indexes are created through the use of the LOCAL parameter with the CREATE INDEX statement. It is unnecessary to provide partitioning information because the underlying table partitioning will be used. A local index can be created with the following syntax: CREATE INDEX "ETW".dogs_ix1 ON DOGS (ID) LOCAL; Because the index is local, all partition changes to the table will be automatically reflected on the index partitions as well. Local partitioned indexes have some inherent advantages that are similar to the advantages you get from partitioned tables. These advantages include the following: •Because the index exists entirely on one partition, any maintenance operations affect only that one partition. •The Oracle optimizer can use the local index to generate better query plans based on the fact that a local index is used. •If a partition is lost and must be recovered, only the data and index for that particular partition needs to be recovered. With a global index, the entire index would need recovery. As you can see, there are many advantages of using both global and local partitioned indexes. 2- Index-Only Tables Many systems contain several small tables (1 to 3 columns) where all of the elements form the primary key. This is typically the case of tables created to physically implement conceptual relations of the type O,n O,n. However, there exists an extremely efficient way to create such tables, by using a B*-Tree structure. In ORACLE 8, an index-organized table, that is a table with the same physical structure as an index, allows us to do exactly that. In an index-organized table, the database engine will place the data values in a « table » segment, but with a B*-tree structure. An index-only table is a schema object introduced in Oracle8. An index-only table is similar to an index, but whereas an index contains the primary key value and a ROWID pointing to where the data is kept, the index-only table stores the column data in the leaf block of the index. Because the leaf blocks of the Oracle index are traditionally very small and tightly packed, there can be some drawbacks to having large rows stored there. Oracle has developed a way to compensate for this: If rows become too large (by a set threshold), the row data is stored in an overflow area as specified in the CREATE TABLE statement. This creates storage more like the traditional index and table relationship. An index-only table contains the same structure as the Oracle B*-tree index. Only the leaf blocks have changed. Index-only tables have many of the attributes of both indexes and tables, but there are a few exceptions: •Because it is part index and part table, no other indexes can be added to the index-only table.

•The UNIQUE constraint is not allowed on an index-only table.

•A trigger can be added to the index-only table. •An index-only table cannot be stored in a cluster. •Replication is not supported at this time. As you can see, there are some restrictions on index-only tables, but there is also a great deal of benefits. When performing inserts, there is a performance improvement, since only a single segment needs to be updated, which is the table itself. Data retrieval is also faster since the optimizer processes the table just as if it were an index. Furthermore, one read operation is saved since ORACLE doesn't have to read the index prior to performing the read in the table. When to Use Index-Only Tables Index-only tables are very useful whenever data is always accessed via the primary key index. If this is the case with your data, the index-only table will cut down on the space used by both the index and the table (by combining them) and improve performance. Performance is improved because, by the time the ROWID would have been retrieved, you have the data.

82

Tables that are not accessed via the primary key value are not good candidates for index-only tables. Also, tables whose primary key values are updated and tables that have frequent insertions are not good candidates for index-only tables. How to Create Index-Only Tables Index-only tables are created with the CREATE TABLE command; the ORGANIZATION INDEXED qualifier is used to identify the table as index-only. The following qualifiers are used in creating index-only tables: •ORGANIZATION INDEXED--This qualifier specifies an index-only table organization.

•OVERFLOW TABLESPACE ts_name--This qualifier specifies the overflow tablespace name. •PCTTHRESHOLD threshold--This qualifier specifies the percent of a block that a row must be larger than in order to be offloaded to the overflow tablespace. Creating an index-only table with the CREATE TABLE command. CREATE TABLE "ETW".DOGS ( ID NUMBER, NAME VARCHAR2(40), OWNER_ID NUMBER, BREED_ID NUMBER, RANK NUMBER NULL, NOTES VARCHAR2(80) PRIMARY KEY(ID) ) ORGANIZATION INDEXED PCTTHRESHOLD 40 OVERFLOW TABLESPACE "DOGS2" TABLESPACE "DOGS"; ANLYSIS: This specifies that the index-only tablespace be created on the DOGS tablespace, whereas the overflow tablespace used is DOGS2. NOTE: It is necessary to specify the PRIMARY KEY value when creating an index-only table. This is the value on which the index is created. Unfortunately, there are also some disadvantages to using index-organized tables. For example, it is not possible to create additional indexes since the occurrences of this type of table do not have a ROWID. It is also impossible to add new columns or to modify existing columns. The message « ORA-25182 feature not currently available for index-organized table » is used to alert us to these restrictions. Another factor to consider is the case where updating key values is allowed. ORACLE must delete the old record and do an insert based on the new key value, that is relocate a leaf of the B*tree to another location in the B*-tree. The net result is 2 SQL operations. Therefore, one should weight the advantages and disadvantages before choosing this type of table, even though it is relatively easy to convert an index-organized table back to a conventional format using create table as and then doing an Import/Export to that table. 3- Bitmap Indexes Another type of index available the bitmap index. With the traditional index you saw earlier, Oracle uses a B*-tree method to traverse the index to find the leaf block. With a bitmap index, a bitmap of ROWIDs is kept; this bitmap indicates which rows correspond to the index item. If the bit is set, this indicates that the corresponding row contains the key value; if the bit is not set, the opposite is true. As you can probably tell, bitmap indexes can probably be quite useful under the right circumstances, and useless overhead otherwise. When to Use Bitmap Indexes As you can probably guess, the bitmap index works well on items with low cardinality. Low cardinality means there is a small amount of variance in the possible values stored in that column. For example, the column representing the sex of the dog is said to have low cardinality because only two values are

83

possible. Other column types that might have low cardinality include •Marital status •Account status (good or bad) •Sales region (if there are only a few) •Rank (if there are only a few) •Special notes (whether there is a note) With columns that have low cardinality, the bitmap index can greatly improve performance. Columns with high cardinality are not candidates for bitmap indexes. Locking issues affect data manipulation operations in Oracle. As a result, bitmapped indexes are not appropriate for OLTP applications that have a high level of concurrent insert, update and delete operations. Concurrency is usually not an issue in a data-warehousing environment where the data is maintained by bulk loads, inserts and updates. In addition, bitmapped index maintenance is deferred until the end of the bulk DML operation. If 100 rows are inserted into a table, the inserted rows are placed into a sort buffer and the updates of all 100-index entries are applied as a group. As a result, bitmapped indexes are appropriate for most decision support applications (even those that have bulk updates applied on a regular basis). Mass updates, inserts and delete will run faster if you drop the bitmapped indexes, execute the DML and recreate the bitmapped indexes when the DML completes. Run timings using the straight DML and compare it to the total time consumed by the drop bitmapped index/execute DML/recreate bitmapped index process. How to Create Bitmapped Indexes A bitmap index is created with the CREATE INDEX command with the BITMAP qualifier. For example, the following will create a bitmap index: CREATE BITMAP INDEX To create a bitmap index on the SEX field in the DOGS table, you can use the following syntax: CREATE BITMAP INDEX "ETW".dogs_bx1 ON DOGS (SEX); This simple statement will create the bitmap index on the column specified. At this time, bitmap indexes cannot be created with the graphical tools.

4- Reverse Key Indexes When a column that contains an incrementally increasing value (like those provided by sequences) is indexed, there is a very poor distribution of that value across the B-tree, and hot spots can be introduced into the index. Reverse-key indexes can help eliminate these hot spots by providing a much wider distribution of values than would occur in a regular B-tree index. In this situation, simultaneous inserts requested by the users are done in the same leaf of the index. This will generate contention on the same Oracle block buffer. This problem is exacerbated when several tasks are initiated in parallel, all processing updates against the database. Another problem is the phenomena of « sliding » when the system deletes older numbers and inserts new ones. In this case, the index becomes increasingly large as the space occupied by the deleted index entries never gets reused. The answer to this situation is the reverse-key index whereby different index leafs is used, even if the key sequence is chronological. How to Create Reverse Key Indexes CREATE INDEX my_index ON my_table (my_fields) REVERSE; To make an existing index a reverse index use: ALTER INDEX index_name REBUILD REVERSE; Substitute no reverse if you want to rebuild you index as a non-reversed one. No options are without a certain cost. While reverse-key indexes can help in the distribution of data across an index, this very strength can be a weakness. Since the actual (non-reversed) values of the index are not stored sequentially in the index, index range-scans cannot be performed. Only fetch-by-key

84

and full index scans can be performed on a reverse-key index. Therefore, it is not a good idea to build a reverse-key index on a column that might use range-scans.

5- Function Based Indexes Function based indexes are really going to improve the performance of all those queries which use functions such as SUM, AVG in the select or when the where clause includes some kind of other function such as some mathematical calculation on two columns. Suppose you have an application that routinely selects the sum of the two columns SALARY and BONUS from the PAYMENTS table. In the past, such a select may have been fairly slow, because of the calculation being performed on the select. Now, however, the calculation is stored as part of the index, making the overall selection process that much quicker. How to Create Function Based Indexes CREATE INDEX my_ind ON payments (salary + bonus); So, this query would now utilize the index: SELECT employee_id FROM payments WHERE (salary + bonus) > 1000; You need to enable function-based indexes before you can use them, as follows: ALTER SESSION SET QUERY_REWRITE_ENABLED = true ALTER SESSION SET QUERY_REWRITE_INTEGRITY = trusted Or QUERY_REWRITE_INTEGRITY = TRUSTED QUERY_REWRITE_ENABLED = TRUE COMPATIBLE = 8.1.0.0.0 (or greater) Also, to use a function-based index: The must be analyzed before it can be used The query must be guaranteed not to need any NULL values from the indexed expression, since NULL values are not stored in indexes. 6- Descending Indexes Descending indexes are a special type of function-based index, in which index entries are sorted in descending order. Using the DESC clause does this. When creating an index, as in the example below: create index ix_desc on phonebook2(zip desc); There • • •

are a couple special considerations when using descending indexes: Descending indexes cannot be used on reverse indexes The DESC option is ignored if used in the creation of bitmap indexes The COMPATIBLE initialization parameter must be set to 8.1.0

Knowing when to Rebuild Indexes Where is the index now? In order to understand what we must do with the index, we must first get an idea of the current state of

85

the index. This can be accomplished by using the ANALYZE INDEX VALIDATE STRUCTURE command. Normally, the ANALYZE INDEX command creates either computed or estimated statistics for the index that can be seen in the DBA_INDEXES view. This action may produce unintentional side effects, especially if the index has not previously been analyzed. The VALIDATE STRUCTURE command can be safely executed without affecting the optimizer. The VALIDATE STRUCTURE command populates the SYS.INDEX_STATS table only. The SYS.INDEX_STATS table can be accessed with the public synonym INDEX_STATS. The INDEX_STATS table will only hold validation information for one index at a time. You will need to query this table before validating the structure of the next index. Below is an example of ANALYZE INDEX VALIDATE STRUCTURE and sample output from INDEX_STATS: ANALYZE INDEX shopping_basket_pk VALIDATE STRUCTURE; SELECT name,height,lf_rows,lf_blks,del_lf_rows,distinct_keys,used_space FROM INDEX_STATS; NAME HEIGHT LF_ROWS LF_BLKS DEL_LF_ROW DISTINCT_K USED_SPACE ------------------------- --------- ---------- ---------- ---------- ---------- ---------SHOPPING_BASKET_PK 2 1 3 1 1 65 I have the information, now what? There are two rules of thumb to help determine if the index needs to be rebuilt. If it is determined that the index needs to be rebuilt, this can easily be accomplished by the ALTER INDEX REBUILD command. Although not necessarily recommended, this command could be executed during normal operating hours. Rebuilding the index uses the existing index as a basis. The alternative is to drop and re-create the index. Creating an index uses the base table as its data source that needs to put a lock on the table. The index is also unavailable during creation. First rule of thumb is if the index has height greater than four, rebuild the index. For most indexes, the height of the index will be quite low, i.e. one or two. I have seen an index on a 3 million-row table that had height three. An index with height greater than four may need to be rebuilt as this might indicate a skewed tree structure. This can lead to unnecessary database block reads of the index. It is helpful to know the data structure for the table and index. Most times, the index height should be two or less, but there are exceptions. The second rule of thumb is that the deleted leaf rows should be less than 20% of the total number of leaf rows. An excessive number of deleted leaf rows indicates that a high number of deletes or updates have occurred to the index column(s). The index should be rebuilt to better balance the tree. The INDEX_STATS table can be queried to determine if there are excessive deleted leaf rows in relation to the total number of leaf rows. Let’s look at an example: ANALYZE INDEX item_basket_pk VALIDATE STRUCTURE; SELECT name,height,lf_rows,del_lf_rows, (del_lf_rows/lf_rows)*100 as ratio FROM INDEX_STATS; NAME HEIGHT LF_ROWS DEL_LF_ROW RATIO ------------------------------ ---------- ---------- ---------- ---------ITEM_BASKET_PK 1 235 74 31.4893617 In this example, the ratio of deleted leaf rows to total leaf rows is clearly above 20%. This is a good candidate for rebuilding. Let’s rebuild the index and examine the results. ALTER INDEX item_basket_pk REBUILD; ANALYZE INDEX item_basket_pk VALIDATE STRUCTURE; SELECT name,height,lf_rows,del_lf_rows, (del_lf_rows/lf_rows)*100 as ratio

86

FROM INDEX_STATS; NAME HEIGHT LF_ROWS DEL_LF_ROW RATIO ------------------------------ ---------- ---------- ---------- ---------ITEM_BASKET_PK 1 161 0 0 The index is rebuilt and validated once again. Examining the INDEX_STATS table shows that the 74 deleted leaf rows were dropped from the index. Notice that the total number of leaf rows went from 235 to 161, which is a difference of 74 leaf rows. This index should provide better performance for the application.

Script to find indexes to rebuild Below is a sample script that can be run to determine which indexes need to be rebuilt. For those indexes that need to be rebuilt, the ALTER INDEX REBUILD command is dynamically generated as output. The user can tailor the height and percentage of deleted leaf rows by altering the vMaxHeight and vMaxDel variables. The output of this script can be spooled to a file. This file can then be run to rebuild the indexes. ----------

validate_idx.sql This script will check indexes to find candidates for rebuilding. Run this script in SQL*Plus as a user with SELECT ANY TABLE privileges. This script can be used and modified without permission. Run this script at your own risk! The script author is not responsible for any problems that may arise from running this script.

set serveroutput on size 100000 DECLARE vOwner dba_indexes.owner%TYPE; /* Index Owner */ vIdxName dba_indexes.index_name%TYPE; /* Index Name */ vAnalyze VARCHAR2(100); /* String of Analyze Stmt */ vCursor NUMBER; /* DBMS_SQL cursor */ vNumRows INTEGER; /* DBMS_SQL return rows */ vHeight index_stats.height%TYPE; /* Height of index tree */ vLfRows index_stats.lf_rows%TYPE; /* Index Leaf Rows */ vDLfRows index_stats.del_lf_rows%TYPE; /* Deleted Leaf Rows */ vDLfPerc NUMBER; /* Del lf Percentage */ vMaxHeight NUMBER; /* Max tree height */ vMaxDel NUMBER; /* Max del lf percentage */ CURSOR cGetIdx IS SELECT owner,index_name FROM dba_indexes WHERE OWNER NOT LIKE 'SYS%'; BEGIN /* Define maximums. This section can be customized. */ vMaxHeight := 3; vMaxDel := 20; /* For every index, validate structure */ OPEN cGetIdx; LOOP FETCH cGetIdx INTO vOwner,vIdxName; EXIT WHEN cGetIdx%NOTFOUND; /* Open DBMS_SQL cursor */

87

vCursor := DBMS_SQL.OPEN_CURSOR; /* Set up dynamic string to validate structure */ vAnalyze := 'ANALYZE INDEX ' || vOwner || '.' || vIdxName || ' VALIDATE STRUCTURE'; DBMS_SQL.PARSE(vCursor,vAnalyze,DBMS_SQL.V7); vNumRows := DBMS_SQL.EXECUTE(vCursor); /* Close DBMS_SQL cursor */ DBMS_SQL.CLOSE_CURSOR(vCursor); /* Does index need rebuilding? */ /* If so, then generate command */ SELECT height,lf_rows,del_lf_rows INTO vHeight,vLfRows,vDLfRows FROM INDEX_STATS; IF vDLfRows = 0 THEN /* handle case where div by zero */ vDLfPerc := 0; ELSE vDLfPerc := (vDLfRows / vLfRows) * 100; END IF; IF (vHeight > vMaxHeight) OR (vDLfPerc > vMaxDel) THEN DBMS_OUTPUT.PUT_LINE('ALTER INDEX ' || vOwner || '.' || vIdxName || ' REBUILD;'); END IF; END LOOP; CLOSE cGetIdx; END; /

Database Comparision Table of Contents 1.Introduction 2.Operational Concerns a.Scalability b.Platform Availability c.Networking & Internet Readiness 3.Vendor Related Issues a.Licensing

88

b.Support and Maintenance 4.User Considerations a.DBA Concerns b.Programmability 5.Conclusion Appendix A - System Requirements for Microsoft SQL Server 7.0 Appendix B - Maximum Sizes and Numbers of SQL Server 7.0 Appendix C - Scorecard of Microsoft’s SQL Server & Oracle’s 8i Appendix D - Summary of Features of Microsoft’s SQL Server & Oracle’s 8i Appendix E - Oracle 8 and Oracle 8i Standard Edition Platform Availability

SQL Server 7.0 Introduction SQL Server 7.0 is designed to scale from laptop databases and small business servers all the way up to terabyte-size databases.SQL Server 7.0 is designed to operate on Microsoft’s Windows 95, 98 and NT operating systems.However, the Windows 95 & 98 versions of SQL Server 7.0 only support desktop, laptop and small workgroup applications.SQL Server 7.0 for Windows NT Workstation has been developed for applications that involve a large numbers of users and transactions. Microsoft SQL Server had 30% of the Windows NT database market in 1998, while Oracle had 46.1% of the Windows NT market, which was a 55% growth in 1998.This statistic must be understood in the context that it applies only to the Windows NT platform, since that is the only platform that both Microsoft and Oracle have in common. Although, Microsoft has taken a big step forward in enterprise capability with the SQL Server 7.0, it seems like their product is more appropriate for departmental and small to mid-sized companies.“Rewritten for ease of use, Microsoft’s SQL Server 7.0 is far and away the best choice for smaller organizations or branch offices that need a full-featured relational database.Larger organizations will find SQL Server a better performer than ever before, although competing databases including Oracle 8 and DB2 continue to provide better programmability and scalability.”[ii] In speaking with a few experienced database administrators and programmers, SQL Server really is not known as a competitor with the “big boys” of the relational database software market.The well-known database software products include Oracle, IBM’s DB2, Sybase and Informix.These companies remain leaders in database technology at the enterprise level. Oracle 8i Introduction Oracle 8i is a database product that is built upon a mature Oracle 8 product, but also brings increased capabilities to develop and integrate with Internet applications.Oracle’s databases have been developed and proven to handle the largest of enterprise databases.But Oracle also targets smaller, mid-tier companies who find it necessary to have 24 hours by 7 days availability due to increasing Internet business needs.Oracle’s 8i databases are available on a wide variety of platforms.Dell, IBM, Linux, Sun, Fujitsu and Unisys are a few of the 21 listed on Oracle’s web site.

89

Oracle’s products are definitely not the cheapest on the market. If an evaluation of the application necessitates a high need for reliability, scalability, security and performance then Oracle should be considered. Oracle is the world’s leading supplier of software for information management, holding 27% of the database market share across all platforms.Oracle is the undisputed database leader on UNIX platforms, commanding 60.9% of the market share according to Dataquest.[iii],[iv] 2.Operational Concerns a. Scalability Scalability in the context of database software is defined as the software’s ability to continue to perform at a similar level with a larger amount of data and a growing number of users and transactions. Amount of Data Both SQL Server 7.0 and Oracle 8i are designed to be client-server database products that can take advantage of distributed database architecture. A distributed database is a network of databases managed by multiple database servers that appears to a user as a single database. This means the database could be distributed across several disks and servers with multiple processors.The data of all databases in the distributed databases can be simultaneously accessed and modified. The database architecture on the server will dictate how fast the transaction response time is.The speed of transactions can vary greatly based on the database design as well as server hardware configurations, including RAM, the number and speed of the CPUs. SQL Server 7.0 can grow up to 1,048,516 terra-bytes.Microsoft uses SMP (systems with 4 processors) technology to distribute databases. Other maximum sizes and numbers can be referenced in Appendix C, which outlines other technical specifications of SQL Server 7.0. Oracle 8i is scalable up to hundreds of terabytes to manage very large databases (VLDB).Oracle takes advantage of distributed processing and storage capabilities through architectural features that use more than one processor to divide the processing for a set of related jobs.This distributed architecture is a good example of the expression “the sum of the parts is greater than the whole”, because as individual processors work on a subset of related tasks, performance of the whole system is improved.

Number of Simultaneous Users Theoretically, there is no limit to the number of users that can access either the Oracle 8i or SQL Server 7.0 database servers at one time, given infinite processors and infinite speed.In practical terms, there is a limit, but it should not pose any real issues to be concerned with in terms of concurrent data.One consideration is that SQL Servers will require ODBC software to connect with clients that are not PC based.This will require some overhead, but should be pretty negligible. In a “Score Card” published by ZDNet[v], which is fully documented in Appendix D, the following ratings were published.These ratings really demonstrate the equality of SQL Server and Oracle for these performance criteria.

Server Engine Support for multiple CPUs

PC Microsoft SQL Server 7.0 Excellent Excellent

Oracle8i Standard Edition Good Fair

90

Join and index selection Degree of concurrency Database Design Distributed transactions

Excellent Good Good Excellent

Excellent Excellent Excellent Excellent

These issues of are fundamental topics when performance is being discussed. b.Platform Availability As discussed in the Introduction, SQL Server 7.0 is designed to operate on Microsoft’s Windows 95, 98 and NT 4.0 operating systems.However, the Windows 95 & 98 versions of SQL Server 7.0 will only support desktop, laptop and small workgroup applications and requires an Intel platform. SQL Server 7.0 for Windows NT Workstation has been developed for applications that involve a large numbers of users and transactions and is limited to Intel or Alpha platforms. This limitation could cause hurdles for large corporations in terms of performance that can be expected.Brian McCarthy, CEO of Insurance Holdings said “Microsoft said we’d need an all-Microsoft application if we wanted full scalability, but who’s going to rebuild the whole system?”[vi] It’s especially important to note that although other platforms can be used for clients to access the SQL Server 7.0, a third party ODBC software must be used.ODBC is an interface that allows for data to be accessed in relational databases, independent of the database vendor. Oracle 8i is supported by a large number of hardware manufacturers, as well as several operating systems.There are currently 21 hardware vendors listed on Oracle’s website, with at least 6 operating systems, counting UNIX as one although the flavors may vary by manufacturer.Reference Appendix F for details on some of the platforms and operating systems that Oracle runs on.Further details can be found on specific platforms at Oracle’s dedicated website:www.platforms.oracle.com.

Networking & Internet Readiness The need for a database to be Internet ready is quickly becoming a necessity in today’s rapidly growing web based world. At every turn in the software industry, the topic of e-business and ecommerce is a top issue for companies wanting to compete in the future. Therefore, the need for database software to support and enhance Internet application development is a must.

SQL Server 7.0 still lags behind in its ability to support multimedia data support and in programmability, which are necessary for many Internet applications. Third party software will have to be used to store special images, sound, video or geographic data support. SQL Server 7.0 doesn’t support Java, which is an industry standard for developing network applications.

Oracle 8i is the best product for companies wanting to move their database applications to the Web. Oracle leads the market in handling of multimedia objects. Multimedia support is particularly relevant when building Web-based applications like online stores that include

91

multimedia items such as pictures or video clips of items for sale. Oracle uses a product call JServer, which brings Java and relational databases together. It allows for controlling the database through Java and supports the creation of JavaBeans. JavaBeans are the basic building blocks for Java-based Internet applications, and are (or will be) supported by just about every high-end Internet application server on the market. In the ZDNet Scorecard (Appendix D), SQL Server 7.0 and Oracle 8i were rated as follows, in respect to their internet readiness features:

Microsoft SQL Server 7.0 Multimedia Data Poor Handling

Oracle8i Standard Edition Excellent

Web connectivity

Poor

Excellent

Support for sound, media, video, images

Poor

Excellent

Full text search

Good

Excellent

3. Vendor Related Issues a.Licensing SQL Server Pricing structures of software can be complex.Microsoft recognizes this and even offers “A Guide to BackOffice Pricing and Licensing” to help readers understand some of the subtleties and complexities before “cutting a check”. SQL Server can be purchased by itself in either of the above-mentioned versions, as an upgrade to certain other database products or as a part of Microsoft BackOffice.A license for the server is distinct from the licenses for the CAL (client access license), but every server is accompanied with a certain number of CALS.Although the number of CALS may vary by application, there would always be a need for at least one CAL or the database could not be accessed to retrieve data. To compare prices the details of the system architecture must be well understood.Some of those details include the number of servers required to support the database, how many processors a server will have, the number of users needing to access the database, whether the system will be serving an Internet or intranet application. Based on an application where 250 or more users (CALs) will be accessing one database server, the cost of SQL Server 7.0 Enterprise Version is listed as $28,999 on Microsoft web site.To get an understanding of the price differences between the Enterprise version and the Standard version, SQL Server 7.0 Standard Version and Five CALs would cost $3,999, while the Enterprise version with Five CALs lists at $7999.An upgrade of the SQL Server 7.0 Enterprise version for a customer who is also upgrading the clients accessing the database costs $3969, while a customer who is buying licenses for new clients along with the server license costs $7099. The benefits of the Enterprise Edition over the Standard Edition cited in the Microsoft publications get blurred in the marketing jargon.The Enterprise version is used for increased system scalability and reliability by providing support for SMP (systems with multiple processors) and extended memory These prices are negotiable and the price varies in terms of how customer acquires the SQL Server.For example, if a customer purchases software that runs on SQL Server or purchases it from an independent software vendor then the pricing would obviously be different.

92

Oracle 8i Oracle’s pricing structure is different from Microsoft’s, in that it doesn’t charge per server license or client access license.Rather Oracle charges by licensing units:“named user”, “concurrent system” and “power unit”. A named user is defined as “an individual who is authorized by his/her company to use the Oracle Software programs, regardless of whether the individual is actively using these programs at any given time.”[vii] A concurrent device is defined as “an input device accessing the program on the designated system at any given point in time. The number of "Concurrent Devices" you are licensed for is the maximum number of input devices accessing the programs on the Designated System at any given point in time. If multiplexing hardware or software (e.g., a TP Monitor or a Web server product) is used, this number must be measured at the multiplexing front-end.”vii A power unit is defined as one MHz of power in any Intel compatible or RISC processor in any computer of the Designated Systems on the Order Confirmation page on which the Oracle software programs are installed and operating. (Intel refers to Intel Solaris, Linux, and Windows NT; RISC refers to Sun SPARC Solaris, HP-UX, and IBM/AIX. A "Processor" license shall be for the actual number of processors installed in the licensed computer and running the Oracle program(s), regardless of the number of processors which the computer is capable of running.)”vii A named user licensing unit costs $600, a concurrent device costs $1495 and a power unit costs $200 for the Oracle 8i Enterprise Edition.These prices are 5 times more than what Oracle charges for the Standard Edition. The Enterprise Editions includes these advanced features on top of the Standard Edition:large-database partitioning (which helps you keep monster gigabyte-size databases under control), flexible security features, and speed features such as bitmapped indexes, summary tables, and parallelism. Two other modules that Oracle offers for enhanced web integration and multi-media handling are Oracle JServer Standard Edition and WebDB, which if necessary add to the total cost of the Oracle solution.They are also priced based on the licensing unit discussed above. b.Support and Maintenance Availability of qualified database administrators (DBA) and programmers is one issue that cannot be overlooked in considering which database will be best for the given organization and application.Due to the relationship between supply, demand and cost, the shortage of Oracle DBAs and programmers can mean only mean one thing.They are hard to find and when one is available, they command a very high salary. The nature of Oracle is that it can be more difficult to program and administer, so it requires specially trained personnel.SQL Server, on the other hand, is an easier product to learn and administer so the number of available programmers is higher and less expensive to staff a database project. No cost information could be obtained on the annual maintenance fees to remain current on the licensing agreements with either Oracle or SQL Server. 4. User Considerations a. Database Administrator (DBA) Concerns Recovery & Backup

93

In every database system, the possibility of a system or hardware failure always exists. Should a failure occur and affect the database, the database must be recovered. The goals after a failure are to ensure that the effects of all committed transactions are reflected in the recovered database and to return to normal operations as quickly as possible while insulating users from problems caused by the failure. Databases can fail due power outages, operating system crashes, disk failure or operator error.

Both SQL Server 7.0 and Oracle make commitments on a two-phase commit approach, which allows for users to control a logical set of SQL statements so they all either succeed or fail as a unit. This two-phase mechanism guarantees that no matter what type of system or network failure might occur, a distributed transaction either commits on all involved nodes or rolls back on all involved nodes to maintain data consistency across the global distributed database. Monitoring & Tuning Capabilities SQL Server 7.0 is an exceptionally easy product to administer and is more forgiving than previous SQL Server versions.SQL Server 7.0 has an auto-tuning feature that allows for memory to be self-managed and there are several new wizards that simply advanced tasks such as creating databases, scheduling backups, importing and exporting data and configuring replication.This should make the training of database administrators much easier. Oracle 8i databases can be administered and controlled very tightly, but it is a complex and requires trained database administrators to do so proficiently.“Oracle8i tools are Java-based and can even be run from a Web browser. They provide all the essentials for designing and setting up a database, including some advanced features like letting you selectively delegate authority to users of its Enterprise Manager administration console. This is a handy tool for branch office deployment.Like previous releases of Enterprise Manager, though, this one is a version behind the database, and it doesn't know a thing about new Oracle8i features such as Java stored procedures.”[viii] b.Programmability There are languages supported within the database software for programming and controlling the database.For example, since PL/SQL can be stored in the database, network traffic between applications and the database is reduced, thereby increasing application and system performance. SQL Server 7.0 comes with an internal programming language called Transact-SQL, which has received a poor rating in several reviews.“While everyone else in the SQL database market is moving (or has already moved) to a modern programming language like Java, SQL Server customers are still stuck in the programming Dark Ages—no object orient development, no big class libraries to use, and no code interoperability with anything else.”[ix]The programming can be done, but it will require a lot more work. Oracle gets an excellent rating for it’s internal language offerings, which include Java and PL/SQL.

5.Conclusion In comparing these two database products, it became apparent they each hold a different place and purpose in the market.They don’t compete in the same niche.Microsoft SQL Server, a client-server database, continues to make strides toward the enterprise database market, but is still most appropriate for a departmental or small to mid-sized company whose database doesn’t have such high scalability, reliability and availability needs.SQL Server’s greatest weakness is the Windows NT platform, which it operates on, is not mature enough to provide the kind of availability that enterprise worthy systems require.“In the small-business market, the differentiating factors are ease of database administration, Web connectivity, the speed and features of the database server engine, branch-office and mobile support, and

94

the ability to warehouse data efficiently. SQL Server 7.0 shines in all of these areas except Web connectivity. Its administration tools include many wizards and self-tuning settings that make it the only database we reviewed that might not require a specially trained administrator.”[x] Oracle, also a client-server database, operates on the high end of the database market and is also reaching out to start ups, small to medium sized businesses who have a need for a complete, integrated platform for critical applications for the internet. Oracle is harder to administer is an expensive choice, unless the application being developed requires its Java or multimedia features.Another selling point to Oracle is that is it sold on a multitude of platforms, in comparison to SQL Server 7.0, which may be appealing to some customers who are seeking a more mature platform.

Appendix A System Requirements for Microsoft SQL Server 7.0* Client Access Licenses required Server  

PC with a Pentium (166 MHz or higher) or Alpha processor Microsoft Windows NT Server operating system version 4.0 or Windows NT Server 4.0 Enterprise Edition with Service Pack 4 or later (Service Pack 4 included)



Microsoft Internet Explorer 4.01 with Service Pack 1 or later (both included)



32 MB of RAM



Hard-disk space required: 

65–180 MB for Server; approximately 170 MB for typical installation



35–50 MB for OLAP services; approximately 50 MB for typical installation



24–36 MB for English Query; approximately 36 MB for typical installation



CD-ROM drive



VGA or higher-resolution monitor; Super VGA recommended



Microsoft Mouse or compatible pointing device

Note SQL Server 7.0 can utilize up to four processors. Additional processor support is available with SQL Server 7.0 Enterprise Edition. Desktop Identical to Server requirements with the following exceptions:

95



Each installation of SQL Server Desktop requires a per-seat client access license for SQL Server 7.0; SQL Server Desktop will only interact with SQL Server in per-seat mode



65–180 MB available hard-disk space; approximately 170 MB for typical installation Note The Desktop version of SQL Server 7.0 can utilize up to two processors.

Networking Support Windows 95, Windows 98, or Windows NT built-in network software (additional network software is not required unless you are using Banyan VINES or AppleTalk ADSP; Novell NetWare client support is provided by NWLink) Clients Supported Windows 95, Windows 98, or Windows NT Workstation, UNIX,** Apple Macintosh,** and OS/2** *Actual requirements will vary based on your system configuration and the features you choose to install. **Requires ODBC client software from a third-party vendor.

Appendix B Maximum Sizes and Numbers of SQL Server 7.0 This table specifies the maximum sizes and numbers of various objects defined in Microsoft SQL Server databases, or referenced in Transact-SQL statements.

Object Batch size Bytes per character or binary column

SQL Server 7.0 128 *Network Packet Size 8000

Bytes per text, ntext, or image column

2GB-2

96

Bytes per GROUP BY, ORDER BY

8060

Bytes per index Bytes per foreign key Bytes per primary key Bytes per row Bytes in source text of a stored procedure Clustered indexes or constraints per table Columns in GROUP BY, ORDER BY

900 900 900 8060 Batch size

Columns or expressions in a GROUP BY WITH CUBE or WITH ROLLUP statement Columns per index Columns per foreign key Columns per primary key Columns per base table Columns per SELECT statement Columns per INSERT statement Connections per client

1 Limited only by number of bytes 10

Database size Files per database File size (data) Object File size (log) FOREIGN KEY constraints per table

16 16 16 1024 4096 1024 Max. value of configured connections 1,048,516 TB 32,767 32 TB SQL Server 7.0 4 TB 63

Foreign key table references per table

63

Identifier length (in characters) Index key size (bytes) Locks per connection

128 900 Max. value of locks configured 64 32 250

Nested subqueries Nested trigger levels Nonclustered indexes or constraints per table Objects in a database * Parameters per stored procedure

2,147,483,647 1024

PRIMARY KEY constraints per table

1

Rows per table

Limited by available storage 128 *TDS packet size Limited by number of objects in a database 256 Limited by number of objects in a database

SQL string length Tables per database Tables per SELECT statement Triggers per table

97

UNIQUE constraints per table

250 nonclustered and 1 clustered

* Database objects include all tables, views, stored procedures, extended stored procedures, triggers, rules, defaults, and constraints.

Appendix C Scorecard of Microsoft’s SQL Server & Oracle’s 8i

Server Administration Graphical tools Ease of maintenance Server Engine Support for multiple CPUs Join and index selection Degree of concurrency Multimedia Data Handling Web connectivity Support for sound, media, video, images Full text search Interoperability Links with other databases Single log-on Operating-system support Programmability Stored procedures and triggers Internal programming language Database Design SQL language support Object-oriented design Branch Office Support Replication Distributed transactions Remote administration Data Warehousing and Reporting Loading tools

PC Microsoft SQL Server 7.0 Excellent Excellent Excellent Excellent Excellent Excellent Good Poor Poor Poor

Oracle8i Standard Edition

Good Good Good Good Fair Fair Good

Excellent Fair Poor Good Good Excellent Excellent

Poor

Excellent

Good Excellent Poor Excellent Excellent Excellent Good Excellent

Excellent Excellent Excellent Excellent Excellent Excellent Excellent Excellent

Excellent

Excellent

Good Good Good Excellent Good Excellent Excellent Excellent Excellent Excellent

98

Appendix D Summary of Features of Microsoft’s SQL Server & Oracle’s 8i

Microsoft SQL Server 7.0 List price Number of users included Price for each additional concurrent user / named user Server operating-system support Client software operating-system support Network protocols supported ADMINISTRATION Graphical tools for: Installing the database server Creating and managing databases/disk devices Creating and managing tables/indexes Creating and managing stored procedures Creating and managing users Creating and managing replication links Backup and restore Web publishing Database diagramming Submitting SQL and viewing query results Viewing all currently executing SQL code Detecting resource-intensive queries/Killing queries Graphing server engine statistics Execution plan display Providing index suggestions based on a single SQL statement/on overall server usage Tools have command line access Reverse-engineer database objects/data to a SQL script Languages supplied for command scripting Security audit log of administrator and user activity Job scheduler can run jobs at certain times/when certain events happen Online manual with search engine SERVER ENGINE Levels of locking granularity available Default locking level for queries

$1,399 5 users (named or concurrent) $127 / $127 Windows NT, Windows 9x

Oracle 8i Standard Edition $3,925 per CPU 5 concurrent users $785 / $392.50

AppleTalk, IPX, Named Pipes, TCP/IP, Vines IP

Windows NT, multiple Unix flavors All server platforms plus Windows 9x IPX, Named Pipes, TCP/IP

Yes Yes Yes

Yes Yes Yes

Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes

Yes Yes Yes Yes Yes Yes Yes Optional Yes Optional Yes Yes

Yes Yes Yes Yes

Yes Optional Optional Optional

Yes Yes No

Yes Yes Optional

JScript, OS commands, SQL, Transact-SQL, VB Script No

Java, OS commands, PL/SQL, SQL, TCL Yes

Yes Yes

Yes Yes

Yes

Yes

Database, table, page, row Row

Database, table, row Row

Windows NT, Windows 9x

99

Readers can block writers/writers can block readers at default isolation level Can use multiple CPUs on database load/within a query/to create an index Can use multiple CPUs on database backup and restore/on update/on delete Nested loop join/Hash join/Merge join Semi-join for star queries B-tree index/Clustered index/Bitmap index Cost-based/rule-based optimizer Can use multiple indexes per query Can use just the index to answer the query Automatically maintains necessary optimizer statistics Dynamic SQL statements parameterized and cached Can mark tables as memory-resident Dynamic memory resource sharing Number of CPUs supported per server Failover server Query resource consumption governor Can assign priorities to different groups of users Incremental backup/Restore to a specified point in time Default disk data block size Users can choose disk block size Parallel/asynchronous (multitasking) disk operations Data and log devices can grow when needed Year 2000-certified/Euro support MULTIMEDIA DATA TYPES Binary large object (BLOB) Sound/Video/Images Text documents/Geospatial data/Time series INTEROPERABILITY Gateways to other databases Single log-on with Windows NT / LDAP / OSF DCE PROGRAMMABILITY Stored procedures/triggers Internal programming languages Debugger supplied for stored procedure languages Database client libraries supported

QUERY LANGUAGE AND DATABASE DESIGN SQL language version supported ANSI isolation levels supported Left/right/full outer joins Declarative referential integrity

No Yes

No No

Yes Yes No

Yes Optional Optional

Yes No No Yes Yes Yes Yes Yes Yes Yes** Yes No Yes Yes Yes

Optional Optional Optional Yes Yes Yes Yes Yes Yes Optional Yes Yes Yes Yes Yes

Yes

Yes

Yes Yes 4 Optional Yes No

Yes No 4 Yes Yes Optional

Yes Yes

Optional Optional

8K No Yes Yes

2K or 8K Yes Yes Yes

Yes

Yes

Yes Yes

Yes Yes

Yes No No No Yes No Yes**

Yes Yes Yes Yes Yes Yes Optional

ODBC, OLE DB Yes No No

Optional Yes Optional Optional

Yes Yes Transact-SQL Optional

Yes Yes Java, PL/SQL Optional

DB/LIB, ODBC, OLE DB

CORBA, Enterprise JavaBeans, JDBC, OCI, ODBC, Oracle Objects for OLE

SQL-92 Entry Level with extensions Read uncommitted, read committed, repeatable read, serializable, read only Yes Yes Yes Yes

SQL-92 Entry Level with extensions Read committed, serializable, read only Yes Yes Yes Yes

100

Cascade delete/Cascade update Object-oriented design support/Object references (REFs) BRANCH OFFICE SUPPORT One-way/bidirectional replication Pager/e-mail notification of errors Administration tools can manage a remote database Web-based administration tools provided Distributed transactions within database/with other vendors' databases DATA WAREHOUSING AND REPORTING Data loader can load directly to disk pages for speed Data transformation and cleansing tools Can delay constraint checking during a bulk load Provides precalculation of summary information Included OLAP server Queries automatically rewritten to use summary tables Summaries understand dimensional hierarchies Automatic refresh of summaries when data changes Can use data sampling to speed processing Top n queries/Top n percent of total queries Can handle ties when ranking top rows Cube/rollup functions

No No No No

Yes No Yes Yes

Yes Yes Yes Yes Yes

Yes Yes Yes Yes Yes

No Yes Yes

Yes Yes Yes

Yes

Yes

Yes Yes

Yes Yes

Yes**

Optional

Yes No

Optional Optional

Yes**

Optional

No

Optional

No Yes Yes Yes Yes Yes

Optional Yes No No Yes Yes

Appendix E Oracle 8 and Oracle 8i Standard Edition Platform Availability

Operating System

Chip

Hardware

Data General DG-UX

Intel

Any, up to 4 cpus *

Digital Unix

Alpha

Digital AlphaServer 300, 400, 800, 1000, 1000A Digital AlphaServer 1200, 2000, 4000

Hewlett-Packard HP-UX

PA-RISC

HP9000 7xx-Series wkstns HP9000 B-Series, C-Series wkstns

101

HP9000 D-Series, E-Series, A-Series HP9000 K360 K370 K380 R380 R390 IBM/

PowerPC

Bull/Motorola AIX

RS/6000 Models: 43P, 42T/42W, C10, C20, E30, F30, F40, F50, H10, H50, H70 Bull Estrella 200, 300, 700 Bull Escala E Motorola RISC PC Plus Series Motorola EX Series Motorola PowerStack II Pro2000, Pro3000, Pro4000

IBM OS/2

Intel

Any, up to 4 cpus *

Microsoft Windows NT

Alpha

Digital AlphaServer 300, 400, 800, 1000, 1000A Digital AlphaServer 1200, 2000, 4000

Intel

Any, up to 4 cpus *

MIPS

SNI RM200, RM300

NCR MP-RAS

Intel

NCR S10, S40

Novell NetWare

Intel

Any, up to 4 cpus *

SCO UnixWare

Intel

Any, up to 4 cpus *

Siemens Nixdorf

MIPS

SNI RM200, RM300

Sun Solaris Intel

Intel

Any, up to 4 cpus *

Sun Solaris SPARC

SPARC

SGI IRIX

MIPS

Any uniprocessor or dual processor only machine from Sun, and the Sun E450 up to 4 cpus O2, Octane, Origin200 (Single Tower Only)

SINIX/Reliant UNIX

* includes Compaq ProLiant and ProSignia, HP NetServer, IBM Netfinity, and any other Intelbased server with up to 4 cpus.

[i]

Dyck, Timothy. “Mission Critical.” PC Magazine.July 30, 1999.November 1, 1999 ')); select extractValue(xml_data, '/FAQ-LIST/QUESTION/RESPONSE') -- XPath expression from XMLTable where existsNode(xml_data, '/FAQ-LIST/QUESTION[QUERY="Question 1"]') = 1;

The XML Developer Kit Beginning with the first release of Oracle 8i, Oracle has offered the XDK for the Oracle database. For Oracle 8i releases 1 and 2 (8.1.5 and 8.1.6) you must download the XDK from Oracle Technology Network and install it manually. With Oracle 8i release 3 (8.1.7) and Oracle 9i, the XDK is integrated into the database and is installed automatically when the database is installed. The XDK may be accessed from PL/SQL, Java, C, and C++ applications. PL/SQL applications must run inside the database (i.e. stored procedures, packages, triggers, or anonymous PL/SQL blocks) in order to access the XDK. Java applications may reside inside or outside the database. C and C++ applications, of course, reside outside the database. In order to access the XDK from PL/SQL or Java applications residing inside the database, you must install Oracle’s JVM (sometimes called the Java option or Oracle JServer). It may seem counter-intuitive that you must have Oracle’s JVM installed in order to use the XDK from PL/SQL, but there is a reason for it: The XDK is itself written in Java. Oracle merely put PL/SQL wrappers on the Java code in order to make it accessible from PL/SQL. The XDK contains an XML parser, an XSLT processor, an XPath engine, an XSQL page processor and servlet, and an XML SQL utility. The first three are Oracle’s implementations of the XML 1.0 specification, while the last two are features unique to Oracle. Note that the XSQL page facility is only accessible from Java applications. Also note that in earlier releases of the XDK, the XML SQL utility was a separate tool that you had to install separately from the XDK. You can download the XML SQL utility from Oracle Technology Network.

Hello! Could you elaborate the example of serializing the XML into a table, let's say the XML file has data which corresponds to 2 tables (repetitive tags for a detail table), is it possible?

110

Followup: Sean here... This is pretty easy to accomplish. There is no automated XML utility in Oracle to insert a single XML document into two different tables... What you could do, however, is create a join view on the two tables, then write an INSTEAD OF trigger on the join view. Insert the XML document into the join view. The INSTEAD OF trigger's job would be to insert rows into the appropriate tables based on the values of the parent key found in each ROWSET of the XML document. As an example, I have an XML document that looks like SO: 10 SALES 100 MARK JOHNSON 20 TECHNOLOGY 200 TOM KYTE 20 TECHNOLOGY 300 SEAN DILLON So you can see... the department data and the employee data co-mingled. We want to normalize this into two tables... so here's what I'd do: ----------------------------system@SLAP> create table dept ( 2 deptno number 3 primary key, 4 dname varchar2(30)); Table created. system@SLAP> create table emp ( 2 empno number 3 primary key, 4 deptno number, 5 ename varchar2(30)); Table created. system@SLAP> create view deptemp as 2 select d.deptno, d.dname, e.empno, e.ename 3 from dept d, emp e 4 where d.deptno = e.empno; View created.

111

system@SLAP> create or replace trigger deptemp_ioifer 2 instead of insert on deptemp 3 declare 4 begin 5 begin 6 insert into dept (deptno, dname) 7 values (:new.deptno, :new.dname); 8 exception 9 when DUP_VAL_ON_INDEX then 10 update dept 11 set dname = :new.dname 12 where deptno = :new.deptno; 13 end; 14 -15 insert into emp (empno, deptno, ename) 16 values (:new.empno, :new.deptno, :new.ename); 17 end; 18 / Trigger created. system@SLAP> declare 2 l_clob clob := ' 3 4 5 10 6 SALES 7 100 8 MARK JOHNSON 9 10 11 20 12 TECHNOLOGY 13 200 14 TOM KYTE 15 16 17 20 18 TECHNOLOGY 19 300 20 SEAN DILLON 21 22 '; 23 24 l_ctx dbms_xmlsave.ctxType; 25 l_rows number; 26 begin 27 l_ctx := dbms_xmlsave.newContext('DEPTEMP'); 28 l_rows := dbms_xmlsave.insertxml(l_ctx,l_clob); 29 dbms_xmlsave.closeContext(l_ctx); 30 dbms_output.put_line(l_rows || ' rows inserted...'); 31 end insert_xml_emps; 32 / PL/SQL procedure successfully completed. system@SLAP> select * from dept; DEPTNO DNAME

112

---------- -----------------------------10 SALES 20 TECHNOLOGY system@SLAP> select * from emp; EMPNO DEPTNO ENAME ---------- ---------- -----------------------------100 10 MARK JOHNSON 200 20 TOM KYTE 300 20 SEAN DILLON ----------------------------...and there you have it. Hope that helps!

How can I handle this? One row for the department table and 3 rows for the employee table in the same XML row. 10 SALES 100 MARK JOHNSON 200 VICTOR JAEN 300 JHON SMITH Thanks a lot! Followup: 1* select dbms_xmlgen.getxml( 'select deptno, dname, cursor( select empno, ename from emp where emp.deptno = dept.deptno ) employee from dept where deptno = 10' ) from dual scott@ORA920> / DBMS_XMLGEN.GETXML('SELECTDEPTNO,DNAME,CURSOR(SELECTEMPNO,ENAMEFROMEMPWHEREEMP.D ------------------------------------------------------------------------------- 10 ACCOUNTING

113

7782 CLARK 7839 KING 7934 MILLER

Oracle 9i and 8i Database Limits Oracle8i ONLY Advanced Queuing Processes

maximum per instance

Oracle8i ONLY Job Queue Processes I/O Slave Processes

maximum per instance maximum per background process (DBWR, LGWR, etc.)

36 15 15

10

114

32K, limited by PROCESSES and SESSIONS init parameters

LCK Processes

maximum per Backup session maximum per instance maximum per instance

MTS Servers

maximum per instance

Unlimited within constraints set by PROCESSES and SESSIONS init parameters, for instance

Dispatchers

maximum per instance maximum per instance

Unlimited within constraints set by PROCESSES and SESSIONS init parameters, for instance. Unlimited within constraints set by PROCESSES and SESSIONS init parameters, for instance.

maximum per instance

Unlimited within constraints set by PROCESSES and SESSIONS init

Sessions

Parallel Execution Slaves Backup Sessions

10

parame

ters, for instance.

Oracle 9i Limits

Datatype Limits VARCHAR2 NVARCHAR2 NUMBER( p,s) LONG DATE TIMESTAMP( fractional_seconds_precision)

TIMESTAMP( fractional_seconds_precision) WITH TIME ZONE TIMESTAMP( fractional_seconds_precision)WITH LOCAL TIME ZONE INTERVAL YEAR( year_precision) TO MONTH

INTERVAL DAY (day_precision) TO SECOND ( fractional_seconds_precision)

Maximum size is 4000 Maximum size is determined by the national character set definition, with an upper limit of 4000 bytes The precision p can range from 1 to 38. The scale s can range from -84 to 127 up to 2 gigabytes, or 231 -1 bytes range from January 1, 4712 BC to December 31, 9999 AD fractional_seconds_precisionis the number of digits in the fractional part of the SECOND datetime field. Accepted values of fractional_seconds_precision are 0 to 9. The default is 6 fractional_seconds_precisionis the number of digits in the fractional part of the SECOND datetime field. Accepted values are 0 to 9. The default is 6 same as TIMESTAMP( fractional_seconds_precision) WITH TIME ZONE year_precision is the number of digits in the YEAR datetime field. Accepted values are 0 to 9. The default is 2 day_precision is the maximum number of digits in the DAY datetime field. Accepted values are 0 to 9. The default is 2 fractional_seconds_precision is the number of digits in the fractional part of the SECOND field. Accepted values are 0 to 9. The default is 6

115

RAW( size) LONG RAW ROWID

Maximum size is 2000 bytes up to 2 gigabytes Base 64 string representing the unique address of a row in its table Base 64 string representing the logical address of a row of an index-organized table. The optional size is the size of a column of type UROWID. The maximum size and default is 4000 bytes Fixed-length character data of length size bytes.Maximum size is 2000 bytes. Default and minimum size is 1 byte Fixed-length character data of length size characters. Maximum size is determined by the national character set definition, with an upper limit of 2000 bytes. Default and minimum size is 1 character Maximum size is 4 gigabytes Maximum size is 4 gigabytes Maximum size is 4 gigabytes Maximum size is 4 gigabytes

UROWID [( size)]

CHAR( size)[BYTE |CHAR]

NCHAR( size)

CLOB NCLOB BLOB BFILE

Physical Database Limits Database Block Size

Minimum

Database Blocks

Maximum Operating system dependent; never more than 32 KB Minimum in initial 2 blocks extent of a segment

Controlfiles

Database files

Maximum per datafile Number of control files

2048 bytes; must be a multiple of operating system physical block size

Platform dependent; typically 222-1 blocks 1 minimum; 2 or more (on separate devices) strongly recommended

Size of a control file Dependent on operating system and database creation options; maximum of 20,000 x (database block size) Maximum per Operating system dependent; usually 1022 tablespace Maximum per database

65533. May be less on some operating systems Limited also by size of database blocks and by the

116

Database extents

Maximum

Database file size

Maximum

MAXEXTENTS

Default value

Redo Log Files

Redo Log File Size Tablespaces

DB_FILES initialization parameter for a particular instance 2 GB, regardless of the maximum file size allowed by the operating system Operating system dependent. Limited by maximum operating system file size; typically 222 or 4M blocks Derived from tablespace default storage or DB_BLOCK_SIZE initialization parameter

Maximum Unlimited Maximum number of Limited by value of MAXLOGFILES parameter in the logfiles CREATE DATABASE statement. Control file can be resized to allow more entries; ultimately an operating system limit Maximum number of logfiles per group Unlimited Minimum size 50 KB Maximum size Operating system limit; typically 2 GB Maximum number 64 KB Number of tablespaces cannot exceed the per database number of database files, as each tablespace must include at least one file

Logical Database Limits GROUP BY clause

Maximum length

Indexes

Maximum per table total size of indexed column

Columns

Constraints Subqueries

Partitions

Per table Per index (or clustered index) Per bitmapped index Maximum per column

The GROUP BY expression and all of the nondistinct aggregates functions (for example, SUM, AVG) must fit within a single database block. Unlimited 75% of the database block size minus some overhead 1000 columns maximum 32 columns maximum 30 columns maximum Unlimited

Maximum levels of subqueries Unlimited in the FROM clause of the top-level in a SQL statement query; 255 subqueries in the WHERE clause Maximum length of linear 4 KB - overhead partitioning key Maximum number of columns 16 columns in partition key Maximum number of

64 K-1 partitions

117

Rollback Segments

Rows SQL Statement Length

partitions allowed per table or index Maximum number per No limit; limited within a session by database MAX_ROLLBACK_SEGMENTS initialization parameter Maximum number per table Unlimited

Stored Packages

Maximum length of statements Maximum size

Trigger Cascade Limit

Maximum value

64 KB maximum; particular tools may impose lower limits PL/SQL and Developer/2000 may have limits on the size of stored procedures they can call. The limits typically range from 2000 to 3000 lines of code. See Also: Your PL/SQL or Developer/2000 documentation for details Operating system-dependent, typically 32

Users and Roles

Maximum

2,147,483,638

Tables

Maximum per clustered table 32 tables Maximum per database Unlimited

Process and Runtime Limits Instances per database

Operating system-dependent

Locks

Maximum number of cluster database instances per database Row-level

SGA size

Distributed Lock Manager Maximum value

Advanced Queuing Processes Job Queue Processes

Maximum per instance Maximum per instance

Operating system dependent Operating system-dependent; typically 2 to 4 GB for 32-bit operating systems, and > 4 GB for 64-bit operating systems 10 1000

I/O Slave Processes

Maximum per background process (DBWR, LGWR, etc.)

15

Sessions

Maximum per Backup session Maximum per instance

Global Cache Service Processes

Maximum per instance

15 32K; limited by PROCESSES and SESSIONS initialization parameters 10

Shared Servers

Maximum per instance

Dispatchers

Maximum per instance

Parallel Execution Slaves

Maximum per instance

Unlimited

Unlimited within constraints set by PROCESSES and SESSIONS initialization parameters, for instance Unlimited within constraints set by PROCESSES and SESSIONS initialization parameters, for instance Unlimited within constraints set by PROCESSES and SESSIONS initialization parameters, for instance

118

Backup Sessions

Maximum per instance

Unlimited within constraints set by PROCESSES and SESSIONS initialization parameters, for instance

Oracle 8i Limits Datatype Limits Datatypes BFILE

BLOB

Limit maximum size: 4GB maximum size of file name: 255 characters maximum size of open BFILEs: see comments 4GB maximum

CHAR CHAR VARYING CLOB

2000 bytes maximum 4000 bytes 4GB maximum

Literals (characters or numbers in SQL or PL/SQL LONG NCHAR NCHAR VARYING NCLOB

4000 characters maximum

NUMBER

999...(38 9's)x10 to power of 25 maximum value -999...(38 9's)x 10 to power of 125 minimum value 38 significant digits 2000 bytes maximum 4000 bytes maximum 4000 bytes maximum

Precision RAW VARCHAR VARCHAR2

Comments The maximum number of BFILEs is limited by SESSION_MAX_OPEN_FILES, which is itself limited by the maximum number of open files the operating system will allow. The number of LOB columns per table is limited only by the maximum number of columns per table (i.e., 1000)

The number of LOB columns per table is limited only by the maximum number of columns per table (i.e., 1000)

231-1 bytes (2GB) maximum 2000 bytes 4000 bytes 4GB maximum

Only one LONG column allowed per table

The number of LOB columns per table is limited only by the maximum number of columns per table (i.e., 1000) Can be represented to full 38-digit precision (the mantissa).

Physical Database Limits Item Database Block Size

Type of Limit minimum maximum

Database Blocks

Controlfiles

minimum in initial extent of a segment maximum per datafile number of controlfiles

Limit Value 2048 bytes; must be a multiple of O/S physical block size O/S-dependent never more than 32KB 2 blocks platform dependent; typically 2 to power of 22 blocks 1 minimum: 2 or more (on separate devices)

119

size of controlfile

Database files

maximum per tablespace maximum per database

Database file size

maximum

MAXEXTENTS

default value

Redo Log Files

maximum maximum number of

Redo Log File Size Tablespaces

strongly recommended dependent on O/S and database creation options; maximum of 20,000 x (database block size) O/S dependent, usually 1022 65533; may be less on some operating systems; limited also by size of database blocks, and by the DB_FILES init parameter for a particular instance O/S dependent, limited by maximum O/S file size; typically 2 to power of 22 or 4M blocks derived from tablespace default storage or DB_BLOCK_SIZE

logfiles

maximum number of logfiles per group minimum size maximum size maximum number per database

unlimited LOG_FILES initialization parameter, or MAXLOGFILES in CREATE DATABASE; controlfile can be resized to allow more entries; ultimately an O/S limit Unlimited 50K bytes O/S limit, typically 2GB 64K ; Number of tablespaces cannot exceed the number of database files, as each tablespace must include at least one file.

Logical Database Limits Item GROUP BY clause

Type maximum length

Indexes

maximum per table total size of indexed column

Columns

Constraints Nested Queries Partitions

Rollback Segments

table indexed (or clustered index) bitmapped index maximum per column maximum number maximum length of linear partitioning key maximum number of columns in partition key maximum number of partitions allowed per table or index maximum number per

Limit The group-by expression and all of the non-distinct aggregate (e.g., sum, avg) need to fit within a single database block. Unlimited 40% of the database block size minus some overhead. 1000 columns maximum 32 columns maximum 30 columns maximum Unlimited 255 4KB - overhead 16 columns 64K-1 partitions no limit; limited within a session by

120

database Rows SQL Statement Length Stored Packages

Trigger Cascade Limit Users and Roles Tables

maximum number per maximum length of statements maximum size

table

maximum value maximum maximum per clustered table maximum per database

MAX_ROLLBACK_SEGMENTS init parameter no limit 64K maximum; particular tools may impose lower limits PL/SQL and Developer/2000 may have limits on the size of stored rocedures they can call. Consult your PL/SQL or Developer/2000 documentation for details. The limits typically range from 20003000 lines of code. O/S dependent, typically 32 2,147,483,638 32 tables unlimited

Schema Object Naming Item Names of databases Names of database links All other schema objects

Limit 8 bytes 128 bytes 30 bytes

Process / Runtime Limits Item Instances per database Locks SGA size

Type maximum number of OPS instances per database row-level Distributed Lock Manager maximum value

Limit O/S dependent unlimited O/S dependent O/S dependent, typically 2-4 GB for 32bit O/S, > 4 GB for 64 bit O/S

121

Effective Coding Style Revealing Logical Structure with Indentation Indentation is one of the most common and effective techniques used to display a program's logic via format. As illustrated in the following examples, programs that are indented are easier to read than those that are not indented. Here is an unindented IF statement: IF to_number(the_value) > 22 THEN IF max_totals = 0 THEN calc_totals; ELSE WHILE more_data LOOP analyze_results; END LOOP; END IF; END IF; I have found that a three (or four)-space indentation not only adequately reveals the logical structure of the code but also keeps the statements close enough together to read comfortably. And, with deeply nested structures, you won't run off the right margin as quickly! Here is the three-space indented version of the previous nested IF statement: IF to_number(the_value) > 22 THEN IF max_totals = 0 THEN calc_totals; ELSE WHILE more_data LOOP analyze_results; END LOOP; END IF; END IF; Using Case to Aid Readability PL/SQL code is made up of many different components: variables, form items, report fields, procedures, functions, loops, declarations, control elements, etc. But they break down roughly into two types of text: reserved words and application-specific names or identifiers.Reserved words are those names of language elements that are reserved by PL/SQL and have a special meaning for the compiler. Some examples of reserved words in PL/SQL are:

122

WHILE IF BEGIN TO_CHAR Application-specific identifiers are the names that you give to data and program structures that are specific to your application and that vary from system to system. The compiler treats these two kinds of text very differently. You can improve the readability of your code greatly by reflecting this difference in the way the text is displayed. Many developers make no distinction between reserved words and application-specific identifiers. Consider the following lines of code: if to_number(the_value)>22 and num1 between lval and hval then newval := 100; elsif to_number(the_value) < 1 then calc_tots(to_date('12-jan-95')); else clear_vals; end if; While the use of indentation makes it easier to follow the logical flow of the IF statement, all the words in the statements tend to blend together. It is difficult to separate the reserved words and the application identifiers in this code. Changing entirely to uppercase also will not improve matters. Indiscriminate, albeit consistent, use of upper- or lowercase for your code reduces its readability. The distinction between reserved words and application-specific identifiers is ignored in the formatting. This translates into a loss of information and comprehension for a developer.

The UPPER-lower Style You can easily solve this problem by adopting a guideline for using a mix of upper- and lowercase to your code. I have recoded my previous example below, this time using the UPPER-lower style: all reserved words are written in UPPERCASE and all application names are kept in lowercase: IF to_number(the_value) > 22 AND num1 BETWEEN lval AND hval THEN newval := 100; ELSIF TO_NUMBER (the_value) < 1 THEN calc_tots (TO_DATE ('12-jan-95')); ELSE clear_vals; END IF; Using a mixture of upper- and lowercase words increases the readability of the code by giving a sense of dimension to the code. The eye can more easily cruise over the text and pick the different syntactical elements of each statement. You can focus quickly on the lowercase words for the application-specific content. Consistent use of this method makes the program listings more attractive and accessible at a glance.

Formatting Single Statements Most of your code consists of individual statements, such as assignments, calls to modules, and declarations. A consistent approach to formatting and grouping such statements will improve the readability of your program as a whole. This section suggests some guidelines. Use at most one statement per line PL/SQL uses the semicolon (;) as the logical terminator for a statement, as a result you can have more than one statement on a line and you can continue a single executable statement over more than one line. You will sometimes be tempted to place several statements on a single line, particularly if they are very

123

simple. Consider the following line: new_id := 15; calc_total (new_id); max_dollars := 105 * sales_adj; It is very difficult to pick out the individual statements in this line, in addition to the fact that a procedure is called in the middle of the line. By placing each statement on its own line you mirror the complexity of a program--the simple lines look simple and the complex statements look complex--and reinforce the topto-bottom logic of the program: new_id := 15; calc_total (new_id); max_dollars := 105 * sales_adj; Use whitespace inside a statement You can use all the indentation and blank lines you want to reveal the logic of a program and still end up with some very dense and unreadable code. It is also important to employ whitespace within a single line to make that one statement more comprehensible. Always include a space between every identifier and separator in a statement. Instead of this: WHILE(total_sales
View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF