Test Direct load
kiro, October 10, 2002 - 9:34 am UTC
Hi Tom
I have tried to reproduce reenabling of index. I am using direct path load. After first start of data everithing was OK.
But after second load with same data I expected rows into ex table, but see result below:
Invoice_10 is partition table with 12 part
mfapp> truncate table invoice_10;
Table truncated.
mfapp> alter table INVOICE_10 drop CONSTRAINT PK_INVOICE_10;
Table altered.
mfapp> ALTER TABLE INVOICE_10 ADD (
2 CONSTRAINT PK_INVOICE_10
3 PRIMARY KEY (YEAR, INVOICE_NO ,TILL_NO)
4 USING INDEX
5 TABLESPACE MEGAFINS_INDEX_LARGE
6 STORAGE (
7 INITIAL 10 M
8 NEXT 10 M
9 MINEXTENTS 1
10 MAXEXTENTS UNLIMITED
11 )
12 LOCAL
13 );
Table altered.
control file for loading is:
OPTIONS ( ERRORS=10000, ROWS=5000, BINDSIZE=220000 )
LOAD DATA
APPEND
INTO TABLE INVOICE_10
reenable disabled_constraints exceptions ex
WHEN (1) <> '*'
FIELDS TERMINATED BY '^'
.....
after first load:
mfapp> select count(*) from invoice_10;
COUNT(*)
----------
790
mfapp> select count(*) from ex;
COUNT(*)
----------
0
mfapp> desc ex;
Name Null? Type
------------------------------- -------- ----
ROW_ID ROWID
OWNER VARCHAR2(30)
TABLE_NAME VARCHAR2(30)
CONSTRAINT VARCHAR2(30)
this is OK.
NEXT step:
mfapp> alter table invoice_10 disable CONSTRAINT PK_INVOICE_10;
Table altered.
and start again Direct Path loading with same data:
mfapp> select count(*) from invoice_10;
COUNT(*)
----------
1580
mfapp> select count(*) from ex;
COUNT(*)
----------
0
Q1) Why? Is there somenting with partition tables? Can you explain,please?
thanks
kiro
October 11, 2002 - 7:21 pm UTC
sqlldr will only disable constraints that relate to other tables (eg: foreign keys) NOT the primary key.
SQLLDR will only re-enable the constraints which IT disabled, not the ones you did yourself.
Direct load - SQL Loader and insert /*+ append */
Dushan, October 16, 2002 - 4:28 am UTC
During a direct load (SQL Loader), primary key constraints are not disabled.
But before direct path load as insert /*+ append */, primary (unique) keys must be disabled, what means the PK, UK's indexes are dropped. And that's the pain - in the moment of enabling PK, UK's - the storage information about the indexes before is gone, and those indexes are created with defaults!
I would expect that when enabling PK, UK's, the indexes are created with the same parameters as they were defined before disabling PK, UK's.
Is't there any way how to achieve this?
October 16, 2002 - 12:55 pm UTC
really? (but, instead of drop -- set unusable, skip_unusable_indexes=true, do the thing and rebuild!!! don't drop!!!!)
but anyway (did it in 817 up at least)
ops$tkyte@ORA920.LOCALHOST> create table t ( x int primary key );
Table created.
1* insert /*+ append */ into t select rownum from all_users
ops$tkyte@ORA920.LOCALHOST> /
36 rows created.
ops$tkyte@ORA920.LOCALHOST> select * from t;
select * from t
*
ERROR at line 1:
ORA-12838: cannot read/modify an object after modifying it in parallel
ops$tkyte@ORA920.LOCALHOST> commit;
Commit complete.
ops$tkyte@ORA920.LOCALHOST> insert /*+ append */ into t select rownum from all_users;
insert /*+ append */ into t select rownum from all_users
*
ERROR at line 1:
ORA-00001: unique constraint (OPS$TKYTE.SYS_C003125) violated
I didn't drop any constraints here.
Dushan, October 17, 2002 - 3:51 am UTC
The point is that the speed of direct path load insert (insert /*+ append */) for table with disabled PK, UK's, plus time spent on enabling PK, UK's (creating indexes) is much faster then speed of the same statement with enabled PK, UK's.
But there are some annoying side effects regarding unique indexes when enabling PK, UK's.
As I understood they do not exist for direct path load using SQL*Loader.
system@OD6I> @connect system/osystemi@od6i
Connected.
GLOBAL_NAME
----------------------------------------------------------------------------------------------------
system@OD6I
Elapsed: 00:00:00.00
system@OD6I> grant connect, resource to a identified by a;
Grant succeeded.
Elapsed: 00:00:00.60
system@OD6I> @connect a/a@od6i
Connected.
GLOBAL_NAME
----------------------------------------------------------------------------------------------------
a@OD6I
Elapsed: 00:00:00.10
a@OD6I> create table dv_all_objects as
2 select * from all_objects
3 where 1=0
4 /
Table created.
Elapsed: 00:00:00.20
a@OD6I> ed
Wrote file afiedt.buf
1 ALTER TABLE DV_all_objects
2 ADD (CONSTRAINT DV_all_obj_pk PRIMARY KEY
3* (object_ID) using index tablespace users)
a@OD6I> /
Table altered.
Elapsed: 00:00:00.50
a@OD6I> select index_name, status, tablespace_name from user_indexes
2 where table_name='DV_ALL_OBJECTS';
INDEX_NAME STATUS TABLESPACE_NAME
------------------------------ -------- ------------------------------
DV_ALL_OBJ_PK VALID USERS
Elapsed: 00:00:00.20
-- OK, index DV_ALL_OBJ_PK for PK DV_ALL_OBJ_PK is in tablespace users
a@OD6I> insert /* +append */ into DV_all_objects
2 select * from all_objects;
21954 rows created.
Elapsed: 00:00:28.41
a@OD6I> truncate table DV_all_objects;
Table truncated.
Elapsed: 00:00:07.80
a@OD6I> alter index DV_ALL_OBJ_PK unusable;
Index altered.
Elapsed: 00:00:00.40
a@OD6I> alter session set skip_unusable_indexes=true
2 ;
Session altered.
Elapsed: 00:00:00.00
a@OD6I> insert /* +append */ into DV_all_objects
2 select * from all_objects;
insert /* +append */ into DV_all_objects
*
ERROR at line 1:
ORA-01502: index 'A.DV_ALL_OBJ_PK' or partition of such index is in unusable state
Elapsed: 00:00:00.20
-- Oops! It does not work for indexes belonging to PK, UK's !
-- BTW, no surprise, I've found this in J. Lewis, Practical Oracle
a@OD6I> alter table DV_all_objects disable constraint DV_ALL_OBJ_PK;
Table altered.
Elapsed: 00:00:00.00
a@OD6I> select index_name, status, tablespace_name from user_indexes
2 where table_name='DV_ALL_OBJECTS';
no rows selected
Elapsed: 00:00:00.20
-- Index for PK is gone !!!!!!!!!!
a@OD6I> insert /* +append */ into DV_all_objects
2 select * from all_objects;
21953 rows created.
Elapsed: 00:00:13.19
a@OD6I> alter table DV_all_objects enable constraint DV_ALL_OBJ_PK;
Table altered.
Elapsed: 00:00:03.35
-- Well, much faster 16:54 sec comparing to 28:41 sec
a@OD6I> select index_name, status, tablespace_name from user_indexes
2 where table_name='DV_ALL_OBJECTS';
INDEX_NAME STATUS TABLESPACE_NAME
------------------------------ -------- ------------------------------
DV_ALL_OBJ_PK VALID SYSTEM
Elapsed: 00:00:00.10
-- Index for PK was created, BUT in default tablespace for user A
-- i.e.'SYSTEM' instead of 'USERS', as it was before disabling PK
October 17, 2002 - 7:10 am UTC
use a deferrable constraint -- really nice for when you want to dislable a primary key from time to time without totally dropping the index:
ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t ( x int, constraint t_pk primary key (x) deferrable );
Table created.
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> alter table t disable constraint t_pk;
Table altered.
ops$tkyte@ORA817DEV.US.ORACLE.COM> alter index t_pk unusable;
Index altered.
ops$tkyte@ORA817DEV.US.ORACLE.COM> alter session set skip_unusable_indexes=true;
Session altered.
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert /*+ append */ into t select rownum from all_users;
46 rows created.
ops$tkyte@ORA817DEV.US.ORACLE.COM> alter index t_pk rebuild;
Index altered.
ops$tkyte@ORA817DEV.US.ORACLE.COM> alter table t enable constraint t_pk;
Table altered.
Dushan - mind the HINT syntax pitfall
andrew, October 17, 2002 - 2:35 pm UTC
Just a note that the hint syntax gets ignored unless the "+" is the first character after the comment.
-- hint used
select /*+ full(emp) */ ename from emp where empno = 7934;
Operation Object Name Rows Bytes Cost TQ In/Out PStart PStop
SELECT STATEMENT Hint=CHOOSE 1 1
TABLE ACCESS FULL EMP 1 8 1
-- hint ignored
select /* +full(emp) */ ename from emp where empno = 7934;
Operation Object Name Rows Bytes Cost TQ In/Out PStart PStop
SELECT STATEMENT Hint=CHOOSE 1 1
TABLE ACCESS BY INDEX ROWID EMP 1 8 1
INDEX UNIQUE SCAN EMP_PRIMARY_KEY 1
Do we need unique indexes?
Dushan, October 18, 2002 - 12:27 pm UTC
Thanks for response. Nevertheless, some more thoughts.
In case of existing non-unique indexes on column(s) which should be PK, UK, we can create primary or unique key on this column(s)using index(no matter if deferrable or non deferrable). The index (even if non-unique) is reused by PK, or UK. When disabling PK, UK, the index is not dropped, which is cool, much bigger flexibility comparing to PK+unique index. For me, the strategy for creating PK, UK's on table seems like :
1) Create non-unique index on PK, UK's column(s)
2) Create PK, UK's using index
So, do we need unique indexes at all? Or, is there any performance cons when going the way above?
October 18, 2002 - 12:43 pm UTC
I would
3) use deferrable constraints
which will either kidnap or create a non-unique index for you.
the optimizer understands that the values are unique (given primary key) even if a unique index is not present.
Arash, May 13, 2003 - 11:32 am UTC
Hi Tom,
In general what events may cause to have a disable constraint like disable foreign key ? I know that you can manually disable or enable a constraint. But what else could disable a foreign key automatically?
Thanks for your time,
Arash
May 13, 2003 - 4:26 pm UTC
nothing will do it "automagically", you have to ask for it to be done.
disabling indexes
Lakshmi, May 19, 2003 - 8:41 am UTC
Excellent !!!
What about a LOAD with truncate
Rich, September 05, 2003 - 10:41 am UTC
Hi Tom,
How would you do a load (conventional way) on a table that have many indexes, when using a Truncate in the ctl file. Since the table is truncate, the unusables indexes are then put back as valid. Would you DROP/CREATE the indexes?
September 05, 2003 - 4:29 pm UTC
truncate the table, set the indexes unusable, load, rebuild...
or look at skip_index_maintenance.
Direct-path and duplicates in job stream
Mark Umbach, September 14, 2004 - 5:38 pm UTC
We recently moved to 9.2.0.4 and have found that if Loader, direct-path, is used and duplicated exist in the input, the Loader job does not signal a warning but it loads the rows and sets the PK index to UNUSABLE. Is that the normal function? I recall that 8.1.7 returned a warning status out of the Loader step.
Obviously, when another load is tried (or something that uses the index) it fails because an index or index partition is unusable. If unique data is loaded in one session and is duplicated in another, that does result in the Loader step signaling a warning. This seems misleading and inconsistent.
Duplicate data within a load is not considered an error (warning) even though it results in the index becoming unusable, but between loads does.
September 14, 2004 - 7:27 pm UTC
direct path load always worked that way.
direct path loads write table data above the HWM and create a "mini index" of the loaded data off to the side (they are NOT using sql here). at the end, the mini index of new data is merged with the existing index and if a dup was found -- the index set to unusable.
it worked this way in 8i (i just tested) it was documented to work this way in 8i.
a direct path load is a sign that you are "doing some serious big loading and stuff". it is usually coupled with some "verification" afterwards.
if you are doing load, load, load, load -- you should use skip index maintainence and just rebuild them afterwards perhaps
sql*loader using direct path and primary key
Daniel laloyaux, November 18, 2004 - 7:03 am UTC
Hello,
the last comment you mentionned concerning Oracle 9i r2 behavior using direct path and primary key is that it is a normal behavior that primary keys are left in an unusable state if duplicates are found (!?). Ok, you state just the obvious, but then, the index cannot be rebuild because duplicates are still there.
So, your answer doesn't help at all.
thanks
November 18, 2004 - 10:49 am UTC
umm, REMOVE THE DUPLICATES (seems obvious? no?)
quote:
The primary key constraint must be disabled and
then reenabled using the exceptions clause in order to populate the exceptions
table.
/quote
which part of that wasn't really clear? of course you cannot rebuild a unique index with duplicates in it, you need to REMOVE them. and I told you how.