This blog contains experience gained over the years of implementing (and de-implementing) large scale IT applications/software.

SAP SLD Change Log Cleanup Table Reorg

When you apply changes or content updates to the SLD (system landscape directory) in SAP, the change log grows.
It’s possible to see the change log entries from the SLD administrator page.
Due to this growth, the underlying database table will benefit from reorganisation at some point.
In our scenario, this was on DB2.
We decided to run the cleanup, but first here was the size of the table BC_SLD_CHANGELOG:

db2prd> db2 “SELECT TABNAME, NPAGES FROM SYSCAT.TABLES
ORDER BY NPAGES DESC”
TABNAME                       NPAGES
—————————- ——————–
BC_SLD_CHANGELOG              14162
BC_SLD_INST                   12830
J2EE_CONFIGENTRY              5870
BC_SLD_ASSINST                3905
EP_ATTR_VALUES3               3082
J2EE_CONFIG                   2163
DBH_STG_PKG_CACHE_METRICS     1421
SYSCOLDIST                    1193

Then delete the change log in https://<server>/sld
Select “Administration -> Maintenance -> Clean Up Change Log -> Remove Entries”.
I then scheduled a standard job to do this work from the “Cleanup Task Configuration” tab.
Finally, reorg the following tables to release the space:

db2 “REORG INDEXES ALL FOR TABLE SAPPODDB.BC_SLD_CHANGELOG”

db2 “runstats on table SAPPODDB.BC_SLD_CHANGELOG AND INDEXES ALL”

db2 “SELECT TABNAME, NPAGES FROM SYSCAT.TABLES WHERE TABNAME = ‘BC_SLD_CHANGELOG'”

TABNAME                       NPAGES
—————————- ——————–
BC_SLD_CHANGELOG              1205

That’s it.

BW Table Types & Descriptions

A useful list of table types in a SAP BW system, including the proposed table name definitions and the SAP table where the list of those types of tables are stored.
SID table /BI0/S<characteristic>: RSDMSIDTAB
Text table /BI0/T<characteristic>: RSDMTXTTAB
Master data table (time-independent) /BI0/P<characteristic>: RSDMCHNTAB
Master data table (time-dependent) /BI0/Q<characteristic>: RSDMCHTTAB
View master data tables /BI0/M<characteristic>: RSDMCHKTAB
Attribute SID table (time-independent) /BI0/X<characteristic>: RSDMASITAB
Attribute SID table (time-dependent) /BI0/Y<characteristic>: RSDMASTTAB
SID view: /BI0/R<characteristic>: RSDMSIDVIEW
Hierarchy table /BI0/H<characteristic>: RSDMHIETAB
Hierarchy SID table /BI0/K<characteristic>: RSDMHSITAB
Hierarchy structure SID table: /BI0/I<characteristic>: RSDMINCTAB
Hierarchy interval table: /BI0/J<characteristic>: RSDMHINTAB
Hierarchy SID view /BI0/Z<characteristic>: RSDMHSIVIEW

HANA OOM Error Tip #1 – Partition Tables Correctly

If your HANA system is regularly experiencing OOM (Out Of Memory) errors, then there are a number of things that you can do to try and reduce memory consumption.

Tip #1:  Partition Large Tables Correctly
If there are large Column Store tables in your HANA system, you should partition them.
Whilst this is an absolute must in a HANA scale-out scenario (for enabling multi-node parallelism), it might not be so obvious that it can also help in a single node HANA system.
Partitioning a column table means that only the required partitions of the table are loaded into memory when accessed, you would think.

Partitioning a large table into smaller chunks will therefore help to reduce the memory usage of the table during SQL queries and also during updates.
During updates, each partition gets its own delta cache area.

Choosing how to partition a table is slightly more difficult and will depend on whether the table is a custom table, SAP standard table or other.
Plus, you will need to know what and how queries or updates are executed against the table.  A period of monitoring is suggested, to enable to you collect the required information to be able to make a decision.

One thing you should try to do, is partition the table using the most logical, selective columns.
Read on for a simple example with a twist!

A simple example, a single node HANA system has 1 large column table T1.
The table is partitioned into ranges based on the date column INVOICEDATE:

CREATE COLUMN TABLE “DARRYL”.”T1″ (“INVOICEREF” VARCHAR(1) NOT NULL ,
     “INVOICEDATE” DAYDATE CS_DAYDATE NOT NULL ) UNLOAD PRIORITY 5 AUTO MERGE WITH PARAMETERS (‘PARTITION_SPEC’ = ‘RANGE year(INVOICEDATE) 2000-2001,2001-2002,2002-2003,*’)
;
CREATE UNIQUE INDEX “I1” ON “DARRYL”.”T1″ ( “INVOICEREF” ASC ) NONLEAF PARTIAL KEY LENGTH 1;

As you can see, I’ve created 3 partitions by year:  2000 to 2001,  2001 to 2002 and 2002 to 2003.
This will actually create 4 partitions:  year 2000,  year 2001, year 2002 and year <OTHER>.

HANA Table Distribution

Insert 5 records into the table:

insert into darryl.t1 (INVOICEREF,INVOICEDATE) values(‘1′,’2000-01-01’)
insert into darryl.t1 (INVOICEREF,INVOICEDATE) values(‘2′,’2001-01-01’)
insert into darryl.t1 (INVOICEREF,INVOICEDATE) values(‘3′,’2002-01-01’)
insert into darryl.t1 (INVOICEREF,INVOICEDATE) values(‘4′,’2003-01-01’)
insert into darryl.t1 (INVOICEREF,INVOICEDATE) values(‘5′,’2004-01-01’)

Inside the Table Distribution tab, you will now see that the records have been inserted according to their values into the respective partitions (see Raw Record Count field on the right):

HANA Table Distribution

The last two records for year 2004 and 2003 are in the fourth partition.
You can also see that each partition has a Delta Size, and that the Delta Size for the fourth partition with the most records, is larger than the other partitions.
Unload the table from memory:

HANA Unload Table from memory

Refreshing the Table Distribution tab now shows the table partitions to have zero size in memory:

HANA Table Distribution

Now select the records for the years 2004 and 2005 only:

select * from darryl.t1 where invoicedate in (‘2004-01-01′,’2003-01-01’)

Refreshing the Table Distribution tab now shows the tables to have non-zero size in memory for ALL partitions!

HANA Table Distribution

All of the records from all of the partitions appear to be loaded!
What went wrong?
Well, it’s simple, we didn’t create an index on the column INVOICEDATE.
This forced HANA to scan through the entire table to access the required records, meaning that it needed to load them all into memory.

Let’s create an index in INVOICEDATE:

CREATE UNIQUE INDEX “I1” ON “DARRYL”.”T1″ ( “INVOICEDATE” ASC ) NONLEAF PARTIAL KEY LENGTH 1;

Unload the table from memory:

HANA Unload Table from memory

Refreshing the Table Distribution tab now shows the tables to have zero size in memory:

HANA Table Distribution

Now re-execute the SELECT statement:

select * from darryl.t1 where invoicedate in (‘2004-01-01′,’2003-01-01’)

Once again, on the Table Distribution tab, we can see that it has accessed all partitions, AGAIN!:

HANA Table Distribution

What went wrong this time?  Well, HANA doesn’t yet have any statistics on the table data, so it simply ignored the index.
If you now unload the table from memory once again (we haven’t done anything else):

HANA Unload Table from memory

Now re-execute the SELECT statement:

select * from darryl.t1 where invoicedate in (‘2004-01-01′,’2003-01-01’)

Look at the Table Distribution tab:

HANA Table Distribution

You can see that HANA has now only accessed the final partition of the table.  The other partitions have not been loaded into memory.
At first I thought this feature might be due to statistics, so I tried removing them from the table T1 (drop statistics on T1;).  Then I retried the process of unloading and re-running the query.  This had no effect, HANA correctly went straight to the fourth partition.
This left me with one other option, the Plan Cache.

Clearing the Plan Cache using:

ALTER SYSTEM CLEAR SQL PLAN CACHE

I then re-ran the test by unloading the table from memory:

HANA Unload Table from memory

Re-executing the SQL SELECT:

select * from darryl.t1 where invoicedate in (‘2004-01-01′,’2003-01-01’)

Look at the Table Distribution tab:

HANA Table Distribution

Bingo!
The Plan Cache was storing some form of execution plan statistics that meant that it was accessing the fourth partition straight away.
Each time the table is unloaded, the statistics from the existing Plan Cache remain and are re-used upon next execution of the query, which means HANA is able to go straight to the fourth partition.

Summary:
Partitioning is a great way of parallelising access to a table in HANA.
It also serves to help reduce memory by only loading specific partitions into memory when they are required.
In order to effectively use partitioning, you need to partition on an indexed column.
The initial access of a newly partition table with a new index, does not enable the benefits of partition until the second subsequent access of the table due to the Plan Cache.  A method/process of pre-loading the execution plan/statistics into the cache is required.

SAP Unicode Conversion Sample DB Table Size

As an example, a non-Unicode SAP table (DBTABLOG) in an Oracle 11gR2 database (character set ALE32UTF16) without any Oracle compression, was ~80GB in total size (sum of table segments, excluding indexes).

Once this was exported to disk using R3load export, in preparation for a conversion to Unicode, it occupied ~70GB in the data files (DBTABLOG.00*).

Once this was re-imported into a new Oracle 11gR2 database with character set UTF8 (again, no compression) it occupied ~90GB (sum of segments, excluding indexes).

You must remember that this table is specific in it’s usage.  It doesn’t have any rows deleted from it, it’s append only, so it should grow in a nice uniform manner and not be fragmented.  There may be other tables where you could save space.
If you notice that your R3load export files are significantly different in size compared to the Oracle size, then you could have some serious fragmentation inside your Oracle database.