Quantcast
Channel: Andrew's Oracle Blog
Viewing all 330 articles
Browse latest View live

ORA-28002

$
0
0
The PASSWORD_LIFE_TIME in the DEFAULT profile is 180 days in Oracle 11:
 
SQL> select limit from dba_profiles
  2  where profile = 'DEFAULT'
  3  and resource_name = 'PASSWORD_LIFE_TIME'
  4  /
 
LIMIT
----------------------------------------
180
 
SQL>
 
If you are not careful, a user’s password will expire if it is not changed soon enough. It will go into a grace period before it does. This has just happened to the user below:
 
SQL> l
  1  select account_status from dba_users
  2* where username = 'EBASE'
SQL> /
 
ACCOUNT_STATUS
--------------------------------
EXPIRED(GRACE)
 
SQL>
 
This isn’t too much of a problem if the user connects via SQL*Plus as Oracle just displays an appropriate warning before connecting during the grace period. This allows you to identify and rectify the issue before the password expires and locks the user out completely:
 
SQL> conn EBASE
Enter password:
ERROR:
ORA-28002: the password will expire within 6 days
 
Connected.
SQL>
 
However, many people, especially application users, connect via an application-specific front-end screen. These may have to work on a variety of hardware platforms and on other databases besides Oracle (e.g. Microsoft SQL Server or MySQL). Typically they do not handle error situations very well.

I came across one of these today. A user in Holland had connected to a database in the United Kingdom with the EBASE user above. The connection was successful and a corresponding row appeared in V$SESSION. However, the front-end screen saw the ORA-28002 warning, displayed a message saying that it could not connect to the database and allowed the user to go no further. The user sent the message to me but it did not make it clear what had caused the problem. The presence of entries for the user in V$SESSION did not seem to agree with the fact that the application said it had failed to connect. It was therefore quite some time before I worked out what had gone wrong.
 
You can reset a user's ACCOUNT_STATUS by changing its password. This particular application expects to always see the same password so I just reinstated the previous encrypted value as I do not want to show the actual value in a public blog post:
 
SQL> select password from sys.user$
  2  where name = 'EBASE'
  3  /
 
PASSWORD
------------------------------
82E46EECF1AFF14B
 
SQL> alter user ebase identified by values '82E46EECF1AFF14B'
  2  /
 
User altered.
 
SQL> select account_status from dba_users
  2  where username = 'EBASE'
  3  /
 
ACCOUNT_STATUS
--------------------------------
OPEN
 
SQL>
 
Then when the user logs in again, Oracle will not display an error:
 
SQL> conn EBASE
Enter password:
Connected.
SQL>
 
To stop this happening again, you may decide to change PASSWORD_LIFE_TIME to UNLIMITED:
 
SQL> conn / as sysdba
Connected.
SQL> l
  1  alter profile default
  2* limit password_life_time unlimited
SQL> /
 
Profile altered.
 
SQL> select limit from dba_profiles
  2  where profile = 'DEFAULT'
  3  and resource_name = 'PASSWORD_LIFE_TIME'
  4  /
 
LIMIT
----------------------------------------
UNLIMITED
 
SQL>

Hard Coded Variables in PL/SQL

$
0
0
Many applications need to use the same value in several different places. The examples below show a net value and a tax figure being added to create a gross amount. The tax figure is calculated by multiplying the net value by the tax rate. In the first example, the tax rate is hard-coded as 0.2. This is quite simple to implement but, if the tax rate changes, you will need to go through your whole application and amend every individual value: 

SQL> set serveroutput on
SQL> declare
  2    net number;
  3    tax number;
  4    gross number;
  5  begin
  6    net := 1;
  7    tax := 0.2;
  8    gross := net + (net * tax);
  9    dbms_output.put_line('Gross = '||to_char(gross,'$9.99'));
 10  end;
 11  /
Gross =  $1.20
 
PL/SQL procedure successfully completed.

SQL> 

The second example stores the tax rate as a constant in a package. When you need to know the tax rate, you fetch it from the package as shown below. This is slightly harder to implement but, if the tax rate changes, you only need to amend the value in one place: 

SQL> create or replace package special_values1
  2  is
  3    tax constant number := 0.2;
  4  end special_values1;
  5  /
 
Package created.
 
SQL> declare
  2    net number;
  3    tax number;
  4    gross number;
  5  begin
  6    net := 1;
  7    tax := special_values1.tax;
  8    gross := net + (net * tax);
  9    dbms_output.put_line('Gross = '||to_char(gross,'$9.99'));
 10  end;
 11  /
Gross =  $1.20
 
PL/SQL procedure successfully completed.

SQL>

The third example is similar to the second but, this time, the tax rate is returned by a function:
 
SQL> create or replace package special_values2
  2  is
  3    function tax
  4    return number;
  5  end special_values2;
  6  /
 
Package created.
 
SQL> create or replace package body special_values2
  2  is
  3    function tax
  4    return number
  5  is
  6  begin
  7    return 0.2;
  8  end;
  9  end special_values2;
 10  /
 
Package body created.
 
SQL> declare
  2    net number;
  3    tax number;
  4    gross number;
  5  begin
  6    net := 1;
  7    tax := special_values2.tax();
  8    gross := net + (net * tax);
  9    dbms_output.put_line('Gross = '||to_char(gross,'$9.99'));
 10  end;
 11  /
Gross =  $1.20
 
PL/SQL procedure successfully completed.
 
SQL>

The simplest method of all is possibly to store the tax rate as a value in a table. I won't insult your intelligence by showing an example using this method!

ORA-00030

$
0
0
This was tested on Oracle 11.2. When you run ALTER SYSTEM KILL SESSION ‘X,Y’; X must be a SID from V$SESSION and Y must be the SERIAL# from the same row. If not, you will get an ORA-00030: 

SQL> select count(*) from v$session
  2  where sid = 123
  3  and serial# = 321
  4  /
 
  COUNT(*)
----------
         0
 
SQL> alter system kill session '123,321'
  2  /
alter system kill session '123,321'
*
ERROR at line 1:
ORA-00030: User session ID does not exist.
 
SQL>

ORA-01754

$
0
0
The first example below was tested on Oracle 11.2. If you try to have more than one long column in a table, you get an ORA-01754:

SQL> create table tab1 (col1 long, col2 long)
  2  /
create table tab1 (col1 long, col2 long)
                              *
ERROR at line 1:
ORA-01754: a table may contain only one column of type LONG
 
SQL> 

That was fairly obvious. Now here is another example, which I wrote at the start of 2012. I do not know which Oracle version I did it on. First I created a table with one column:

SQL> create table andrews_table
  2  (col1 varchar2(10))
  3  /

Table created.

SQL>

Then I added a long column to the table and described it to show the column I had just added:

SQL> alter table andrews_table
  2  add (col2 long)
  3  /

Table altered.

SQL> desc andrews_table
Name                      Null?    Type
-------------------------- -------- ------------------
COL1                                VARCHAR2(10)
COL2                                LONG

SQL>

Next I set the long column to unused. This does not restore the disk space used by the column:

SQL> alter table andrews_table
  2  set unused column col2
  3  /

Table altered.

SQL>

I described the table again to show that the long column had gone:

SQL> desc andrews_table
Name                      Null?    Type
-------------------------- -------- ------------------
COL1                                VARCHAR2(10)

SQL>

Then I tried to add another long column. This failed as you can only have 1 long column per table. How would you diagnose this problem if it happened to you in real life?

SQL> alter table andrews_table
  2  add (col3 long)
  3  /
add (col3 long)
    *
ERROR at line 2:
ORA-01754: a table may contain only one column of type
LONG

SQL>

You can get a clue by looking in user_unused_col_tabs, which confirms that the table has 1 unused column:

SQL> select count(*) from user_unused_col_tabs
  2  where table_name = 'ANDREWS_TABLE'
  3  /

  COUNT(*)
----------
         1

SQL>

Drop the unused column from the table. This frees up the disk space which the column occupied:

SQL> alter table andrews_table
  2  drop unused columns
  3  /

Table altered.

SQL>

The table no longer has an entry in user_unused_col_tabs:

SQL> select count(*) from user_unused_col_tabs
  2  where table_name = 'ANDREWS_TABLE'
  3  /

no rows selected

SQL>

And you can add another long column if you wish:

SQL> alter table andrews_table
  2  add (col3 long)
  3  /

Table altered.

SQL>

DBMS_UTILITY.EXEC_DDL_STATEMENT

$
0
0
I published a post recently about executing DDL from PL/SQL. You can also do this using dbms_utility.exec_ddl_statement as shown in the examples below, which I tested in Oracle 11: 

SQL> begin
  2    dbms_utility.exec_ddl_statement
  3    ('create table tab1(col1 number)');
  4  end;
  5  /
 
PL/SQL procedure successfully completed.
 
SQL> declare
  2    sql_statement varchar2(50);
  3  begin
  4    sql_statement := 'alter table tab1 add(col2 number)';
  5    dbms_utility.exec_ddl_statement(sql_statement);
  6  end;
  7  /
 
PL/SQL procedure successfully completed.
 
SQL> desc tab1
Name                       Null?    Type
-------------------------- -------- ------------------
COL1                                NUMBER
COL2                                NUMBER
 
SQL> 

It even seems to allow you to run DDL in a remote database: 

SQL> begin
  2    dbms_utility.exec_ddl_statement@remote_db
  3    ('create table tab1(col1 number)');
  4  end;
  5  /
 
PL/SQL procedure successfully completed.
 
SQL> desc tab1@remote_db
Name                       Null?    Type
-------------------------- -------- ------------------
COL1                                NUMBER
 
SQL>

ORA-02210

$
0
0
I discovered a new error today while working on an Oracle 11 database. If you try to use alter table without any options, you get an ORA-02210. If you add a valid option, the error does not appear.

SQL> alter table srce.go_tpr_nhh_ppc
  2  /
alter table srce.go_tpr_nhh_ppc
                              *
ERROR at line 1:
ORA-02210: no options specified for ALTER TABLE
 
SQL> alter table srce.go_tpr_nhh_ppc enable all triggers
  2  /
 
Table altered.
 
SQL>

ORA-00604, ORA-04092, ORA-06512 and ORA-00942

$
0
0
I saw an ORA-00604 in a database recently and decided to see what might have caused it. The test below was run in an Oracle 9 database and shows one possible reason for an ORA-00604. Strangely enough, when I repeated the test in Oracle 10 and Oracle 11 databases, the ORA-00604 did not appear. If / when I find out why, I will update this post accordingly. First I ensured that _system_trig_enabled was set to true. You will see why at the end:
 
SQL> conn / as sysdba
Connected.
SQL> alter system
  2  set "_system_trig_enabled"=TRUE
  3  /
 
System altered.
 
SQL>
 
Then I created a user:

SQL> grant create session to andrew
  2  identified by reid
  3  /
 
Grant succeeded.
 
SQL>
 
The user looked for a table which did not exist and got an ORA-00942 (as you do):
 
SQL> conn andrew/reid
Connected.
SQL> select * from tab1
  2  /
select * from tab1
              *
ERROR at line 1:
ORA-00942: table or view does not exist
 
SQL>
 
Next I created a user to own a trigger. This trigger is to fire on an after servererror on database event, write an error message to a table and commit it. To do this the user needs create trigger and administer database trigger privileges:  
 
SQL> conn / as sysdba
Connected.
SQL> create user fred identified by bloggs
  2  default tablespace users
  3  quota unlimited on users
  4  /
 
User created.
 
SQL> grant create session,
  2  create table,
  3  create trigger,
  4  administer database trigger
  5  to fred
  6  /
 
Grant succeeded.
 
SQL>
 
SQL> conn fred/bloggs
Connected.
SQL> create table failure_log
  2  (message varchar2(40))
  3  /
 
Table created.
 
SQL> create or replace trigger error_trigger
  2  after servererror on database
  3  begin
  4    insert into failure_log
  5    values('We have a problem');
  6    commit;
  7  end;
  8  /
 
Trigger created.
 
SQL>
 
You can identify these triggers as they have a trigger_type of AFTER EVENT:
 
SQL> select trigger_name, trigger_type
  2  from user_triggers
  3  /
 
TRIGGER_NAME         TRIGGER_TYPE
-------------------- ----------------
ERROR_TRIGGER        AFTER EVENT
 
SQL>
 
The next time Andrew tried to look for the table which did not exist, he got an ORA-00604 and an ORA-04092 as well because Fred’s trigger tried to do a commit:
 
SQL> conn andrew/reid
Connected.
SQL> select * from tab1
  2  /
select * from tab1
              *
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-04092: cannot COMMIT in a trigger
ORA-06512: at line 4
ORA-00942: table or view does not exist
 
SQL>
 
I set _system_trig_enabled to false to stop Fred’s trigger firing:
 
SQL> conn / as sysdba
Connected.
SQL> alter system
  2  set "_system_trig_enabled"=FALSE
  3  /
 
System altered.
 
SQL>
 
So the next time Andrew looked for the missing table, he just got an ORA-00942:
 
SQL> conn andrew/reid
Connected.
SQL> select * from tab1
  2  /
select * from tab1
              *
ERROR at line 1:
ORA-00942: table or view does not exist
 
SQL> 

ORA-12500

$
0
0
I had ORA-12500 errors each time I tried to connect to a database on a particular server:
 
C:\>sqlplus system@livsost1
 
SQL*Plus: Release 11.2.0.3.0 Production on Fri Feb 7 11:05:18 2014
 
Copyright (c) 1982, 2011, Oracle.  All rights reserved.
 
Enter password:
ERROR:
ORA-12500: TNS:listener failed to start a dedicated server process
 
Enter user-name: system@ebesost1
Enter password:
ERROR:
ORA-12500: TNS:listener failed to start a dedicated server process
 
Enter user-name:
 
Logging in to the server as the oracle UNIX user gave a clue to the cause of the problem:
 
login as: oracle
oracle@sge-mktred-dev1's password:
Last login: Thu Feb  6 09:13:51 GMT 2014 from 10.80.14.248
Compaq Tru64 UNIX V5.1B (Rev. 2650); Tue Jun 13 17:14:04 BST 2006
No mail.
task_create() failed for pid 479503: max_proc_per_user (=1024) exceeded for uid 200.
task_create() failed for pid 479503: max_proc_per_user (=1024) exceeded for uid 200.
task_create() failed for pid 479503: max_proc_per_user (=1024) exceeded for uid 200.
task_create() failed for pid 479503: max_proc_per_user (=1024) exceeded for uid 200.
 
I logged in as root and saw several defunct processes all associated with process 431167:
 
root > ps -ef|grep oracle|grep defunct|grep 431167|more
oracle         2311     431167  0.0 -        ??           0:00.00 <defunct>
oracle         8250     431167  0.0 -        ??           0:00.00 <defunct>
oracle         9459     431167  0.0 -        ??           0:00.00 <defunct>
oracle        11819     431167  0.0 -        ??           0:00.00 <defunct>
oracle        12526     431167  0.0 -        ??           0:00.00 <defunct>
oracle        12814     431167  0.0 -        ??           0:00.00 <defunct>
oracle        13421     431167  0.0 -        ??           0:00.00 <defunct>
etc
 
So I counted them:
 
root > ps -ef|grep oracle|grep defunct|grep 431167|wc -l
       427
root >
 
Then I found out where they came from:
 
root > ps -ef|grep 'oracle       431167'
oracle       431167     210307  0.0   Feb 01 ??        1-07:14:58 /oracle/app/oracle/product/grid/agent10g/bin/emagent
root >
 
I decided to kill the process. It’s just the Oracle Enterprise Manager agent so I can start it again afterwards:
 
root > kill 431167
 
… and the problem went away:
 
C:\>sqlplus system@livsost1
 
SQL*Plus: Release 11.2.0.3.0 Production on Fri Feb 7 11:36:28 2014
 
Copyright (c) 1982, 2011, Oracle.  All rights reserved.
 
Enter password:
 
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.7.0 - Production
With the Partitioning option
JServer Release 9.2.0.7.0 - Production
 
SQL>

SP2-0308

$
0
0
If you are running a SQL script and you see the message below: 

SP2-0308: cannot close spool file
SQL>

... it could be that the disk the SPOOL file is on is full (as usual, click on the image to enlarge it):


If you clear some space, future SPOOL files should be created OK but, if my experience is anything to go by, the output you were SPOOLing before the SP2-0308 occurred will be lost forever.


DROP TYPE Statement Hangs

$
0
0
This happened in an Oracle 11 database. I had an INACTIVE session in the database:

SQL> select status from v$session
  2  where sid = 112;
 
STATUS
--------
INACTIVE
 
SQL>
 
I tried to use this session to drop a type but it did not seem to work:
 
SQL> drop type ppc_day_rec
  2  /

… but the status of the session had changed to ACTIVE so I assumed it was doing something:

SQL> l
  1  select status from v$session
  2* where sid = 112
SQL> /
 
STATUS
--------
ACTIVE
 
SQL>
 
Nothing showed up in DBA_WAITERS:
 
SQL> select * from dba_waiters;
 
no rows selected
 
SQL>
 
… but I found what was holding onto the TYPE like this:
 
SQL> l
  1  select a.sid, serial#
  2  from v$access a, v$session b
  3  where a.sid = b.sid
  4* and object = 'PPC_DAY_REC'
SQL> /
 
       SID    SERIAL#
---------- ----------
       106       1378
 
SQL>
 
I killed the offending session as follows:
 
SQL> alter system disconnect session '106,1378' immediate
  2  /
 
System altered.
 
SQL>
 
… and the DROP TYPE statement completed:
 
SQL> drop type ppc_day_rec
  2  /
 
Type dropped.
 
SQL>

ORA-13505

$
0
0
I tested this on an Oracle 10 database running on Linux. If you try to make the SYSAUX tablespace READ ONLY, you get an error. There is no way round this, you cannot do it: 

SQL> alter tablespace sysaux read only
  2  /
alter tablespace sysaux read only
*
ERROR at line 1:
ORA-13505: SYSAUX tablespace can not be made read only

SQL>

Recursive Procedure Compilation

$
0
0
This was tested on Oracle 11.2. You cannot compile a procedure if anybody is running it so, if you write a procedure which compiles itself, it hangs:
 
SQL> conn andrew/reid
Connected.
SQL> select distinct sid from v$mystat
  2  /
 
       SID
----------
       296
 
SQL> create procedure blah
  2  is
  3  begin
  4  execute immediate 'alter procedure blah compile';
  5  end;
  6  /
 
Procedure created.
 
SQL> exec blah;
 
This appears in V$SESSION_EVENT as a library cache pin:
 
SQL> conn / as sysdba
Connected.
SQL> undefine sid
SQL> select time_waited/100
  2  from v$session_event
  3  where event = 'library cache pin'
  4  and sid = '&&sid'
  5  /
Enter value for sid: 296
old   4: and sid = '&&sid'
new   4: and sid = '296'
 
TIME_WAITED/100
---------------
         459.91
 
SQL> exec sys.dbms_lock.sleep(10);
 
PL/SQL procedure successfully completed.
 
SQL> select time_waited/100
  2  from v$session_event
  3  where event = 'library cache pin'
  4  and sid = '&&sid'
  5  /
old   4: and sid = '&&sid'
new   4: and sid = '296'
 
TIME_WAITED/100
---------------
         468.94
 
SQL>
 
… and, if you look in x$kglpn, you see that SID 296 is blocking and waiting simultaneously:
 
SQL> conn / as sysdba
Connected.
SQL> select s.sid, kglpnmod "Mode", kglpnreq "Req"
  2  from x$kglpn p, v$session s, v$session_wait w
  3  where p.kglpnuse = s.saddr
  4  and p.kglpnhdl = w.p1raw
  5  and w.sid = &sid
  6  /
Enter value for sid: 296
old   5: and w.sid = &sid
new   5: and w.sid = 296
 
       SID       Mode        Req
---------- ---------- ----------
       296          0          3
       296          2          0
 
SQL>

Logons Cumulative

$
0
0
The logons cumulative statistic in V$SYSSTAT shows how many sessions have connected since the database was opened. If this value is too high, there could be shell scripts looping round and connecting then disconnecting from the database. This can have a detrimental effect on performance.

SQL> col name format a20
SQL> select * from v$sysstat where name = 'logons cumulative'
  2  /

STATISTIC# NAME                 CLASS      VALUE      STAT_ID
---------- -------------------- ---------- ---------- ----------
0          logons cumulative    1          44         2666645286

SQL>


If you reconnect to the database, the value should increase by 1.

SQL> conn system/manager@adhoc
Connected.
SQL> select * from v$sysstat where name = 'logons cumulative'
  2  /

STATISTIC# NAME                 CLASS      VALUE      STAT_ID
---------- -------------------- ---------- ---------- ----------
0          logons cumulative    1          45         2666645286

SQL>

User Commits, Log File Parallel Write and Log File Sync

$
0
0
I ran this example on Oracle 11.2. If an application spends too much time waiting on log file parallel write and/or log file sync, it may be doing too many user commits. To illustrate this, I created the SQL*Plus script below. It accepts a parameter and uses this to create a unique SPOOL file name and table name. It then sees how many user commits the database has done and looks to see the total time which has been spent waiting on the log file parallel write and log file sync events. After that, it inserts and deletes a row in the table 10,000 times. Each insert and delete is committed immediately. Once this has finished, the script counts the user commits and records the time spent waiting on log file parallel write and log file sync again. Finally, it waits 60 seconds before logging out. This is probably a bit of overkill but I wanted to be sure that all sessions would still be present in v$session_event while the last one to finish recorded the statistics I was interested in:
 
Oracle 11.2: cat test.sql
spool test&&1
col start_time format a10
set echo on
set lines 55
set termout off
set trimspool on
conn /
select to_char(sysdate,'hh24:mi:ss')
start_time from dual
/
create table tab&&1(col1 number)
/
select value from v$sysstat b
where name = 'user commits'
/
select sum(time_waited/100) from v$session_event
where event = 'log file parallel write'
/
select sum(time_waited/100) from v$session_event
where event = 'log file sync'
/
begin
for a in 1..10000 loop
  begin
  insert into tab&&1 values (a);
  commit;
  delete tab&&1;
  commit;
  end;
end loop;
end;
/
select value from v$sysstat
where name = 'user commits'
/
select sum(time_waited/100) from v$session_event
where event = 'log file parallel write'
/
select sum(time_waited/100) from v$session_event
where event = 'log file sync'
/
drop table tab&&1
/
select to_char(sysdate,'hh24:mi:ss')
end_time from dual
/
exec dbms_lock.sleep(60);
exit
spool off
Oracle 11.2:
 
Then I ran it from the following UNIX shell script. This runs the SQL script in 20 SQL*Plus sessions simultaneously in the background:
 
Oracle 11.2: cat test.ksh
#!/bin/ksh
export ORAENV_ASK=NO
export ORACLE_SID=ORCL
. oraenv
sqlplus  / @test 0 &
sqlplus  / @test 1 &
sqlplus  / @test 2 &
sqlplus  / @test 3 &
sqlplus  / @test 4 &
sqlplus  / @test 5 &
sqlplus  / @test 6 &
sqlplus  / @test 7 &
sqlplus  / @test 8 &
sqlplus  / @test 9 &
sqlplus  / @test 10 &
sqlplus  / @test 11 &
sqlplus  / @test 12 &
sqlplus  / @test 13 &
sqlplus  / @test 14 &
sqlplus  / @test 15 &
sqlplus  / @test 16 &
sqlplus  / @test 17 &
sqlplus  / @test 18 &
sqlplus  / @test 19 &
Oracle 11.2:
 
Once they had all finished, I sorted the output into chronological order:
 
Oracle 11.2: ls -ltr *lst
-rw-r--r--   1 oracle   dba         1868 Feb 24 18:04 test14.lst
-rw-r--r--   1 oracle   dba         1864 Feb 24 18:04 test1.lst
-rw-r--r--   1 oracle   dba         1868 Feb 24 18:04 test18.lst
-rw-r--r--   1 oracle   dba         1864 Feb 24 18:04 test3.lst
-rw-r--r--   1 oracle   dba         1868 Feb 24 18:04 test12.lst
-rw-r--r--   1 oracle   dba         1868 Feb 24 18:04 test15.lst
-rw-r--r--   1 oracle   dba         1864 Feb 24 18:04 test4.lst
-rw-r--r--   1 oracle   dba         1868 Feb 24 18:04 test19.lst
-rw-r--r--   1 oracle   dba         1868 Feb 24 18:04 test17.lst
-rw-r--r--   1 oracle   dba         1864 Feb 24 18:04 test9.lst
-rw-r--r--   1 oracle   dba         1864 Feb 24 18:04 test6.lst
-rw-r--r--   1 oracle   dba         1868 Feb 24 18:04 test16.lst
-rw-r--r--   1 oracle   dba         1864 Feb 24 18:04 test2.lst
-rw-r--r--   1 oracle   dba         1864 Feb 24 18:04 test8.lst
-rw-r--r--   1 oracle   dba         1868 Feb 24 18:04 test11.lst
-rw-r--r--   1 oracle   dba         1864 Feb 24 18:04 test7.lst
-rw-r--r--   1 oracle   dba         1868 Feb 24 18:04 test10.lst
-rw-r--r--   1 oracle   dba         1864 Feb 24 18:04 test5.lst
-rw-r--r--   1 oracle   dba         1868 Feb 24 18:04 test13.lst
-rw-r--r--   1 oracle   dba         1864 Feb 24 18:04 test0.lst
Oracle 11.2:
 
Then I looked at the last one:
 
Oracle 11.2: cat test0.lst
SQL> set lines 55
SQL> set termout off
SQL> set trimspool on
SQL> conn /
Connected.
SQL> select to_char(sysdate,'hh24:mi:ss')
  2  start_time from dual
  3  /
 
START_TIME
----------
18:01:55
 
SQL> create table tab&&1(col1 number)
  2  /
old   1: create table tab&&1(col1 number)
new   1: create table tab0(col1 number)
 
Table created.
 
SQL> select value from v$sysstat b
  2  where name = 'user commits'
  3  /
 
     VALUE
----------
    206889
 
SQL> select sum(time_waited/100) from v$session_event
  2  where event = 'log file parallel write'
  3  /
 
SUM(TIME_WAITED/100)
--------------------
             3434.49
 
SQL> select sum(time_waited/100) from v$session_event
  2  where event = 'log file sync'
  3  /
 
SUM(TIME_WAITED/100)
--------------------
              100.38
 
SQL> begin
  2  for a in 1..10000 loop
  3    begin
  4    insert into tab&&1 values (a);
  5    commit;
  6    delete tab&&1;
  7    commit;
  8    end;
  9  end loop;
10  end;
11  /
old   4:   insert into tab&&1 values (a);
new   4:   insert into tab0 values (a);
old   6:   delete tab&&1;
new   6:   delete tab0;
 
PL/SQL procedure successfully completed.
 
SQL> select value from v$sysstat
  2  where name = 'user commits'
  3  /
 
     VALUE
----------
    605793
 
SQL> select sum(time_waited/100) from v$session_event
  2  where event = 'log file parallel write'
  3  /
 
SUM(TIME_WAITED/100)
--------------------
             3495.45
 
SQL> select sum(time_waited/100) from v$session_event
  2  where event = 'log file sync'
  3  /
 
SUM(TIME_WAITED/100)
--------------------
              821.08
 
SQL> drop table tab&&1
  2  /
old   1: drop table tab&&1
new   1: drop table tab0
 
Table dropped.
 
SQL> select to_char(sysdate,'hh24:mi:ss')
  2  end_time from dual
  3  /
 
END_TIME
--------
18:03:04
 
SQL> exec dbms_lock.sleep(60);
 
PL/SQL procedure successfully completed.
 
SQL> exit
Oracle 11.2:
 
The script took 69 seconds to run. In that time, the database did 399,084 user commits. It waited 60 seconds for the log file parallel write event. It waited 721 seconds for the log file sync event.
 
I changed the SQL to do 1 commit at the end and repeated the exercise:
 
Oracle 11.2: cat test16.lst
SQL> set lines 55
SQL> set termout off
SQL> set trimspool on
SQL> conn /
Connected.
SQL> select to_char(sysdate,'hh24:mi:ss')
  2  start_time from dual
  3  /
 
START_TIME
----------
18:14:27
 
SQL> create table tab&&1(col1 number)
  2  /
old   1: create table tab&&1(col1 number)
new   1: create table tab16(col1 number)
 
Table created.
 
SQL> select value from v$sysstat b
  2  where name = 'user commits'
  3  /
 
     VALUE
----------
    605851
 
SQL> select sum(time_waited/100) from v$session_event
  2  where event = 'log file parallel write'
  3  /
 
SUM(TIME_WAITED/100)
--------------------
              3496.2
 
SQL> select sum(time_waited/100) from v$session_event
  2  where event = 'log file sync'
  3  /
 
SUM(TIME_WAITED/100)
--------------------
                97.4
 
SQL> begin
  2  for a in 1..10000 loop
  3    begin
  4    insert into tab&&1 values (a);
  5    delete tab&&1;
  6    end;
  7  end loop;
  8  commit;
  9  end;
10  /
old   4:   insert into tab&&1 values (a);
new   4:   insert into tab16 values (a);
old   5:   delete tab&&1;
new   5:   delete tab16;
 
PL/SQL procedure successfully completed.
 
SQL> select value from v$sysstat
  2  where name = 'user commits'
  3  /
 
     VALUE
----------
    605878
 
SQL> select sum(time_waited/100) from v$session_event
  2  where event = 'log file parallel write'
  3  /
 
SUM(TIME_WAITED/100)
--------------------
             3515.87
 
SQL> select sum(time_waited/100) from v$session_event
  2  where event = 'log file sync'
  3  /
 
SUM(TIME_WAITED/100)
--------------------
              120.89
 
SQL> drop table tab&&1
  2  /
old   1: drop table tab&&1
new   1: drop table tab16
 
Table dropped.
 
SQL> select to_char(sysdate,'hh24:mi:ss')
  2  end_time from dual
  3  /
 
END_TIME
--------
18:14:53
 
SQL> exec dbms_lock.sleep(60);
 
PL/SQL procedure successfully completed.
 
SQL> exit
Oracle 11.2:
 
The script took 26 seconds to run. In that time, the database did 27 user commits. It waited 19 seconds for the log file parallel write event. It waited 23 seconds for the log file sync event. So, by reducing the number of commits, the time spent waiting on these two events was significantly reduced.

ORA-00028

$
0
0
This example shows how to kill a user session. You can view sessions in your database as follows:

SQL> col username format a10
SQL> l
  1  select username, sid, serial#, status
  2  from v$session
  3* where username = 'ANDREW'
SQL> /

USERNAME          SID    SERIAL# STATUS
---------- ---------- ---------- --------
ANDREW            143         79 INACTIVE

SQL>


You can then use the SID and SERIAL# displayed to kill a session as shown below. The username you are interested in may have more than one session. If this happens, you will need to use one or more of the other columns in V$SESSION (e.g.OSUSER, MACHINE, LOGON_TIME etc) to see exactly which session you want to get rid of:

SQL> alter system kill session '143,79';
 

System altered.
 
SQL>

The killed session stays in V$SESSION with a status of KILLED:

SQL> select username, sid, serial#, status
  2  from v$session
  3  where username = 'ANDREW';


USERNAME          SID    SERIAL# STATUS
---------- ---------- ---------- --------
ANDREW            143         79 KILLED

SQL>

Until the user tries to access it again (the connection was made earlier). He will then get an ORA-00028:

SQL> conn andrew/reid@test10
Connected.
SQL> select sysdate from dual;
select sysdate from dual
*
ERROR at line 1:
ORA-00028: your session has been killed


SQL>

... and the session will disappear from V$SESSION:

SQL> select username, sid, serial#, status
  2  from v$session
  3  where username = 'ANDREW';


no rows selected

SQL>

Permissions Required to Create a Materialized View

$
0
0
The idea for this post came from a problem, which I saw on Javier Morales Carreras' blog here.

This example was tested on Oracle 11.2. It shows the permissions required to create a materialized view. First I created a user:
 
SQL> conn / as sysdba
Connected.
SQL> create user andrew identified by reid
  2  /
 
User created.
 
SQL> grant create session to andrew
  2  /
 
Grant succeeded.
 
SQL>
 
I logged in as the user and tried to create a materialized view. This failed (obviously):
 
SQL> conn andrew/reid
Connected.
SQL> create materialized view mv1 as select * from dual
  2  /
create materialized view mv1 as select * from dual
                                              *
ERROR at line 1:
ORA-01031: insufficient privileges
 
SQL>
 
I granted create materialized view to the user:
 
SQL> conn / as sysdba
Connected.
SQL> grant create materialized view to andrew
  2  /
 
Grant succeeded.
 
SQL>
 
…but when I logged in as the user and tried to create a materialized view again, this failed too:
 
SQL> conn andrew/reid
Connected.
SQL> create materialized view mv1 as select * from dual
  2  /
create materialized view mv1 as select * from dual
                                              *
ERROR at line 1:
ORA-01031: insufficient privileges
 
SQL>
 
This is because you also need the create table privilege before you can create a materialized view:
 
SQL> conn / as sysdba
Connected.
SQL> grant create table to andrew
  2  /
 
Grant succeeded.
 
SQL>
 
When I tried to create a materialized view this time, I saw a different error:
 
SQL> conn andrew/reid
Connected.
SQL> create materialized view mv1 as select * from dual
  2  /
create materialized view mv1 as select * from dual
                                              *
ERROR at line 1:
ORA-01950: no privileges on tablespace 'USERS'
 
SQL>
 
I attended to the ORA-01950 and the user was then able to create a materialized view:
 
SQL> conn / as sysdba
Connected.
SQL> alter user andrew quota unlimited on users
  2  /
 
User altered.
 
SQL> conn andrew/reid
Connected.
SQL> create materialized view mv1 as select * from dual
  2  /
 
Materialized view created.
 
SQL>
 
You need to be able to create tables because a materialized view has an underlying table itself:
 
SQL> select object_name, object_type from user_objects
  2  /
 
OBJECT_NAME     OBJECT_TYPE
--------------- --------------------
MV1             TABLE
MV1             MATERIALIZED VIEW
 
SQL>
 
Oracle does not allow you to drop the table as this would stop the materialized view working:
 
SQL> drop table mv1
  2  /
drop table mv1
           *
ERROR at line 1:
ORA-12083: must use DROP MATERIALIZED VIEW to drop
"ANDREW"."MV1"
 
SQL>
 
Conversely, if you drop a materialized view, the associated table disappears too:
 
SQL> drop materialized view mv1
  2  /
 
Materialized view dropped.
 
SQL> select object_name, object_type from user_objects
  2  /
 
no rows selected
 
SQL>

ORA-04098

$
0
0
I noticed this recently on an Oracle 11.1.0.6.0 database.
 
If you create a table, add a trigger then add a column, it all works:
 
SQL> create table tab1 (col1 varchar2(1))
  2  /
 
Table created.
 
SQL> create trigger trig1
  2  after update on tab1
  3  begin
  4  null;
  5  end;
  6  /
 
Trigger created.
 
SQL> alter table tab1
  2  add col2 varchar2(1)
  3  /
 
Table altered.
 
SQL> desc tab1
Name                       Null?    Type
-------------------------- -------- ------------------
COL1                                VARCHAR2(1)
COL2                                VARCHAR2(1)
 
SQL>
 
If the trigger is invalid (in this case because there is no semi-colon at the end of the null statement), you get an error when you try to create it but you can still add the column:
 
SQL> create table tab1 (col1 varchar2(1))
  2  /
 
Table created.
 
SQL> create trigger trig1
  2  after update on tab1
  3  begin
  4  null
  5  end;
  6  /
 
Warning: Trigger created with compilation errors.
 
SQL> alter table tab1
  2  add col2 varchar2(1)
  3  /
 
Table altered.
 
SQL> desc tab1
Name                       Null?    Type
-------------------------- -------- ------------------
COL1                                VARCHAR2(1)
COL2                                VARCHAR2(1)
 
SQL>
 
However, if you include a default clause when you add the column, you get an ORA-04098 instead and the column is not added to the table:
 
SQL> create table tab1 (col1 varchar2(1))
  2  /
 
Table created.
 
SQL> create trigger trig1
  2  after update on tab1
  3  begin
  4  null
  5  end;
  6  /
 
Warning: Trigger created with compilation errors.
 
SQL> alter table tab1
  2  add col2 varchar2(1) default 'Y'
  3  /
alter table tab1
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-04098: trigger 'ANDREW.TRIG1' is invalid and
failed re-validation
 
SQL> desc tab1
Name                       Null?    Type
-------------------------- -------- ------------------
COL1                                VARCHAR2(1)
 
SQL>
 
Of course, if the trigger is valid, the column gets added even with the default clause:
 
SQL> create table tab1 (col1 varchar2(1))
  2  /
 
Table created.
 
SQL> create trigger trig1
  2  after update on tab1
  3  begin
  4  null;
  5  end;
  6  /
 
Trigger created.
 
SQL> alter table tab1
  2  add col2 varchar2(1) default 'Y'
  3  /
 
Table altered.
 
SQL> desc tab1
Name                       Null?    Type
-------------------------- -------- ------------------
COL1                                VARCHAR2(1)
COL2                                VARCHAR2(1)
 
SQL>

Justify Left, Centre and Right

$
0
0
This was tested on Oracle 11.2. NUMBER items and their column headings are right justified by default:
 
SQL> set numwidth 15
SQL> select count(*) table_count from dba_tables
  2  /
 
    TABLE_COUNT
---------------
           3110
 
SQL>
 
If you want to see the heading in the centre of the column, you can do so with justify centre:
 
SQL> col table_count justify centre
SQL> select count(*) table_count from dba_tables
  2  /
 
  TABLE_COUNT
---------------
           3110
 
SQL>
 
If you want to see the heading to the left of the column, you can do so with justify left:
 
SQL> col table_count justify left
SQL> select count(*) table_count from dba_tables
  2  /
 
TABLE_COUNT
---------------
           3110
 
SQL>
 
VARCHAR2 items and their column headings are left justified by default:
 
SQL> select table_name from dba_tables
  2  where rownum = 1
  3  /
 
TABLE_NAME
------------------------------
CON$
 
SQL>
 
If you want to see the heading in the centre of the column, you can do so with justify centre:
 
SQL> col table_name justify centre
SQL> select table_name from dba_tables
  2  where rownum = 1
  3  /
 
          TABLE_NAME
------------------------------
CON$
 
SQL>
 
If you want to see the heading to the right of the column, you can do so with justify right:
 
SQL> col table_name justify right
SQL> select table_name from dba_tables
  2  where rownum = 1
  3  /
 
                    TABLE_NAME
------------------------------
CON$

ORA-00034

$
0
0
If a session does ALTER SESSION DISABLE COMMIT IN PROCEDURE then a procedure tries to do a COMMIT or ROLLBACK, Oracle returns an ORA-00034. You can see what I mean in the example below, which was tested on Oracle 11.2: 

SQL> create or replace procedure commit_proc as
  2  begin
  3  commit;
  4  end;
  5  /
 
Procedure created.
 
SQL> create or replace procedure rollback_proc as
  2  begin
  3  rollback;
  4  end;
  5  /
 
Procedure created.
 
SQL> exec commit_proc();
 
PL/SQL procedure successfully completed.
 
SQL> exec rollback_proc;
 
PL/SQL procedure successfully completed.
 
SQL> alter session disable commit in procedure
  2  /
 
Session altered.
 
SQL> exec commit_proc();
BEGIN commit_proc(); END;
 
*
ERROR at line 1:
ORA-00034: cannot COMMIT in current PL/SQL session
ORA-06512: at "ANDREW.COMMIT_PROC", line 3
ORA-06512: at line 1
 
SQL> exec rollback_proc;
BEGIN rollback_proc; END;
 
*
ERROR at line 1:
ORA-00034: cannot ROLLBACK in current PL/SQL session
ORA-06512: at "ANDREW.ROLLBACK_PROC", line 3
ORA-06512: at line 1
 
SQL> alter session enable commit in procedure
  2  /
 
Session altered.
 
SQL> exec commit_proc();
 
PL/SQL procedure successfully completed.
 
SQL> exec rollback_proc;
 
PL/SQL procedure successfully completed.
 
SQL>

Data Dictionary Cache Hit Ratio

$
0
0
Every Oracle database has a data dictionary, which is owned by the SYS user and stored in the SYSTEM tablespace. This consists of read-only tables, which record information about the database e.g. table definitions, details of integrity constraints, usernames and the roles and privileges granted to them etc. You can read about this in detail in Oracle's own documentation.

So, for example, if user SCOTT tries to read a table, Oracle checks the data dictionary first to see whether he has been granted SELECT access to it.

Each time the data dictionary is accessed, the GETS column is updated in V$ROWCACHE.


Oracle retains parts of the data dictionary in a cache in the SGA. If the information (to determine if SCOTT will be allowed to read the table) is not  found in this cache, Oracle has to get it from the underlying tables. When this happens, the GETMISSES column is updated in V$ROWCACHE.


Once your database has been open for a while, you can use the number of GETS and GETMISSES to calculate the data dictionary cache hit ratio as shown in the SQL below, which I ran on an Oracle 11.2 database: 

SQL> select sum(gets) as "Gets",
  2  sum(getmisses) as "Misses",
  3  (1-(sum(getmisses)/sum(gets)))*100 as "DDC Hit Ratio"
  4  from v$rowcache
  5  /
 
      Gets     Misses DDC Hit Ratio
---------- ---------- -------------
  39375878      96143   99.7558327
 
SQL>

The hit ratio should be around 99% but anything over 90% should be OK. If it is too low, you can try increasing the size of your database's shared pool.
Viewing all 330 articles
Browse latest View live