Public/Test-sqmTempDbFileCount.ps1
|
<# .SYNOPSIS Prueft ob die Anzahl der TempDB-Datendateien der empfohlenen CPU-Anzahl entspricht. .DESCRIPTION Liest die Anzahl der TempDB-Datendateien (Typ = Rows, ohne Log) per SMO und vergleicht sie mit der Anzahl der CPU-Kerne des Servers (max 8 gemaess Microsoft-Empfehlung). Hintergrund: Zu wenige TempDB-Dateien koennen zu PAGELATCH-Konflikten auf der Allocation-Seite fuehren. Microsoft empfiehlt eine Datei pro logischem Kern, maximal 8. Gibt ein PSCustomObject mit aktuellem Wert, empfohlenem Wert und Status zurueck. .PARAMETER SqlInstance SQL Server-Instanz. Standard: lokaler Computername. .PARAMETER SqlCredential PSCredential fuer die SQL-Verbindung. .PARAMETER MaxFiles Maximale empfohlene Dateianzahl. Standard: 8 (Microsoft-Empfehlung). .PARAMETER EnableException Ausnahmen sofort ausloesen statt Write-Error. .OUTPUTS [PSCustomObject] mit den Feldern: SqlInstance : Instanzname CurrentFileCount : Aktuell vorhandene TempDB-Datendateien RecommendedCount : Empfohlene Anzahl (CPU-Kerne, max MaxFiles) LogicalCores : Ermittelte logische CPU-Kerne Status : OK | Warning | Error Message : Detailmeldung .EXAMPLE Test-sqmTempDbFileCount -SqlInstance "SQL01" .EXAMPLE Test-sqmTempDbFileCount -SqlInstance "SQL01\INST1" -MaxFiles 4 .NOTES Empfehlung: 1 Datendatei pro logischem Kern, max 8. Alle Datendateien sollten gleich gross sein (Autogrowth identisch). Nur Datendateien (FileType = RowData) werden gezaehlt, keine Logdateien. #> function Test-sqmTempDbFileCount { [CmdletBinding()] [OutputType([PSCustomObject])] param ( [Parameter(Mandatory = $false, Position = 0)] [string]$SqlInstance, [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential]$SqlCredential, [Parameter(Mandatory = $false)] [ValidateRange(1, 64)] [int]$MaxFiles = 8, [Parameter(Mandatory = $false)] [switch]$EnableException ) begin { $functionName = $MyInvocation.MyCommand.Name if (-not $PSBoundParameters.ContainsKey('SqlInstance') -or [string]::IsNullOrWhiteSpace($SqlInstance)) { $SqlInstance = $env:COMPUTERNAME } # MaxFiles aus Modulkonfiguration lesen (ueberschreibt Parameter-Default wenn nicht explizit angegeben) if (-not $PSBoundParameters.ContainsKey('MaxFiles')) { $cfgVal = Get-sqmConfig -Key 'CheckTempDbMaxFiles' if ($null -ne $cfgVal) { $MaxFiles = [int]$cfgVal } } Invoke-sqmLogging -Message "Starte $functionName auf $SqlInstance (MaxFiles: $MaxFiles)" -FunctionName $functionName -Level 'INFO' } process { try { [void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.Smo') $server = New-Object Microsoft.SqlServer.Management.Smo.Server($SqlInstance) if ($SqlCredential) { $server.ConnectionContext.LoginSecure = $false $server.ConnectionContext.Login = $SqlCredential.UserName $server.ConnectionContext.SecurePassword = $SqlCredential.Password } # Logische CPU-Kerne ermitteln (max MaxFiles) $logicalCores = ($server.Processors | Measure-Object).Count if ($logicalCores -eq 0) { # Fallback: WMI lokal $logicalCores = (Get-CimInstance Win32_Processor | Measure-Object -Property NumberOfLogicalProcessors -Sum).Sum } $recommendedCount = [Math]::Min($logicalCores, $MaxFiles) # TempDB Datendateien zaehlen (nur RowData, kein Log) $tempDb = $server.Databases['tempdb'] $dataFiles = $tempDb.FileGroups | ForEach-Object { $_.Files } | Where-Object { $_.UsedSpace -ge 0 } # alle DataFiles $fileCount = ($dataFiles | Measure-Object).Count if ($fileCount -eq $recommendedCount) { $status = 'OK' $message = "TempDB Datendateien: $fileCount - entspricht empfohlenem Wert ($recommendedCount bei $logicalCores logischen Kernen)." Write-Host " OK $message" -ForegroundColor Green } else { $status = 'Warning' $message = "TempDB Datendateien: $fileCount - empfohlen sind $recommendedCount ($logicalCores logische Kerne, max $MaxFiles). Bitte anpassen." Write-Host " WARN $message" -ForegroundColor Yellow } Invoke-sqmLogging -Message $message -FunctionName $functionName -Level $(if ($status -eq 'OK') { 'INFO' } else { 'WARNING' }) return [PSCustomObject]@{ SqlInstance = $SqlInstance CurrentFileCount = $fileCount RecommendedCount = $recommendedCount LogicalCores = $logicalCores Status = $status Message = $message } } catch { $errMsg = "Fehler in $functionName auf ${SqlInstance}: $($_.Exception.Message)" Invoke-sqmLogging -Message $errMsg -FunctionName $functionName -Level 'ERROR' if ($EnableException) { throw } Write-Error $errMsg return [PSCustomObject]@{ SqlInstance = $SqlInstance CurrentFileCount = $null RecommendedCount = $null LogicalCores = $null Status = 'Error' Message = $errMsg } } } end { Invoke-sqmLogging -Message "$functionName abgeschlossen." -FunctionName $functionName -Level 'INFO' } } |