How to speed up client deletions
When deleting large clients, long runtimes are often a problem. Parallelism can help, but the real bottleneck are large tables. So maybe this guide can help. The SQL statements are for Oracle databases with SAPSR3 layout, for other databases or layouts you have to modify them.
Manual deletion of tables
First of all, you need to identify large, client specific tables. E. g. in IS-U systems candidates are DFKKOP or SWWCNTP0. These tables are client
specific, so you can easily find out if the table can be truncated without harming the other clients:
SELECT mandt, count( * ) FROM sapsr3.dfkkop GROUP BY mandt;
or
SELECT client, count( * ) FROM sapsr3.swwcntp0 GROUP BY mandt;
Copy & deletion of “unbalanced” tables
CREATE TABLE sapsr3."dfkkop_tmp" TABLESPACE psapsr3 NOLOGGING PARALLEL 8 AS
SELECT /*+ INDEX("dfkkop" "dfkkop~0") */ * FROM sapsr3."dfkkop" WHERE mandt NOT IN ('100'):
TRUNCATE TABLE sapsr3."dfkkop";
INSERT INTO sapsr3."dfkkop" SELECT * FROM "dfkkop_tmp";
COMMIT;
ALTER INDEX sapsr3."dfkkop~0" REBUILD ONLINE;
Automation of finding tables / preparing statements
use DBI;
my $sid = "<SID>";
my $hostname = "localhost";
my $port = "<listener port>";
my $sappw = "<password>";
my $sapuser = "SAPSR3";
my $connection = DBI->connect("DBI:Oracle:SID=$sid;host=$hostname;port=$port","$sapuser/$sappw")
|| die "Can't connect to $sid: $!";
my $mandt_exclude = '100';
my $sql_all_tables = "SELECT object_name FROM dba_objects
WHERE owner = 'SAPSR3' AND object_type = 'TABLE' ORDER BY object_name ASC";
my $all_cursor = $connection->prepare($sql_all_tables);
$all_cursor->execute();
while (my @table = $all_cursor->fetchrow_array) {
$sql_first_column = "SELECT table_name, column_name FROM dba_cons_columns
WHERE table_name = '$table[0]'
AND constraint_name = ( SELECT MIN( constraint_name ) FROM dba_cons_columns
WHERE table_name = '$table[0]' )";
my $first_col_cursor = $connection->prepare($sql_first_column);
$first_col_cursor->execute();
while (my @col = $first_col_cursor->fetchrow_array) {
if ($col[1] eq "CLIENT" or $col[1] eq "MANDANT" or $col[1] eq "MANDT") {
$sql_count_all = "SELECT count( * ) FROM \"$table[0]\"";
my $count_all_cursor = $connection->prepare($sql_count_all);
$count_all_cursor->execute();
while (my @exc = $count_all_cursor->fetchrow_array) {
<Put your custom logic here>
}
$sql_count_exclude_mandt = "SELECT count( * ) FROM \"$table[0]\"
WHERE $col[1] NOT IN ($mandt_exclude)";
my $count_exclude_cursor = $connection->prepare($sql_count_exclude_mandt);
$count_exclude_cursor->execute();
while (my @exc = $count_exclude_cursor->fetchrow_array) {
<Put your custom logic here>
}
}
You just have to add some output to build the SQL scripts.
Well written Daniel.. This is Great..!!
5 starts 🙂
and thanks for sharing.
Best Regards,
Thanks! We used this script in a critical operation, it worked perfectly... 🙂
I have bookmarked it for reference.
Thanks man !
Good stuff, Daniel.
Just the reminder that perl comes with your oracle licence is worthwhile 🙂
It's very useful, since you have all the modules you need... 😉