TempDB-Performance-Tuning out of the box – T-SQL Tuesday #87

TempDB-Performance-Tuning out of the box - T-SQL Tuesday #87

T-SQL Tuesday ist eine wiederkehrende Blog-Serie, die von Adam Machanic (b | t) gestartet wurde, jeden Monat ist ein Blogger Gastgeber für ein Thema rund um den SQL Server und jeder kann einen Blogbeitrag zu diesem bestimmten Thema schreiben.

Diesen Monat ist Matt Gordon (b | t) unser Host und das Thema geht um neue Features im SQL Server (ab der Version 2014) welche alte Problemstellungen beheben, bekannt gegeben in seinem Announcement-Post.

Mein Thema für diesen TSQL2sDay ist die neue Möglickeit zur Konfiguration der TempDB im Rahmen der SQL Server Installation.

Umsetzung der Best-Practise für die TempDB vereinfacht

Bisher musste man nach erfolgter Installation des SQL Server die Best-Practise Empfehlungen von Microsoft mehr oder weniger aufwändig konfigurieren. Entweder man ist auf herkömmliche Art und Weise an das Thema heran gegangen und hat die Werte manuell über das SQL Servermanagement Studio eingestellt oder man hatte es sich einfacher gemacht, dieses entweder per T-SQL oder Powershell Skript automatisiert. Aber dennoch musste man jedesmal diese Konfigurationsanpassungen nachträglich hinzufügen, um eine optimierte Performance der TempDB zu erreichen.

Die grundsätzliche Performance erhält die TempDB im Grunde zwar über die Hardware-Ausstattung, hier die physikalische Trennung zwischen User-Datenbanken und TempDB und die Verlagerung der TempDB auf hochperformanten Storage. Microsoft empfiehlt die strikte Trennung von UserDB und TempDB nicht nur durch getrennte Ordner-Strukturen oder getrennte Partitionen, es sollen eigene (schnelle) Platten sein. Hier muss auch keine großartige RAID-Konfiguration vorliegen, ein RAID 1 oder RAID 10 wären toll, aber keine wirkliche Notwendigkeit, denn die TempDB wird beim Neustarten des SQL Servers immer wieder “neu” erstellt, somit wäre es kein “Drama” wenn sie korrput wäre oder die drunterliegenden Platten crashen würden. (Ok, mal von dem Verlust von Daten und Zeit abgesehen).

Überblick über die Best-Practise Änderungen

Soviele Anpassungen sind gar nicht notwendig um eine bessere Performance der TempDB zu erreichen, diese möchte ich hier kurz zusammenfassen:

  • physikalische Trennung von User-Datenbanken und TempDB
  • Aufsplittung der TempDB in einzelne Datenfiles gem. Prozessor-Anzahl
  • Autogrowth-Parameter Anpassungen
  • Trace-Flag je nach Verwendung/Bedarf

Wenn man nun diese physikalische Optimierung im Storage-Bereich realsiert hat, kann man sich an die logischen Anpassungen in der Konfiguration machen. Je nach Prozessor-/Kernzahl empfiehlt Microsoft anstatt eines großen Datenfiles die Aufsplittung in mehrere getrennte Datenfiles, um eine Optimierung der IO-Streams umzusetzen (Parallelisierung). Ebenso kann man – je nach Anwendungsgebiet bzw Bedarfs – nun die Datenfiles initial auf eine feste Größe festlegen, damit der interne Aufbau der Datendateien optimiert wird und alle Dateien gleich groß sind. (ähnl. Traceflag 1117/1118). Anderweitig sollte man den Autogrowth-Parameter auf 10% setzen, so dass die Datendateien in Verbindung mit den Traceflag 1117 und 1118 zu einem optimierten, gleichmäßigen Aufbau der TempDB beitragen.

SQLServer2016 - Configure TempDB during Installation

SQL Server 2016 bringt integrierte Vereinfachungen

Der SQL Server 2016 bringt nun diese ganzen logischen Optimierung gleich im Rahmen der Installation mit… man kann also ohne Umschweife dem SQL Server mitteilen, wie man die Anzahl und Aufteilung der TempDB-Datenfiles sowie deren Autogrowth-Parameter setzen möchte. Microsoft hat endlich die lange publizierten Best-Practise Empfehlungen in den Installationsprozess integriert. Somit muss man eigentlich nur noch die Hardware-Vorraussetzungen für die TempDB schaffen und kann anfangen zu installieren.
Ok, auch hier muss man sich natürlich Gedanken machen, welche Werte man wie setzt, aber zumindest muss man sich über diese Konfigurationen hinterher keine Gedanken machen!

VIELEN DANK an Microsoft für diese Verbesserung.

Man kann man während des Installationsprozesses einstellen, wieviele Datenfiles man anlegen möchte, dazu die initiale Größe und auch den Autogrowth-Parameter festlegen. Theoretisch könnte man sogar für jedes einzelne Datenfile (Aufteilung anhand der Anzahl der Kerne) einen eigenen Datenpfad oder sogar eine eigene (SSD-)Platte spendieren. Alles in einem übersichtlichen Screen dargestellt und auf für den unerfahrenen DBA einsetzbar.

Durch dieses neue “Toy” konnten einige “Problems” reduziert werden… 😉

Azure Meetup – Erfahrungsbericht und Einblicke bei Microsoft

In der letzten Woche hatte ich die Ehre/das Vergnügen mein erstes Azure Meetup in Hamburg bei Microsoft zu veranstalten. Wie bereits in einem meiner letzten Beiträge verkündet, gibt es nun auch in Hamburg ein Azure Meetup. Innerhalb von rund vier Wochen hatten sich etwa 90 Mitglieder angesammelt und ihr Interesse an dem Thema Azure bekundet und mehr als 60 (am Nachmittag der Veranstaltung) wollten erscheinen. Am Montag Nachmittag musste ich sogar die Teilnehmerzahl auf 65 begrenzen, sonst hätte man mir den Raum “gesprengt”. Laut der Webseite waren es dann 57 Teilnehmer, vor Ort konnte ich etwa 50 Interessierte begrüßen.

Begrüssung Azure Meetup Hamburg - November 2016

Aufgrund von Terminschwierigkeiten mussten wir kurzfristig die Reihenfolge tauschen, da Sia am nächsten Morgen einen Kundentermin hatte und uns frühzeitig verlassen musste. Aber wir sind da ja flexibel und ich freute mich überhaupt, dass er trotz der widrigen Umstände und Zeitknappheit erschienen ist und seinen Erfahrungsbericht zum Umzug einer On-Premise Application nach Azure gehalten hat. VIELEN DANK dafür nochmal an Sia für diesen Einsatz!

Erfahrungsbericht von Sia Ghassemi

Sia erzählte uns viele interessante Punkte, welche vor Beginn der eigentlichen Migration nach Azure zu beachten waren, welche Hürden in seinem Projekt überwunden werden mussten und wie sie nach einem recht beschwerlichen Weg doch noch (mehr oder weniger) ans Ziel gekommen sind. Dass einige Teile der Applikation umgeschrieben werden mussten, andere komplett umgeschrieben wurden, damit sie in Azure performanter und stabiler laufen als zuvor. Sein Vortrag war eine perfekte Mischung aus Einblicken, Ideen, Beispielen und wahren “Begebenheiten”, seinem Vortrag zu lauschen war alles andere als langweilig. Dass letztendlich die Applikation nicht mehr in Azure läuft, lag nicht an Azure oder an Sia, sondern an anderen Randbedingungen welche leider nicht so ohne weiteres beseitigt werden konnten.

Sia Ghassemi mit einem Erfahrungsbericht zur Migration nach Azure

Sozusagen als Begrüßungsgeschenk haben wir von Microsoft Pizza und Bier erhalten, welche reichlich und gerne verspeist wurde. Ich denke alle Teilnehmer konnten auch unserem zweiten Teil des Azure Meetups gestärkt und gesättigt zuhören. Im zweiten Teil hielten Sebastian Klenk und Malte Lantin (beide Microsoft Technical Evangelisten) einen zwei geteilten Vortrag zu den neuen Azure Functions und zur Microsoft internen Nutzung von Azure.

Einblick und Überblick über die Microsoft interne Nutzung von Azure

Sebastian erläuterte anhand zahlreicher Folien, Zahlen und Beispielen sehr gut die vielfältige Nutzung der Azure Cloud bei Microsoft selber. Seinen Vortrag leitete er ein, in dem er erst einmal einen groben Überblick über die Möglichkeiten von Azure zeigte.

Azure Meetup Hamburg - MSFT Intro - Azure Services

Hier kommen ein paar Zahlen aus dem Vortrag 😉

Bei Microsoft nutzen weltweit etwa 120.000 Mitarbeiter die internen und externen Services von Azure => 29.000 Devices werden in Intunes gemonitored, ~400 Apps werden im Unternehmensportal angeboten, 150.000 Devices im Exchange Active Sync. Im Monitoring laufen täglich etwa 7 Milliarden Security Event-Meldungen auf und Microsoft verwaltet im Azure System Center etwa 330.000 Geräte, ob dies ein Microsoft Surface ist, ein Microsoft Lumia Handy oder ein “normaler” Arbeitsplatz oder sogar ein Fremdgerät (BYOD) spielt keine Rolle.

Microsoft intern nutzt in Azure ~19.000 virtuelle Maschinen zum Beispiel für Entwicklung und Tests, aber auch für Monitoring-Zwecke, desweiteren rund 5.000 SQL Instanzen als Datenquellen oder Datensenken.

die neuen Azure Functions

Malte gewährte noch einen Überblick in die brandneuen Azure Functions und zeigte uns eine kurze aber eindrucksvolle Demo, wie einfach und schnell man diese Functions erstellen und aktivieren kann. In seinen Erläuterungen ging auch darauf ein, dass die Zukunft eben Serverless sein wird, zumindest aus Sicht von Microsoft und der OnPrem-WebService aussterben wird. Denn mittels der Azure Functions lassen sich Funktionsaufrufe sehr schnell und unkompliziert deployen und das vor allem kostengünstig.

Bei den Azure Functions werden Ereignis-getriggerte Computefunktionen skalierend ausgeführt und man zahlt nur die tatsächliche Nutzung der Functions => also nur pro Aufruf/Ereignis-Trigger. So lassen sich in Zukunft eine Vielzahl von Funktionen kurzfristig und kostengünstig umsetzen, da man sich nicht erst mit einer geeigneten Infrastruktur beschäftigen muss.

Unser nächstes Azure Meetup : 13. Dezember ebenfalls bei Microsoft Hamburg

Alle IT Begeisterten und Azure-Freunde sind recht herzlich eingeladen, Simon Schwingel wird eine sehr interessanten Vortrag präsentieren, wie man die Migration einer SQL Server Landschaft nach Azure plant und durchführt bzw durchführen könnte.

ServicePack 1 für SQL Server 2016 released – Enterprise meets Standard

Gestern Vormittag (Ortszeit New York) bzw Nachmittag bei uns wurden viele neue Themen im Rahmen der Keynote vom Microsoft Event “Connect(); // 2016” vorgestellt, der wichtigste Punkt aus meiner Sicht sind die Neuerungen aus dem Servicepack 1 für den SQL Server 2016. Bisher waren einige Features nur in der Enterprise Edition des SQL Servers verfügbar, jetzt eröffnet Microsoft seinen Kunden die Möglichkeiten eben diese Features auch in der Standard Edition zu nutzen.

Features in SQL Server 2016 RTM

Das ServicePack 1 des SQL Server 2016 beinhaltet alle Fixes bis zum Cumulative Update 3 und dem Security Update MS16–136.

Folgende Features wurden (zusätzlich) im ServicePack 1 als Verbesserungen eingeführt:

  • Row-level Security
  • Dynamic Data Masking
  • Change Data Capture
  • Database Snapshot
  • Columnstore
  • Partitioning
  • Compression
  • InMemory OLTP
  • Always Encrypted
  • PolyBase
  • Fine grained auditing
  • Multiple filestream containers
  • Database Cloning
  • CREATE OR ALTER
  • USE HINT – als zusätzliche Abfrage Option
  • TempDB – Verbesserung in der Erkennbarkeit im Errorlog
  • und zahlreiche Verbesserungen in DMVs und XEs

All the newly introduced Trace flags with SQL Server 2016 SP1 are documented and can be found at http://aka.ms/traceflags.

Features in SQL Server 2016 ServicePack 1

Einige Einschränkungen gibt es noch in den einzelnen Features in den kleineren Editionen, wie zum Beispiel die Speichergrenzen für InMemory OLTP – Details zu den teilweise recht geringen Größen finden Sie hier.

Fazit:
Nun lohnt sich der Wechsel auf den SQL Server 2016 erst recht, wenn auch erst ab dem ServicePack 1… UND man braucht nicht mehr unbedingt eine Enterprise-Edition um zum Beispiel Compression und Partitioning einsetzen zu können.

VIELEN DANK an Microsoft für diesen großartigen Schritt!

#3.1 Update zu meinem Powershell Skript “Öffnen von Firewall Port”

Nachdem ich meinen Beitrag zum Thema “Öffnen der Firewall Ports mit Powershell” Ende Oktober veröffentlicht hatte, habe ich mein Skript nochmals überarbeitet. Der SQL Server und seine Features wie z.B. die Analysis Services haben eigene Ports, welche auch nur geöffnet werden müssen, wenn die jeweiligen Features installiert sind.

Grundlage für meine weiteren Versuche ist der MSDN-Beitrag zu diesem Thema und der eigene Wunsch nach mehr Flexibilität beim Erstellen von Regeln.

Flexibilität durch eigene Powershell-Funktion “GET SQLServices for Firewall”

Ich habe also meine bisherige Funktion aufgesplittet, so dass ich nicht mehr wie bisher stur (per Copy&Paste) die Regel erstelle. Jetzt habe ich eine Funktion gebaut, welche alle relevanten SQL Server Dienste ermittelt, um diese dann individuell freizuschalten. Also mein erster Schritt ist die Analyse der SQL Server Installation:

function GET_SQLServices_for_Firewall($SQLServerTCPPort) {
    # TCP = 6, UDP = 17

    Write-Host "Opening Firewall ports for this Instance"
    # General Ports
    OpenFirewallPorts 4022 6 "SQL Service Broker"
    OpenFirewallPorts 1434 17 "SQL Browser"

    $Services=get-wmiobject -class win32_service | where {$_.DisplayName -like '*SQL*'} | select-object DisplayName 
    foreach ( $service in $Services ) {
        
        # DB-Engine Ports
        if ($Service.DisplayName -like '*SQL Server (*') { 
            OpenFirewallPorts $SQLServerTCPPort 6 "SQL Server"
        }

        # SSAS Ports
        if ($Service.DisplayName -like '*Analysis Services (*') {
            OpenFirewallPorts 2383 6 "SQL - Analysis Services"
            OpenFirewallPorts 2382 6 "SQL - Analysis Services Browserservice"
        }
    }
}

Wie man nun erkennen kann, rufe ich nun eine weitere Funktion auf mit der ich die Verwaltung der Windows Firewall übernehme. Die eigentlichen Teile meines bisherigen Skriptes habe ich somit relativ unverändert gelassen, nur “eingedampft” und variabler gestaltet.
Ich rufe also die eigentliche Arbeitsfunktion mit entsprechenden Parametern auf, um den jeweiligen Port, das Protokoll und eine sprechende Beschreibung zu übermitteln.

function OpenFirewallPorts ([int]$Port, [int]$Protocol, [string]$FirewallRuleDescsription) {
    
    if ($Protocol -eq 6) {$Protocol_String = "TCP"}
    if ($Protocol -eq 17) {$Protocol_String = "UDP"}

    Try {
	Write-Host "Opening Firewall on $Protocol_String Port $Port" 
	$port1 = New-Object -ComObject HNetCfg.FWOpenPort
	$port1.Port = $SQLServerTCPPort
	$port1.Name = $FirewallRuleDescsription + "(" + $Protocol_String + " " + $Port + ") " + $InstanceName 
	$port1.Enabled = $true
	$port1.Protocol = $Protocol
	$fwMgr = New-Object -ComObject HNetCfg.FwMgr
	$profiledomain=$fwMgr.LocalPolicy.GetProfileByType(0)
	$profiledomain.GloballyOpenPorts.Add($port1)
        Write-Host "[INFO] Successfully opened Firewall on $Protocol_String Port $Port." -ForegroundColor Green
	} 
    Catch { 
        Write-Host "[ERROR] Opening Firewall on $Protocol_String Port $Port failed." -ForegroundColor Red 
    }
}

Für mich und meine Zwecke funktioniert das soweit ganz gut und ist natürlich bei Bedarf individuell anpassbar. Wenn man als Beispiel einen weiteren Listener im SQL Server konfiguriert, dann könnte man dies ebenfalls ermitteln und in der Windows Firewall freischalten. Grob => Invoke-SQLcmd “Get Listener Port” => OpenFirewallPorts newListenerPortNumber 6 “Additional SQL Server Listener”

Für mich bedeutet das Niederschreiben und Erläutern der einzelnen Schritte und Veränderungen auch einen Lernprozess. Wenn jemand Anmerkungen oder Verbesserungen für mich hat, freue ich mich sehr darüber. “Please share your knowledge” 😉

#3 Firewall Ports für den SQL Server öffnen mit Powershell

Nach ein paar Tagen Ruhe kommt nun mein dritter Teil der Powershell Serie zum Thema “Firewall Ports öffnen“.
Sicherlich wird der ein oder andere sagen, “Firewall? die interne? die haben wir per Gruppenrichtlinie immer ausgeschaltet!”…was ist vielleicht in einem halben Jahr, jemand aktiviert die Windows Firewall auf dem Server manuell? Kann der SQL Server (also die Datenbank-Enigne) dann immer noch mit der Welt da draußen kommunizieren?

Sicherheit geht vor – daher nur definiert und bewußt die Firewall Ports öffnen

Windows Firewall Ports öffnen für den SQL Server

Ich empfehle nur die notwendigen Ports für die Datenbank-Enigne zu öffnen, im Beispielbild wären das die folgenden Ports

  • SQL Server DB Engine => TCP 10001
  • der SQL Browser => UDP 1434
  • der SQL Service => Broker 4022

Dies reicht völlig aus, um dem SQL Server und den nutzenden Applikationen im Notfall eine Kommunikation zu ermöglichen. Nun gibt es mehrere Möglichkeiten dies zu realisieren, die Konfiguration der Firewall über die grafische Oberfläche, was doch umständlich und “kompliziert” sein kann, aber ebenso der Weg über die Kommandozeile entweder als DOS-Befehl bzw mit dem netsh-Befehl oder mit einem Powershell-Skript.

Wer noch andere Features des SQL Servers auf dem selben Server einsetzt, muss natürlich noch weitere Ports öffnen und auch die entsprechenden Skripte erweitern, aber in der Regel reichen diese Firewall Ports für einen Datenbank Server aus.

weitere Hinweise zu den Firewall Ports des SQL Server findet man hier : https://msdn.microsoft.com/de-de/library/cc646023.aspx

Umsetzung über die Kommandozeile

netsh advfirewall firewall add rule name="SQL Server (TCP 10001) TEST_Instanz" dir=in action=allow protocol=TCP localport=10001 profile=domain
netsh advfirewall firewall add rule name="SQL Service Broker (TCP 4022)" dir=in action=allow protocol=TCP localport=4022 profile=domain
netsh advfirewall firewall add rule name="SQL Browser (UDP 1434)" dir=in action=allow protocol=UDP localport=1434 profile=domain

Der netsh-Befehl lässt sich sehr gut parametrisieren und skripten, ist daher sehr individuell einsetzbar, also recht umgänglich. Hier kommt es auf die Unternehmensstrategie oder die der Systemadministratoren an, welche Skriptsprache bevorzugt wird. Ich bevorzuge (mittlerweile) Powershell, was auch Hauptthema dieser Serie ist, daher gehe ich nun etwas tiefer in die Umsetzung “Firewall Ports öffnen” mit Powershell ein.

Umsetzung mittels Powershell

Auch die Windows-Firewall hat ein Powershell Commandlet, so dass wir die Firewall Ports recht einfach und komfortabel öffnen können. Mein Lösungsansatz ist vielleicht etwas länger und umfangreicher, der erfahrene Powershell Programmierer bekommt das bestimmt auch in eine Schleife gepackt oder gar in eine Zeile 😉
Meine Zeilen stammen aus einem Skript, welches ich für die Konfiguration nach der Installation verwende, daher sind hier zahlreiche Variablen genutzt worden, um die Flexibilität zu erhalten.

  • $SQLServerTCPPort = 10001
  • $InstanceName = TEST_Instanz

Auch ein wenig “Monitoring” habe ich implementiert, so dass man gleich das Ergebnis, den Fehlschlag bzw den Fortschritt anhand der Ausgabe erkennen kann. Für meine Zwecke im Rahmen der SQL Server Installation reichen diese Zeilen um die Firewall Ports zu öffnen, zudem erklären sich die einzelnen Parameter nahezu von selbst.

Write-Host "Opening Firewall ports for this Instance"
    Try {
		Write-Host "Opening Firewall on Port $SQLServerTCPPort" 
		$port1 = New-Object -ComObject HNetCfg.FWOpenPort
		$port1.Port = $SQLServerTCPPort
		$port1.Name = "SQL Server (TCP " + $SQLServerTCPPort + ") " + $InstanceName 
		$port1.Enabled = $true
		$port1.Protocol = 6
		$fwMgr = New-Object -ComObject HNetCfg.FwMgr
		$profiledomain=$fwMgr.LocalPolicy.GetProfileByType(0)
		$profiledomain.GloballyOpenPorts.Add($port1)
        Write-Host "[INFO] Successfully opened Firewall on Port $SQLServerTCPPort." -ForegroundColor Green
     } 
    Catch { 
        Write-Host "[ERROR] Opening Firewall on Port $SQLServerTCPPort failed." -ForegroundColor Red 
    }
   
   Try {
		Write-Host "Opening Firewall on Port 4022" 
		$port1 = New-Object -ComObject HNetCfg.FWOpenPort
		$port1.Port = 4022
		$port1.Name = "SQL Service Broker (TCP 4022)"
		$port1.Enabled = $true
		$port1.Protocol = 6
		$fwMgr = New-Object -ComObject HNetCfg.FwMgr
		$profiledomain=$fwMgr.LocalPolicy.GetProfileByType(0)
		$profiledomain.GloballyOpenPorts.Add($port1) 
        Write-Host "[INFO] Successfully opened Firewall on Port 4022." -ForegroundColor Green
    } 
    Catch { 
        Write-Host "[ERROR] Opening Firewall on Port 4022 failed." -ForegroundColor Red 
    }
   
    Try {
		Write-Host "Opening Firewall on Port UDP 1434" 
		$port1 = New-Object -ComObject HNetCfg.FWOpenPort
		$port1.Port = 1434
		$port1.Name = "SQL Browser (UDP 1434)"
		$port1.Enabled = $true
		$port1.Protocol = 17
		$fwMgr = New-Object -ComObject HNetCfg.FwMgr
		$profiledomain=$fwMgr.LocalPolicy.GetProfileByType(0)
		$profiledomain.GloballyOpenPorts.Add($port1) 
        Write-Host "[INFO] Successfully opened Firewall on Port UDP 1434." -ForegroundColor Green
    } 
    Catch { 
        Write-Host "[ERROR] Opening Firewall on Port 1434 failed." -ForegroundColor Red 
    }