A Bag of Tips and Tricks for DBAs and Developers

advertisement
A Bag of Tricks and
Tips for DBAs and
Developers
Ari Kaplan
Independent Consultant
EOUG Madrid 2000
Introduction

Most books and documentation are set up
like reference materials

Training courses focus on the fundamental
aspects of products in a limited time

Hands-on experience is one of the best ways
to learn tricks to maximize your use of
Oracle
Dumping the Contents of a Table
into an ASCII Delimited File

Why do it?

Export/Import are used only with Oracle
databases

You cannot always Export from one Oracle
version and Import into another

ASCII files can be used to copy data from
Oracle to other databases:
Sybase
Informix
Microsoft Access
Paradox
Microsoft SQL Server
Microsoft Excel
email programs
Paradox
Foxpro
Dumping the Contents of a Table
into an ASCII Delimited File
To concatenate two columns in SQL statement, you use the concatenation symbol: ||
For example, assume there is a table such as that below:
EMPLOYEES Table
NAME
David Max
Ari Kaplan
Mickey Mouse
Dilbert
AGE
27
28
100
3
DEPARTMENT
241
242
242
250
You can spool the table with one record per line with the following SQL:
SELECT NAME||AGE||DEPARTMENT FROM
EMPLOYEES;
Dumping the Contents of a Table
into an ASCII Delimited File
The result of
SELECT NAME||AGE||DEPARTMENT FROM EMPLOYEES; will be:
David Max27241
Ari Kaplan28242
Mickey Mouse100242
Dilbert3250
You can see that the format does not separate columns. Typical formats include tabs to
separate columns. In Oracle, this is represented with a CHR(9). So, a better syntax would
be the following SQL:
SELECT NAME||CHR(9)||AGE||CHR(9)||DEPARTMENT FROM
EMPLOYEES;
The result will be:
David Max
Ari Kaplan
Mickey Mouse
Dilbert
27
28
100
3
241
242
242
250
Dumping the Contents of a Table into
an ASCII Delimited File
1)
SET HEADER OFF
SET PAGESIZE 0
SET FEEDBACK OFF
SET TRIMSPOOL ON
2)
SPOOL file_name.txt
<SQL statement>
3)
SPOOL OFF
4) For tables where the length each record is greater than 80, be sure to set the LINESIZE value
large enough. Otherwise Oracle will break up the lines every 80 characters, making the file not
easily readable by other applications.
Getting Around LONG Datatype Limitations
Limitations:

LONG columns cannot do string manipulations

The CREATE TABLE table_A AS SELECT * FROM table_b cannot be
done if table_b has a LONG column

Snapshots and Replication have problems with LONG columns

Limit of one LONG column per table
Overcoming the LONG columns:
Use BLOB datatypes and procedures with Oracle8. Oracle has already
announced that it will discontinue LONG datatypes in a future release.
You can convert LONG to LOB with the TO_LOB function.
Use PL/SQL to manipulate LONG datatype
Getting around LONG Datatype Limitations
 Assume that there is a table:
RESUME_BANK
Name
VARCHAR2(40)
Department
NUMBER
Resume_text
LONG
(stores the resume text)
 Assume that you want to review all resumes with the word “ORACLE” in it.
Normally, you would issue:
SELECT resume_text
FROM resume_bank
WHERE UPPER(resume_bank) like ‘%ORACLE%’;
The result would be the ORA-932 “Inconsistent Datatypes”.
Getting Around LONG Datatype Limitations
To find all such resume records with the LONG datatype in a table, you must use PL/SQL. Below is a sample
program that will do this by selecting one resume from the resume bank:
SET SERVEROUTPUT ON SIZE 100000;
SET LONG 100000;
DECLARE
LONG_var
LONG;
resume_name
varchar2(40);
CURSOR x IS
SELECT name, resume_text FROM RESUME_BANK;
BEGIN
FOR cur_record in X
resume_name := cur_record.name;
LONG_var := cur_record.LONG_var;
IF UPPER(resume_name) like ‘%ORACLE%’ THEN
/* Print the resume to the screen */
DBMS_OUTPUT.PUT_LINE(‘Below is the resume of ‘||resume_name||
’ that contains the word ORACLE:’);
DBMS_OUTPUT.PUT_LINE(LONG_var);
ENDIF;
END LOOP;
END;
/
Using SQL to Dynamically Generate SQL Scripts

Why do this?

The syntax to create a public synonym follows:
CREATE PUBLIC SYNONYM synonym_name FOR owner.table_name;
The following statement will create a series of “CREATE PUBLIC SYNONYM” statements:
SELECT ‘CREATE PUBLIC SYNONYM ‘|| object_name ||
‘ FOR ‘ || owner || ‘.’ || object_name || ‘;’
FROM ALL_OBJECTS
WHERE OWNER = ‘IOUG’;

This will produce an output similar to:
CREATE PUBLIC SYNONYM ATTENDEE FOR IOUG.ATTENDEE;
CREATE PUBLIC SYNONYM HOTEL_ID FOR IOUG.HOTEL_ID;
CREATE PUBLIC SYNONYM CREDIT_CARD_NBR FOR IOUG.
CREDIT_CARD_NBR;
Notice how there is a space in the original SQL statement between the FOR and the
preceding quote. Without the space, the output would look like...
Using SQL to Dynamically Generate SQL Scripts

The output from the previous SQL:
CREATE PUBLIC SYNONYM ATTENDEEFOR IOUG.ATTENDEE;
CREATE PUBLIC SYNONYM HOTEL_IDFOR IOUG.HOTEL_ID;
CREATE PUBLIC SYNONYM CREDIT_CARD_NBRFOR IOUG. CREDIT_CARD_NBR;

You can see how you must be careful of spaces and quotes.

Also, note the final concatenation with the semicolon (;)
1)
SET HEADER OFF
SET PAGESIZE 0
SET FEEDBACK OFF
2)
SPOOL file_name.sql
<SQL statement>
3)
4)
SPOOL OFF
For output that is greater than 80 characters, be sure to set the
LINESIZE value large enough. Otherwise Oracle will break up the
lines every 80 characters, making the SQL fail.
Using SQL to Dynamically
Generate SQL Scripts

Putting it all together, the commands below will generate a clean
file that contains only proper SQL statements:
SQL> SET HEAD OFF
SQL> SET PAGESIZE 0
SQL> SET FEEDBACK OFF
SQL> SPOOL create_synonym.SQL
SQL> SELECT ‘CREATE PUBLIC SYNONYM ‘|| object_name ||
‘ FOR ‘ || owner || ‘.’ || object_name || ‘;’
FROM ALL_OBJECTS
WHERE OWNER = ‘IOUG’;
CREATE PUBLIC SYNONYM ATTENDEE FOR IOUG.ATTENDEE;
CREATE PUBLIC SYNONYM HOTEL_ID FOR IOUG.HOTEL_ID;
CREATE PUBLIC SYNONYM CREDIT_CARD_NBR
FOR IOUG. CREDIT_CARD_NBR;
SQL> SPOOL OFF
Dynamically Recreate Your INIT.ORA file



What is the INIT.ORA file?
How can your INIT.ORA file get lost or out of synch?
The V$PARAMETER data dictionary view contains the
list of initialization parameters and their values.
NAME
NUM
NAME
TYPE
VALUE
ISDEFAULT
ISSES MODIFIABLE
ISSYS MODIFIABLE
ISMODIFIED
ISADJUSTED
DESCRIPTION
TYPE
NUMBER
VARCHAR2(64)
NUMBER
VARCHAR2(512)
VARCHAR2(9)
VARCHAR2(5)
VARCHAR2(9)
VARCHAR2(10)
VARCHAR2(5)
VARCHAR2(64)
Dynamically Recreate Your INIT.ORA file

To see all of the parameters and their values (along
with whether or not they are the default values), issue
the following SQL:
SQL> COLUMN NAME FORMAT A30
SQL> COLUMN VALUE FORMAT A30
SQL> SELECT NAME, VALUE, ISDEFAULT
FROM V$PARAMETER ORDER BY NAME;
NAME
shared_pool_size
snapshot_refresh_interval
snapshot_refresh_keep_connect
snapshot_refresh_process
sort_area_retained_size
sort_area_size
sort_direct_writes
sort_spacemap_size
sort_write_buffer_size
VALUE
300000000
60
FALSE
0
0
51200000
TRUE
512
32768
ISDEFAULT
FALSE
TRUE
TRUE
TRUE
TRUE
FALSE
FALSE
TRUE
TRUE
Dynamically Recreate Your INIT.ORA file

To generate the INIT.ORA file, you can use SQL to
generate SQL and spool the results to a file:
SQL> SET LINESIZE 200
SQL> SET TRIMSPOOL ON
SQL> SET HEADING OFF
SQL> SET FEEDBACK OFF
SQL> SET PAGESIZE 0
SQL> SELECT NAME||’=‘||VALUE
2 FROM V$PARAMETER WHERE ISDEFAULT=‘FALSE’
3 ORDER BY NAME
SQL> SPOOL initSID.ora
SQL> /
sequence_cache_entries=100
sequence_cache_hash_buckets=89
shared_pool_size=30000
sort_area_size=512000
sort_direct_writes=TRUE
rollback_segments=rbig, r01, r02, r03, r04
…
SQL> SPOOL OFF
Finding All Referencing Constraints to a
Particular Table

The DBA_CONSTRAINTS data dictionary view contains
information on table relationships:
SQL> DESC DBA_CONSTRAINTS
Name
Null?
Type
OWNER
CONSTRAINT_NAME
CONSTRAINT_TYPE
TABLE_NAME
SEARCH_CONDITION
R_OWNER
R_CONSTRAINT_NAME
DELETE_RULE
STATUS
DEFERRABLE
DEFERRED
VALIDATED
GENERATED
BAD
LAST_CHANGE
NOT NULL
NOT NULL
VARCHAR2(30)
VARCHAR2(30)
VARCHAR2(1)
VARCHAR2(30)
LONG
VARCHAR2(30)
VARCHAR2(30)
VARHCAR2(9)
VARCHAR2(8)
VARCHAR2(14)
VARCHAR2(9)
VARCHAR2(13)
VARCHAR2(14)
VARCHAR2(3)
DATE
NOT NULL
Finding All Referencing Constraints to a
Particular Table

To see the constraints on the EMP and DEPT tables,
along with which constraints they are referencing:
SQL> SELECT OWNER||’.’||TABLE_NAME “TABLE”,
2
CONSTRAINT_NAME, R_CONSTRAINT_NAME
3
FROM DBA_CONSTRAINTS
4
WHERE TABLE_NAME IN (‘EMP’,’DEPT’)
TABLE
CONSTRAINT_NAME R_CONSTRAINT_NAME
SCOTT.EMP
FK_EMP
PK_DEPT
SCOTT.DEPT
PK_DEPT
Finding All Referencing Constraints to a
Particular Table

To see all constraints that point to a table, issue:
SQL> SELECT OWNER||’.’||TABLE_NAME “TABLE”,
2
CONSTRAINT_NAME, R_CONSTRAINT_NAME
3
FROM DBA_CONSTRAINTS
4
WHERE (OWNER, R_CONSTRAINT_NAME) IN
5
(SELECT OWNER, CONSTRAINT_NAME
6
FROM DBA_CONSTRAINTS B
7
WHERE B.OWNER = ‘&owner’ AND
8
B.TABLE_NAME = ‘&table’);
Enter value for owner: SYSTEM
Enter value for table: DEPT
TABLE
SCOTT.EMP
TRAINING.EMP
CONSTRAINT_NAME
FK_EMP
FK_EMP
R_CONSTRAINT_NAME
PK_DEPT
PK_DEPT
Finding the Total REAL Size of Data in a
Table, Not Just the INIT/NEXT Extent






What are INITIAL and NEXT extents?
How does data fill into extents?
Two possibilities: ANALYZE the table or use the
ROWID pseudo-column
ANALYZE generates block statistics.
Oracle7’s ROWID is in restricted format, which
includes the block
Oracle8’s ROWID (extended format) can be
converted to restricted format with the
DBMS_ROWID package.
Finding the Total REAL Size of Data in a
Table, Not Just the INIT/NEXT Extent
 You can easily see the number of blocks that have been
used by analyzing the table and querying the
USER_TABLES view:
SQL> ANALYZE TABLE table_name ESTIMATE STATISTICS;
Table Analyzed.
SQL> SELECT TABLE_NAME, BLOCKS, EMPTY_BLOCKS
2
FROM USER_TABLES WHERE TABLE_NAME = ‘table_name’;
TABLE_NAME
BLOCKS
EMPTY_BLOCKS
table_name
964
465
 This will quickly give the results, but the downsides are
…
Finding the Total REAL Size of Data in a
Table, Not Just the INIT/NEXT Extent
 In Oracle7, to find out the total blocks, enter the following SQL:
SELECT count(distinct(substr(rowid,1,8))) FROM table_name;
 In Oracle8, you can find the total blocks using DBMS_ROWID:
SELECT count(distinct(substr(dbms_rowid.rowid_to_restricted(rowid),1,8)))
FROM table_name;
You will get the total number of blocks that contain records of the table.

To determine the overall size, find the block size:
SELECT value FROM V$PARAMETER WHERE NAME = ‘db_block_size’;
 The total space of the data is the multiplication of “Total Blocks”
This will be in bytes.

*
“Block Size”.
To find the density (rows per block for EACH block), issue (Oracle7):
SELECT distinct(substr(rowid,1,8)) FROM table_name;
-or in Oracle8SELECT (distinct(substr(dbms_rowid.rowid_to_restricted(rowid),1,8))
FROM table_name;
What SQL Statement is a
Particular User Account Executing
 One of the most important DBA jobs is to know what
the users are doing
 Oracle does not make this easy
 Determine the SID of the user account you wish to
monitor. To get a list of all users logged in at any given
time, type in the following SQL:
SELECT sid, schemaname, osuser, substr(machine, 1, 20)
Machine
FROM v$session
ORDER BY schemaname;
What SQL Statement is a
Particular User Account Executing
A sample output follows:
SID
---1
2
3
4
7
13
6
14
12
SCHEMANAME
---------------SYS
SYS
SYS
SYS
SYSTEM
SYSTEM
WWW_DBA
WWW_DBA
WWW_DBA
OSUSER
-----------
MACHINE
------------
plat
oracle
oracle
oracle
oracle
ustate1
ustate1
dw1-uw
dw1-uw
dw1-uw
What SQL Statement is a
Particular User Account Executing
Now, you can select a user from list. When you
run the SQL below, the SQL statement that the
user account is running will be shown.
SELECT sql_text
FROM v$sqlarea
WHERE (address, hash_value) IN
(SELECT sql_address, sql_hash_value
FROM v$session
WHERE sid = &1);
Temporarily Changing User
Passwords to Log in as Them
 Can you determine a user’s password if you are the
DBA?
 How are passwords stored in the database?
SELECT username, password
FROM DBA_USERS;

You will get a result of something like:
USERNAME
AKAPLAN
SYSTEM
SYS
PASSWORD
923FEA35C3BE5824
34D93E8F22C21DA4
A943B39DF93E02C2
.
Temporarily Changing User
Passwords to Log in as Them
There is a trick that you can use to temporarily change the users password to
something you do know, and then change it back when you are done.
The unsuspecting user
will never know ;)
Before you do this, you need to find the encrypted password:
SELECT password
FROM all_users
WHERE username = ‘enter_username_here’;
Temporarily Changing User
Passwords to Log in as Them
 Write down the 16-digit encrypted password. You will need this
later. Now, change the password of the user to whatever you want:
ALTER USER AKAPLAN IDENTIFIED BY
applaud_now;
 You can now go into the database as the AKAPLAN user:
sqlplus AKAPLAN/applaud_now
 To change the password back, use the “BY VALUES” clause of the
“ALTER USER” command. For the password, supply the 16-digit
encrypted password in single quotes. An example is shown below:
ALTER USER AKAPLAN
IDENTIFIED BY VALUES ‘923FEA35C3BE5824’;
Temporarily Changing User
Passwords to Log in as Them
Oracle8 Password-Related Management Options:
Highlighted items are affected by temporarily changing passwords

FAILED_LOGIN_ATTEMPTS

PASSWORD_GRACE_TIME

PASSWORD_LIFE_TIME

PASSWORD_LOCK_TIME

PASSWORD_REUSE_MAX

PASSWORD_REUSE_TIME

PASSWORD_VERIFY_FUNCTION
Where to Now?
 There are many discussion Newsgroups on the internet for you to
give questions and get answers:
comp.databases.oracle.server
comp.databases.oracle.tools
comp.databases.oracle.misc
 These can be accessed through a newsgroup program or
“www.deja.com”
 Ari’s free Oracle Tips web page at:
There are over 370 tips and answers to questions that have been posed to me over the
years. This paper will be downloadable from the web page as well.

www.orafaq.org, www.orafans.com,
www.ioug.org, www.orasearch.com,
www.revealnet.com, www.lazydba.com,
www.dbdomain.com
Other good sites with links:
Download