[oaktable] Re: Happy New Year, DROP (unique) INDEX causing a mess and library cache revalidation

  • From: Jocke Treugut <jocke@xxxxxxxxxxxxxxxxxx>
  • To: oaktable@xxxxxxxxxxxxx
  • Date: Thu, 07 Jan 2021 10:43:09 +0100

 

Hi again. 

If anyone was interested in recreating the problem (it behaves the same
in 12.2 and 19): 

CREATE TABLE objects AS SELECT ROWNUM AS object_id, x.* FROM ( SELECT
DISTINCT owner, object_name FROM all_objects WHERE subobject_name IS
NULL AND ROWNUM < 100 ) x;
SELECT COUNT( * ), COUNT( object_id ), COUNT( DISTINCT object_id ),
COUNT( owner || object_name ), COUNT( DISTINCT owner || object_name )
FROM objects;
CREATE UNIQUE INDEX ix_objects_unique ON objects( object_id );
CREATE UNIQUE INDEX ix_objects_nonuniq ON objects( owner, object_name );
CREATE OR REPLACE VIEW v_obj_id AS SELECT object_id, owner, object_name
FROM objects;
CREATE OR REPLACE VIEW v_obj_name AS SELECT owner, object_name FROM
objects;
CREATE OR REPLACE VIEW v_obj_name2 AS SELECT owner, object_name FROM
objects WHERE object_id != 42;
CREATE OR REPLACE PROCEDURE p_obj_id AS
 v_owner VARCHAR2(100);
BEGIN
 SELECT owner INTO v_owner FROM v_obj_id WHERE ROWNUM =1;
END;
/
CREATE OR REPLACE PROCEDURE p_obj_name AS
 v_owner VARCHAR2(100);
BEGIN
 SELECT owner INTO v_owner FROM v_obj_name WHERE ROWNUM =1;
END;
/
CREATE OR REPLACE PROCEDURE p_obj_name2 AS
 v_owner VARCHAR2(100);
BEGIN
 SELECT owner INTO v_owner FROM v_obj_name2 WHERE ROWNUM =1;
END;
/

SELECT status, created, last_ddl_time, timestamp, object_type,
object_name FROM user_objects WHERE object_name LIKE '%OBJ%' ORDER BY
object_type, object_name;
DROP INDEX ix_objects_unique;
SELECT status, created, last_ddl_time, timestamp, object_type,
object_name FROM user_objects WHERE object_name LIKE '%OBJ%' ORDER BY
object_type, object_name;
-- All the views that are using OBJECT_ID are now INVALID, and the
procedures (of course) that are dependent on these views

Take care /Jocke 

2021-01-06 18:48 skrev Jocke Treugut: 

Mighty knights and ladies. 

After almost 30 years with Oracle databases, I came across something that I 
had no clue about. Wow, I still learn :-) But maybe this is old knowledge for 
you. 

If someone had asked me before yesterday, will drop index invalidate views. I 
would answer "no". So wrong I was. 

Our production database 12.2 with compatible set to 12.1 encountered this 
situation: 

Developers uses continuous delivery to deploy to production almost whenever 
they want. 

Their script contained four statements: DROP INDEX <name> ONLINE; 

After that we had huge problems for 13 minutes until one dba executed alter 
system flush shared_pool. 

One of the indexes were unique (created with create unique index, did not 
have a unique constraint) and consisted of four columns. 

The table that this unique index belonged to, had several views that included 
this table and some/all of the columns in the unique index - none of them had 
joins inside them, just some columns from a single table with some 
where-conditions. 

One view was referenced from a procedure inside a package. 

All the views that included at least one column from this unique index, went 
invalid, and so did the package body. 

One of the procedures inside this package is called about 4000+ times every 
second from 200-300 sessions. The procedure has an OUT-parameter, a ref 
cursor. The select used for this ref-cursor has a stored function in the 
select-list that comes from the same package. 

One of these sessions discovered that the view was invalid and did an 
automatic recompile and another session recompiled the package body some 
milliseconds later. I guess that the first session probably wanted to 
recompile the body also and started with the dependent view. 

But the problem was not solved. 100+ sessions started to wait on "library 
cache revalidation" and a lot of them received ORA-4023 object can not be 
validated or authorized. I am quite sure that the developers have not added 
any calls to dbms_session.reset_package (or is it dbms_utility), maybe they 
should? 

Flushing out the SQL that called the procedure with dbms_shared_pool didn't 
help. Recompiling the body manually didn't help. Until one dba in frustration 
issued flush shared_pool. 

* Is getting invalid views when dropping a unique index, expected behaviour, 
bug or documentation bug? 

* Our CTO and our architects were quite upset that Oracle couldn't handle 
this situation. 4000 executions per second were not an excuse. How do you 
handle situations in a very active database when you need to replace a 
package body? The non-Oracle developers want to deploy whenever during the 
day, even when stock markets open and close. We don't have any maintenance 
windows - never. The DBAs have no problems to do some critical changes 
off-hours but the developers don't want to remember routines and have 
restrictions. 

* Does anyone have an idea what happened? There was no blocking sid, just a 
lot of sessions waiting for lc revalidation for a very long time. A call to 
the stored procedure takes about 0.5 milliseconds, so it is not a long 
running query or so. 

* If anyone wants to share how you do continuous delivery in a very active 
database, I would be more than happy. 

Afterwards I tried to understand why a view would be invalid if it contained 
a column that also belonged to a unique index. I tried to have the view both 
as editionable (found one bug on this) and noneditionable. Tried to set the 
index both as unusable and invisible before dropping, trying to drop with 
"deferred invalidation" (I think it was called), using online or not when 
dropping, created the view with WITH READ ONLY and CHECK OPTION, but couldn't 
come up with any workaround. It was a non-partitioned table and a normal 
unique index. 

Stay healthy and happy! 

/Jocke

 

Other related posts: