Home>Question Details



Rajesh -- Thanks for the question regarding "Unused OBJECTS", version 8.1.7.2

Submitted on 12-Aug-2002 12:22 Central time zone
Last updated 18-Sep-2009 10:43

You Asked

Hi Tom,

We are in a process of removing unused objects(tables/functions/procedures/packages) from 
the database. Is there any script(suggestions) or short-cut method to find  these unused 
objects(tables/functions/procedures/packages not used in ddl/dml/select statements for 
more than 3 months). 

There are more than 500 objects(tables/functions/procedures/packages) in our database. 

At least PLEASE help me in finding unused TABLES.For other objects I'm thinking to check 
manually in the application code(using find and grep commands)
  

Please Help me.

Thanks in advance for your reply 

and we said...

You'll have to enable auditing and then come back in 3 months to see.

We don't track this information by default -- also, even with auditing, it may be very 
possible to have an object that is INDIRECTLY accessed (eg: via a foreign key for 
example) that won't show up.

You can try USER_DEPENDENCIES but that won't tell you about objects referenced by code in 
client apps or via dynamic sql

I'm always perplexed by this.  How does one get into a production environment where  by 
they don't know what the objects are used by/for?  No documentation or anything?

 

Reviews    
4 stars I'll tell you why it happens...   August 12, 2002 - 2pm Central time zone
Reviewer: Randy from Texas
Project managers,directors,etc. that don't understand the little problems that arise many months 
later (after go-live) from having ambiguous crap in the production database won't allow us to 
control things the way we'd like.  They just want the developers to be able to "do their job", 
which means the privs. to create objects w/o going through the DBA.

You are a rare specimen, Tom.  I've realized that not many developers have respect for the database 
and will trash it on a whim. 


Followup   August 12, 2002 - 2pm Central time zone:

but production?  test, ok -- development -- ok, but production?  that costs money (and time).

I'm against withholding things from people (not just developer vs dba) -- like "don't use feature 
X, we are afraid of it" but some amount of source code control is just necessary. 

4 stars Thanks for your suggestions!!   August 12, 2002 - 2pm Central time zone
Reviewer: Rajesh 
Hi Tom,

Thank you very much for your responce. We thought the same thing to use USER_DEPENDENCIES.

You are right, we dont have access to the production machine.

It is a very big project, so many modules/layers/releases and we'll always maintain last 3 releases 
in production(end users can access any release).People created some new objects for new designs and 
some how they forgot to drop old and unused objects.

Thanks again!!


Rajesh 


4 stars Oops! I was late!! I didn't see the other review and follow up.   August 12, 2002 - 2pm Central time zone
Reviewer: Rajesh 


4 stars Responding to Randy's Post   August 12, 2002 - 5pm Central time zone
Reviewer: Shrek from MD
IMHO:
No access on Production -- no problem
   (no SELECT only also, some queries can really 
    affect performance)
Test (QA, Demo, or similar)
    Limited access through roles, 
    or execute privileges on packages OR as needed basis
Development:
    I think the developers need Connect, Resource, definitely PLUSTRACE, and some other 
privileges/roles on an as needed basis. Because they Can't do squat without it, and they need a 
destructive test env. Therefore, run in ARCHIVELOG mode, and give developers full freedom

On a separate note:
    Tom: I hope you reconsider the Yahoo/HotMail questions. Many people (myself included) are 
nomads (contractors) who want to use a Yahoo or a HotMail account.

Thanks,

Shrek 


Followup   August 12, 2002 - 6pm Central time zone:

I haven't disabled them -- It is really teed me off this morning when over HALF of the questions 
came bouncing right back at me, and they are always from yahoo.com, hotmail.com, msn.com -- never 
from <real company here>.com

 

3 stars Third Party tools   August 13, 2002 - 12am Central time zone
Reviewer: Gary Myers from Australia
I've used SQL*Impact for this sort of thing, as it can pick references to SQL from batch code, 
forms etc.

You'd probably need some idea of where to start looking. While SQL*Impact does have reports for 
'unused' columns and other anomalies, nothing will help if you've got a form using a table when 
no-one ever uses the form.

>I'm always perplexed by this.  
>How does one get into a production environment whereby
>they don't know what the objects are used by/for?

Easy. I've experienced the following
Make your documentation 'development' focused (ie 'create a procedure to mail clients latest offer' 
as opposed to 'Procedure MAIL_CLIENT is used during the annual STOCKTAKE reconciliation 
process...'). All too common. In one case, the documentation was discarded after the development as 
it had served its purpose.

Make it impossible for developers to keep documentation up to date ("You can't change it. It's 
already been signed off.") Especially applies to updates by support staff, often with the excuse 
that 'they only fix the code so the design won't be changed'

Don't have any procedures for dropping objects and programs, etc out of the application 
environment. Or just make it so hard that no-one bothers.

Don't differentiate between code written for a one-off task (eg data conversion) and regular, 
repeated, processing.


 


3 stars Script to find procedures/functions not being called   January 12, 2006 - 3am Central time zone
Reviewer: Mobra from Norway
Hi Tom,

I've made this quick script to find code in a package that's not being used anywhere (in the same 
package or other packages).

[Note: Of course any public routine might be called from a client, but we have a naming convention 
that allows us to filter out these from the results.]

The script works by first finding and extracting all the function/procedure names within a single 
package, then looking through all the user's code (user_source) to see if this function/procedure 
is being called.

This code works, but it's quite slow.

The question is: Is there a way to optimize the second query ? I've tried with a first_rows hint, 
but it did not appear to make much difference.




declare

  l_proc_used boolean := false;
  l_proc_name varchar2(255);

  cursor l_proc_cursor is
  select trim(replace(replace(lower(text), 'procedure ', ''), 'function ', '')) proc_name
  from user_source
  where (lower(text) like '%procedure %'
  or lower(text) like '%function %')
  and name = 'MY_PACKAGE_PKG'
  and type in ('PACKAGE BODY');
  
  cursor l_src_cursor (p_proc_name in varchar2) is
  select /*+ first_rows(1) */ 'x'
  from user_source
  where lower(text) like '%' || p_proc_name || '%'
  and lower(text) not like '%end ' || p_proc_name || '%'
  and lower(text) not like '%procedure ' || p_proc_name || '%'
  and lower(text) not like '%function ' || p_proc_name || '%';
  
  l_src_rec l_src_cursor%rowtype;
  
  function strip_params (p_proc in varchar2) return varchar2
  as
    l_returnvalue varchar2(255);
  begin
  
    l_returnvalue:=trim(copy_str(p_proc, 1, instr(p_proc, '(') - 1));
    
    return l_returnvalue;

  end strip_params;
  
begin

  for l_proc_rec in l_proc_cursor loop
  
    l_proc_name:=strip_params (l_proc_rec.proc_name);
    l_proc_used:=false;
    
    open l_src_cursor (l_proc_name);
    
    fetch l_src_cursor
    into l_src_rec;
  
    l_proc_used:=l_src_cursor%found;
    
    close l_src_cursor;
    
    if l_proc_used = false then
      dbms_output.put_line('Procedure/function ' || l_proc_name || ' is NOT in use...');
    end if;
  
  end loop;

end;
 


Followup   January 12, 2006 - 11am Central time zone:

what is the point?  so I have a procedure not called by anyother procedure - so?  does that mean 
anything?  It does NOT mean it is not in use, it just means someone is calling it from the client 
directly. 

1 stars The point is...   January 14, 2006 - 4am Central time zone
Reviewer: Mobra from Norway
... to be able to find "dead code".

Like I mentioned in the first post, we have a 
naming convention that allows us to see (or filter out) functions and procedures that are called 
directly from the client.

Which means that any remaining functions/procedures in packages (including subroutines private to a 
package) that are not being called, are not being used any more ("dead code") and can/should be 
removed.

The script supplied finds such code, the question was: Is there a way to optimize the second query 
(second cursor) so that the script runs faster?

 


Followup   January 15, 2006 - 3pm Central time zone:

I don't know.... I've never tried.  It seems that if you have to search for dead code, well, you 
only need to do that once (so what if it goes slow once) since you'll obviously put into place the 
necessary documentation framework in the future to avoid the issue :)

Guess if I had to do it, I would put the names of the procedures/functions into a collection or 
temporary table and then select out everything that wasn't in the rest (instead of running a query 
per function/procedure, run a single query that returns likely ones)

but again, I just plain wouldn't do it - dead code?  if you have a serious problem with dead code 
over and over and over and over and over again, you need to fix the cause - not the effect.  Your 
approach is fairly hit or miss as it is (procedure names embedded in other procedure names - you 
look across ALL packages instead of just one)...


But, if I had to do this for whatever reason, I'd go for the "query" route:

ops$tkyte@ORA10GR2> create or replace package foo
  2  as
  3          procedure p1;
  4          procedure p2;
  5  end;
  6  /

Package created.

ops$tkyte@ORA10GR2>
ops$tkyte@ORA10GR2> create or replace package body foo
  2  as
  3
  4  procedure p1
  5  is
  6  begin
  7          p2;
  8  end;
  9
 10  procedure p2
 11  is
 12  begin
 13          p1;
 14  end;
 15
 16  procedure p3
 17  is
 18  begin
 19          null;
 20  end;
 21
 22  end;
 23  /

Package body created.

ops$tkyte@ORA10GR2> with subroutines
  2  as
  3  (
  4  select name, substr( text, 1, instr( text, '(')-1 ) proc_name
  5    from (
  6  select name,
  7         trim( replace( replace(
  8             lower( translate(text,chr(13)||chr(10),'  ')),
  9             'procedure ', '' ),
 10             'function ', '' ) ) ||
 11          '(' text
 12    from user_source
 13   where (lower(text) like '%procedure %'
 14          or
 15          lower(text) like '%function %')
 16     and type = 'PACKAGE BODY'
 17         )
 18  ),
 19  packages
 20  as
 21  (
 22  select name, lower(text) text
 23    from user_source
 24   where type in ( 'PACKAGE BODY', 'PACKAGE' )
 25  )
 26  select s.*
 27    from subroutines S left outer join packages P
 28      on (     p.text like '%' || s.proc_name || '%'
 29           and p.text NOT like '%end ' || s.proc_name || '%'
 30           and p.text NOT like '%procedure ' || s.proc_name || '%'
 31           and p.text NOT like '%function ' || s.proc_name || '%'
 32         )
 33   where p.name is null
 34  /

NAME                           PROC_NAME
------------------------------ ----------
FOO                            p3

 

4 stars Unused Procedures   January 24, 2006 - 5am Central time zone
Reviewer: Pradikan from INDIA
Hi Tom,

We are having a lot of procedures / packages (approx - 5000), which are used for various 
applications. The point is that we want to eliminate procedures / packages which were unused for a 
long time. Is there any tool which identified these procedures / packages, which we can delete from 
the database.

Also wanted to know about any automated tool which identifies junk code (code which is of no use to 
the actual requirement)in these procedures..

Please let me know

Thanks in advance

Pradikan 


Followup   January 24, 2006 - 8am Central time zone:

I usually call that "documentation".

You have 5,000 procedures - and no idea what they are/do/who uses them/etc??

Sounds like time to stop, take a breath, document system to me. 

2 stars Can we declare an existing proc 'INVALID'   September 8, 2009 - 11am Central time zone
Reviewer: Alex from London, UK
Tom,

Documentation does not solve the problem completely. We did create some of our 1300 procs for 
different releases of different apps (we have 8 apps). The releases have gone out and have been 
superceeded by the new code by now. But you cannot realistically track what is used and what is 
not. You can answer the question 'is this proc definitely used' for any proc by spending 30 minutes 
of your time but you cannot do this 'in bulk' for all the procs.

I can say that a proc is not used 'with 95% confidence'. But before dropping it I would like to 
cover the rest 5%. And the only reliable way to find out is to ask oracle in some way if the proc 
was called or not over specified period of time...

I was thinking of something like 'ALTER procname UNCOMPILE'. That would make perfectly valid procs 
INVALID. Unfortunately there is no such option. If I were to do this for all the procs which I 
suspect are not used, I will be able to come back in a months time and see which ones have been 
called and are valid now.


Followup   September 8, 2009 - 9pm Central time zone:

... Documentation does not solve the problem completely. ...

Documentation solves the problem completely.


.. you cannot realistically track what is used and what is not. ...

why not? Much of the rest of the world can - it is called documentation. If you have a large system - you can and will do this. We do - we do for parameters, for functions for features. And trust me, the Oracle database is probably a little larger than your code. It not only can be done, it MUST be done.

... I can say that a proc is not used 'with 95% confidence'. But before dropping it
I would like to cover the rest 5% ...

I will say again you cannot do that. For you see, you will wait six months - then since no one used it for six months, you will drop it. However, at six months plus one day - I WILL USE THE FUNCTION/FEATURE OF YOUR APPLICATION THAT INVOKES THIS FUNCTION. Now what. You cannot just sit back and watch for things that are not "run" and then drop them. That is beyond naive.




Tell you what, since your developers keep track of nothing, ignore the code. just ignore it. Why worry about getting rid of it? Just IGNORE THE EXISTENCE OF IT, pretend it is all used and just live with it. What goal do you have by dropping it? what would you gain (NOTHING)? what would you lose (probably code that is actually necessary).

Just ignore it.

I won't comment on this any more. Just ignore it if you won't take the time to actually inventory what is used where, for which versions and why/when it is used.

If you can be sloppy in one place, you can do so anywhere - so just ignore it, it is not hurting you anymore than you already hurt.

3 stars Monitoring dead objects   September 9, 2009 - 10pm Central time zone
Reviewer: John Lim from Malaysia
Hi,

We have the same problem that some people have created 3000 tables over a period of 10+ years that 
no one is sure is in use any more.

At first, we were planning to use turn on audit and track it to clean it up, then we came up with 
the idea of using Oracle 10g's AWR and using the log of sql's like this to find out all table 
accesses:

select
timestamp,
  p.object_owner owner,
  p.object_name name,
  p.operation   opn,
  p.options     options,
(EXECUTIONS_TOTAL) recent_execs,
  dbms_lob.substr(t.sql_text, 4000 ) sqltxt
from
  dba_hist_sql_plan p
  join dba_hist_sqlstat s  on p.sql_id = s.sql_id
  join dba_hist_sqltext  t on t.sql_id=p.sql_id
where p.operation='TABLE ACCESS'  /* HOW ABOUT MAT VIEWS -- not sure -- check */
order by
  2,3,6,1

We intend to log AWR for 3+ months and then do the purge of all tables not in the AWR listing. We 
are in the first month of logging. 

Is this a good idea, or did we miss something?


Followup   September 14, 2009 - 10am Central time zone:

please re-read this page.

or just read the comment right above.

I feel I was rather unambiguous on this topic, completely and utterly and totally UNAMBIGUOUS.



but your use of the dba_hist tables - not even a tiny bit reliable in real life. They are populated with samples and will never every have a complete and total history.


I don't get it, just IGNORE THEM if you don't know them. It is bad that you know nothing about them, but they are not hurting your right now, dropping them could only leave you exactly where you are (no smarter) or in a world of hurt 3 months from now when someone says "hey, where did this go"
4 stars   September 11, 2009 - 5am Central time zone
Reviewer: David Aldridge from Friday
I think that if documenting code makes people sad then they ought to be in their bedroom writing 
card games in VB. The sad thing is that it doesn't have to be a huge overhead, it just has to be 
well thoughtout and #actually done#.

I think that it helps people's perspective to see how things are done at the high reliability end 
of the software engineering spectrum, and as Oracle developers we're in a great position for this 
as our primary programming language, PL/SQL, is derived from ADA. 

SPARK is an ADA-based language that has been used to deliver extremely reliable software, with less 
than one error for every 10,000 lines of delivered code 
(http://www.spectrum.ieee.org/computing/software/the-exterminators).

So, start by having a look at this link: http://en.wikipedia.org/wiki/SPARK_(programming_language) 
and see what sort of techniques you might learn. For example, the code is written with extensive 
metadata at the declaration level that tells automated verification tools exactly what is going on 
inside the code. So how about when you write a procedure you include a comment in it such as:

/*
|| :META: selects employee
|| :META: inserts employee
|| :META: updates department
|| :META: updates address
|| :META: calls   is_number
|| :META: calls   log_entry
|| :META: calls   dbms_application_info
|| :META: changes global_counter
*/

Try doing that for SQL statements also, and include a unique name while you're at it ...

/*
|| :META: name    update_employee_job_title
|| :META: updates employee
|| :META: selects employee
|| :META: selects department
|| :META: uses    regexp
*/

People look at these issues and think "But it'll take forever!" and mope around like sullen 
teenagers prevaricating over picking up clothes from their bedroom floor, but you know what? It 
takes maybe a minute, maybe 30 seconds per statement.

Anyway, when you commit yourself to putting that in code it's probably pretty easy to tell if 
someone hasn't done it, and this will be checked this in the code reviews that someone who doesn't 
like you (ideally) will be doing.

Not fool proof.

Not a 100% solution to the "what code does what" problem.

But if it has value then give it a go, and in a year's time maybe someone will be saying "Wow, that 
null job title bug was sure easy to track down. Thanks goodness Jim is such a professional!". Fame 
and glory beckon.


2 stars Don't get it   September 15, 2009 - 10am Central time zone
Reviewer: John Lim from Malaysia
> I don't get it, just IGNORE THEM if you don't know them. 

I would agree with you and we tried to tell the customer this several times. But the customer 
thinks differently... These tables were not created by us, but they want it "fixed" during a 
migration to new database server that we have been employed to carry out, and we are trying to 
solve this issue without too much overhead. 

We were afraid that table audit would take eat up too much disk space. As this seems to be the way 
to go, we will turn on table audit as you suggested. Thank you Tom.


Followup   September 15, 2009 - 11am Central time zone:

tell customer you have analyzed the situation and every table is necessary.


auditing isn't going to answer the question, this is going to be a disaster.
3 stars   September 18, 2009 - 2am Central time zone
Reviewer: David Aldridge from Friday
Just to drift slightly further off topic, I just read about PL/Scope in 11g, that tracks identifier 
usage. 

Docs here: http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10471/adfns_plscope.htm

Very nice, but an enhancement that includes database object usage would be very dear to me.

not that it solves the problem entirely of course.



Write a Review
 


All information and materials provided here are provided "as-is"; Oracle disclaims all express and implied warranties, including, the implied warranties of merchantability or fitness for a particular use. Oracle shall not be liable for any damages, including, direct, indirect, incidental, special or consequential damages for loss of profits, revenue, data or data use, incurred by you or any third party in connection with the use of this information or these materials.

About Oracle | Legal Notices and Terms of Use | Privacy Statement