Fast way to drop schema with large amount of objects for the purpose of testing I have to drop a schema with a large amount of objects often. It consists of > 2000 tables, a large amount of foreign key and check constraints, triggers views and so on. All tables are within the same tablespace, but the tablespace is used by other schemas too.

I did try admin_drop_schema procedure at first, but it takes a lot more time than parsing all schema catalogs, generate all drop statements and execute it as one sql script. The script runs under 45 minutes and the procedure more than a hour. Further more the procedure locks to many things.

What is the fastest way to drop such a schema?
Several years ago I did put together a package of db2utils which included a procedure called DROP_SCHEMA. This was written before ADMIN_DROP_SCHEMA became available in DB2, and uses a fairly crude mechanism for determining what to drop, and in what order. To whit: it uses a large UNION query to get all objects belonging to the schema from the various SYSCAT views:

WITH DROP_LIST (CREATE_TIME, SCHEMA_NAME, DDL) AS (
    SELECT
        CREATE_TIME,
        TABSCHEMA AS SCHEMA_NAME,
        'DROP ' || CASE TYPE
            WHEN 'A' THEN 'ALIAS'
            WHEN 'H' THEN 'TABLE'
            WHEN 'N' THEN 'NICKNAME'
            WHEN 'S' THEN 'TABLE'
            WHEN 'T' THEN 'TABLE'
            WHEN 'U' THEN 'TABLE'
            WHEN 'V' THEN 'VIEW'
            WHEN 'W' THEN 'VIEW'
        END || ' ' || QUOTE_IDENTIFIER(TABSCHEMA) || '.' || QUOTE_IDENTIFIER(TABNAME) AS DDL
    FROM SYSCAT.TABLES
    UNION
    SELECT
        CREATE_TIME,
        TRIGSCHEMA AS SCHEMA_NAME,
        'DROP TRIGGER ' || QUOTE_IDENTIFIER(TRIGSCHEMA) || '.' || QUOTE_IDENTIFIER(TRIGNAME) AS DDL
    FROM SYSCAT.TRIGGERS
    UNION
    SELECT
        CREATE_TIME,
        ROUTINESCHEMA AS SCHEMA_NAME,
        'DROP ' || CASE ROUTINETYPE
            WHEN 'F' THEN 'SPECIFIC FUNCTION'
            WHEN 'M' THEN 'SPECIFIC METHOD'
            WHEN 'P' THEN 'SPECIFIC PROCEDURE'
        END || ' ' || QUOTE_IDENTIFIER(ROUTINESCHEMA) || '.' || QUOTE_IDENTIFIER(SPECIFICNAME) AS DDL
    FROM SYSCAT.ROUTINES
    UNION
    SELECT
        CREATE_TIME,
        TYPESCHEMA AS SCHEMA_NAME,
        'DROP TYPE ' || QUOTE_IDENTIFIER(TYPESCHEMA) || '.' || QUOTE_IDENTIFIER(TYPENAME) AS DDL
    FROM SYSCAT.DATATYPES
    UNION
    SELECT
        CREATE_TIME,
        SEQSCHEMA AS SCHEMA_NAME,
        'DROP SEQUENCE ' || QUOTE_IDENTIFIER(SEQSCHEMA) || '.' || QUOTE_IDENTIFIER(SEQNAME) AS DDL
    FROM SYSCAT.SEQUENCES
    WHERE SEQTYPE &lt;&gt; 'I'
    UNION
    SELECT
        CREATE_TIME,
        SCHEMANAME AS SCHEMA_NAME,
        'DROP SCHEMA ' || QUOTE_IDENTIFIER(SCHEMANAME) || ' RESTRICT' AS DDL
    FROM SYSCAT.SCHEMATA
)
SELECT CREATE_TIME, DDL
FROM DROP_LIST
WHERE SCHEMA_NAME = ASCHEMA!


(Full source; the QUOTE_IDENTIFIER function is another utility in the package)

It then orders the result in descending order by creation time, running the SQL DROP statements with EXECUTE IMMEDIATE:

BEGIN ATOMIC
    FOR D AS
        SELECT DDL
        FROM TABLE(X_DROP_LIST(ASCHEMA))
        ORDER BY CREATE_TIME DESC
    DO
        EXECUTE IMMEDIATE D.DDL;
    END FOR;
END


This is simple, but crude especially in light of DB2's later introduction of deferred revalidation of objects. This can result in creation timestamp orderings for which the drop sequence is no longer correct. In practice, it mostly worked for me and on the rare occasions it didn't I could fall back to running the query manually to figure out what needed dealing with.

This brings me to the other major difference to ADMIN_DROP_SCHEMA: error handling. ADMIN_DROP_SCHEMA takes several parameters which are used to construct and fill a table with error codes and messages for post-analysis. 

While comprehensive, I found this didn't work well with most of my use-cases. Most of the time I was using these tools to tear down development / testing schemas, then tweaking a creation script and re-running it, or using it to destroy relatively simple personal schemas when users were deleted. Hence I designed DROP_SCHEMA deliberately to be atomic: it either works and the schema disappears in its entirety, or it fails with an error and the schema remains in its entirety (assuming you rollback the containing transaction).

I did generally find it faster than ADMIN_DROP_SCHEMA but that wasn't an intention of the design, and given I haven't maintained it for several years there may well be new schema-based objects in DB2 which it doesn't correctly handle. Still, it may serve as a useful starting point for others' efforts.