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

SQL Server Shrink Transaction Log Script

Below is a script that shrinks SQL Server transaction logs tested on SQL Server 2008R2.
Before running the script, you should ensure that you take a transaction log backup of your databases (which obviously means you should have already taken a full backup).  The transaction log backup will free the virtual logs from within the transaction log file.

The script simply tries to shrink the transaction log file by 25% for any databases that are not called “MASTER”, “MODEL”, “MSDB” or “TEMPDB”.

If you wish to shrink logs by more than 25%, either change the script, or run it multiple times until it can’t shrink the logs any further.

NOTE: When executing the script in SQL Management Studio, you should set the results output to “Text”, so that you can see the output of the script.


USE master
GO

DECLARE @database_id    int,
        @database_name  nvarchar(128),
        @file_id        int,
        @file_name      nvarchar(128),
        @size_mb        int,
        @new_size       int;

DECLARE @dbcc_output    char(5);
DECLARE Cur_LogFiles CURSOR LOCAL FOR
  SELECT database_id,
         UPPER(DB_NAME(database_id)) database_name,
         file_id,
         name file_name,
         (size*8)/1024 size_mb
   FROM  master.sys.master_files
   WHERE type_desc = 'LOG'
     AND state_desc = 'ONLINE'
     AND UPPER(DB_NAME(database_id)) NOT IN ('MASTER','TEMPDB','MSDB','MODEL')
   ORDER BY size_mb DESC;

BEGIN
    OPEN Cur_LogFiles
    FETCH NEXT FROM Cur_LogFiles
       INTO @database_id, @database_name, @file_id, @file_name, @size_mb
    WHILE @@FETCH_STATUS = 0
    BEGIN
      -- Determine 25% of our current logfile size.
      SET @new_size = @size_mb*0.75;
      -- Set context to the database that owns the file and shrink the file with DBCC.
      PRINT 'Database: ' + @database_name + ', file: ' + @file_name + ', size: ' + CONVERT(varchar,@size_mb,25) + 'mb';
      PRINT 'Attempting to shrink file: ' + @file_name + ' by 25% to: '+ CONVERT(varchar,@new_size,25) + 'mb';

      EXEC ('USE [' + @database_name + ']; DBCC SHRINKFILE (['+@file_name+'],'+@new_size+');');

      FETCH NEXT FROM Cur_LogFiles
         INTO @database_id, @database_name, @file_id, @file_name, @size_mb
    END;

    CLOSE Cur_LogFiles
    DEALLOCATE Cur_LogFiles

END;

HowTo: Dynamic SQL Server Memory Change from SAP ST04

Scenario: You have a SQL Server database for your SAP system, and you know that right clicking the database server name in SQL Server Management Studio, selecting “Properties” and then “Memory”, will show you the SQL Server memory settings, but you want to know how you can see/change the same detail in SAP…

SQL Server Management Studio - Dynamic Memory

SQL Server Management Studio - Minimum memory

In SAP, you can use transaction ST04 to see the SQL Server database settings.
The memory details are visible in the “Overview” screen.
You will see the “Current Memory MB” equals the amount of memory allocated to SQL Server, and if the “Min server memory” and “Max server memory” settings have been set equal (recommended by SAP), then the overview screen will show “FIXED” for the “SQL Memory Setting”:

SAP SQL Server memory settings

It is possible to modify this setting directly from ST04.
You will need to expand the “Diagnostics” branch and then double click “SQL Command Editor”:

image

On the right hand side, enter the SQL Server commands to resize the memory (notice that these are slightly different to the SQL statements when using them in SSMS):

SAP ST04 SQL code execute

exec sp_configure 'show advanced options', 1
RECONFIGURE
exec sp_configure 'max server memory', 4096
RECONFIGURE


Click Execute:

image

The output window will be displayed:

SAP ST04 SQL code execute

If you noticed, I didn’t change the “Min” memory setting, only the “Max”.
When I check in the “Performance -> Overview” screen in ST04, I can now see that the “Current Memory MB” setting has not changed, but the “SQL Memory Setting” is now showing “RANGE”:

SAP ST04 SQL Server memory settings

Now if I use the SQL Command Editor to also change the “Min” memory, we will see the ST04 overview screen update:

SAP ST04 SQL execute

exec sp_configure ‘show advanced options’, 1
RECONFIGURE
exec sp_configure ‘max server memory’, 4096
exec sp_configure ‘min server memory’, 4096
RECONFIGURE


image

And the overview screen:

image

Well, we’re at “FIXED” again, but the amount of memory has not changed.
Yet in SSMS, I can see the allocation has changed:

SQL Server Management Studio memory settings

This is a weird, because the Microsoft documentation for SQL Server 2008R2 (my version) says that the setting should take effect straight away.
I guess there’s something within the ST04 screen that doesn’t update.
There is another way…
You can use the “Configuration -> Overview” screen and the “Configuration Options” tab to see both the Min and Max memory settings.
As per out change, these correctly reflect the current memory settings:

SAP ST04 SQL Server memory settings

WARNING: You should be aware that during testing, I was able to set the Min memory value higher than the Max memory value in ST04.
I was then unable to change this through ST04, as the store procedures just produced errors and refused to let me change the values.
In the end I had to change the Max value using SSMS.

SAP Unicode Conversion MAXDOP Parallelism on MS SQL Server

When performing a Unicode conversion of an SAP system running on MS SQL Server database, you get pointed to the Unicode Collection Note 1319517.
This note points to a MS SQL Server specific note (Note 1054852 – Recommendations for migrations to MS SQL Server)  which covers a couple of different scenarios, such as moving to SQL Server from another database provider, or just performing an R3load export/import (like me) to the same platform.

Now from experience, I know that the R3load import is actually pretty quick (especially on Oracle with DIRECTPATH).  What takes the time is the index creation afterwards.  Lots of scanning and I/O needs to be done.  This is where you waste time, and where you could save time.
The note 1054852 mentions the use of the MAXDOP (Maximum Degree of Parallelism) SQL Server parameter that could benefit any subsequent index creation/rebuild tasks performed during an R3load import.
The recommendation in note 1054852 is to change the MAXDOP from the SAP recommended setting of 1, to 4 for the entire SQL Server instance.  NOTE: The maximum MAXDOP in 2008R2 is 1024 (see here and SAP note 1654613).
This is the “hammer” approach and should be used with caution.  There is a nice blog here on the use of MAXDOP with SQL Server.  The blog shows how setting this to a value greater than 1 can actually increase fragmentation.  This is completely understandable.  However, the reader must note that the fragmentation is only an issue if the index is specifically set with ALLOW_PAGE_LOCKS to “OFF” (the default in 2008R2/2012 is “ON” (see syntax here)! ).
There is another blog article that shows how this fragmentation problem is overcome by setting the ALLOW_PAGE_LOCKS option.  The article states that by default this is “ON”.  However, according to Microsoft KB 2292737, the default is “OFF” by design. 
So which is it?  In fact, the MS syntax for “ALTER INDEX” specifically states that it is not possible to reorganise an index with ALLOW_PAGE_LOCKS set to “OFF”.

Here’s how to check the value of the ALLOW_PAGE_LOCKS setting for an index (there is no global setting):


use <SAP DB>
go

select name,type,allow_page_locks from sys.indexes
where allow_page_locks != 1
order by 1;


And the results…  well, some of the largest SAP tables in my system have their indexes set with ALLOW_PAGE_LOCKS to “OFF“.  Great!

NAME
TYPE
ALLOW_PAGE_LOCKS
ARFCRDATA~0
1
0
ARFCSDATA~0
1
0
COVREF~0
1
0
COVREF~001
2
0
COVREF~002
2
0
D010INC~0
1
0
D010INC~1
2
0
D010TAB~0
1
0
D010TAB~1
2
0
EDI40~0
1
0
EDIDC~0
1
0
EDIDC~1
2
0
EDIDC~2
2
0
EDIDC~3
2
0
EDIDC~4
2
0
EDIDS~0
1
0
EDIDS~1
2
0
EDIDS~2
2
0
REPOLOAD~0
1
0
REPOSRC~0
1
0
REPOSRC~SPM
2
0
TRFCQIN~0
1
0
TRFCQIN~1
2
0
TRFCQIN~2
2
0
TRFCQIN~3
2
0
TRFCQIN~4
2
0
TRFCQIN~5
2
0
TRFCQIN~6
2
0
TRFCQOUT~0
1
0
TRFCQOUT~1
2
0
TRFCQOUT~2
2
0
TRFCQOUT~3
2
0
TRFCQOUT~4
2
0
TRFCQOUT~5
2
0
TRFCQOUT~6
2
0
VBDATA~0
1
0
VBHDR~0
1
0
VBMOD~0
1
0

I can understand the VB* tables might not want index locking and this is also hinted at in the older SAP R/3 Performance Tuning Guide for Microsoft SQL Server 7.0 web page.  However, where did the other tables come from?
I took a look on SAP Notes but I was unable to find anything definitive.  The system I was working on was recently copied and used SWDM (SAP Software Deployment Manager) to perform the post-copy steps, so it’s possible that the indexes were automatically adjusted (ALTER’d) to try and ensure a consistent approach.
What to do next?  Well, some of those tables can be ignored since they are supposed to have ALLOW_PAGE_LOCKS set to “OFF”, some, like REPOLOAD are re-populated only during a system-copy with R3 tools (e.g. Unicode conversion), so you could try adjusting the setting during the R3load import. 
The others, well in theory you would try to minimise data in those tables (like TRFC*) before you perform a Unicode conversion, so the indexes wouldn’t be massive anyway.

At the end of the day, all we are talking about here is a little fragmentation.  So let’s move on.

Let’s go back to the MAXDOP setting recommendation mentioned in SAP note 1054852. 
Now, my system happens to be a BW type system (it’s actually SEM, but this is just BW in disguise), so I found SAP Note 1654613 – SQL Server Parallelism for SAP BW which suggests that for SAP BW systems, you can now manage the MAXDOP parameter settings in table RSADMIN through report SAP_RSADMIN_MAINTAIN by setting parameters MSS_MAXDOP_QUERY, MSS_MAXDOP_<cubename> and MSS_MAXDOP_INDEXING.
The note 1654613 also goes on to say that by applying the note corrections (or the related support package stacks) the default MAXDOP for BW queries is set to 2, and for (process chain) index creations is set to 8.
Aha! 
So the Unicode collection note’s setting of 4, could actually contradict the setting of 8 in BW systems!
The note 1654613 also states that you may increase the MAXDOP for queries to more than 4, but this depends on the number of worker threads configured in your SQL Server instance.
The worker threads setting in my SQL Server 2008R2 instance was set to “0”, which means the number is dynamically calculated (see here).

You can use the sp_configure procedure to check your setting:

sp_configure @configname='max worker threads';

You can query the current number of threads (thanks to https://blogs.msdn.com/b/boduff/archive/2008/05/17/configuring-max-worker-threads-in-sql-2005.aspx):

select count(*) from sys.dm_os_threads;

My idle database was using 50 threads on a VMWare VM with 4 processors.  So I guess I could increase the MAXDOP for queries permanently in my BW (SEM) system.

You should also note the setting MSS_MAXDOP_INDEXING = 0 means that all available threads will be used during (process chain) index creation.

Summary:
We are advised to set MAXDOP to 4 when moving an SQL Server database or performing a system-copy or Unicode conversion. 
However, more detailed analysis has shown that for BW systems specifically, we can potentially adjust the MAXDOP setting even higher than 4 during our R3load import, to ensure that we make the best use of the available CPU. 
This is underlined by the fact that defaults within the BW system are sometimes higher than the recommended setting of 4.
Therefore, I will be trying out a value of 12 (default of 8 for index creation + 50%) in my Unicode conversion:

sp_configure 'max degree of parallelism', 12;
reconfigure with override

Oracle vs SQL Server – I like it!

I found this today https://www.oaktable.net/sites/default/files/deathmatch.pdf
It shows a good comparison of basic syntactical differences in SQL Server and Oracle when looking to compare performance / features.
I especially like the use of blockrecover in RMAN towards the end.  Nice.

Just take a look at the tags for it’s hosting blog page and it’s obvious which one will win without even reading the slide.