66 Executes UPDATE STATISTICS with configurable options (scan percentage, only modified statistics, etc.).
77 Can be restricted to specific databases, tables, or statistics.
88
9+ Note: dbatools has no Update statistics cmdlet, so this runs UPDATE STATISTICS directly via
10+ Invoke-DbaQuery. The set of statistics to touch is determined from sys.stats /
11+ sys.dm_db_stats_properties so -OnlyModified, -Index and the Table/Statistics filters work
12+ server-side before anything is updated.
13+
914. PARAMETER SqlInstance
1015 SQL Server instance (default: current computer name).
1116
1217. PARAMETER SqlCredential
1318 PSCredential for the connection.
1419
1520. PARAMETER Database
16- Database name or wildcard pattern.
21+ Database name or wildcard pattern (PowerShell wildcards, e.g. '*' or 'Sales*'). System databases
22+ are excluded unless named explicitly. Default: '*' (all user databases).
1723
1824. PARAMETER Table
19- Table name or wildcard pattern.
25+ Table name or wildcard pattern. Default: '*'.
2026
2127. PARAMETER Statistics
22- Statistic name or wildcard pattern.
28+ Statistic name or wildcard pattern. Default: '*'.
2329
2430. PARAMETER SamplePercent
25- Percentage of rows used for the update (0 = full scan ). Default: 0.
31+ Percentage of rows used for the update (0 = FULLSCAN ). Default: 0.
2632
2733. PARAMETER OnlyModified
28- Only update statistics that have changed since the last update. Default: $true.
34+ Only update statistics that have changed since the last update (modification_counter > 0) . Default: $true.
2935
3036. PARAMETER Index
31- Also update statistics associated with an index. Default: $true.
37+ Also update statistics backed by an index. When $false, only column statistics are updated . Default: $true.
3238
3339. PARAMETER WhatIf
3440 Shows which statistics would be affected.
4046 Invoke-sqmUpdateStatistics -Database 'SalesDB' -SamplePercent 10
4147
4248. NOTES
43- Uses dbatools (Update-DbaDbStatistic) .
49+ Uses dbatools (Get-DbaDatabase, Invoke-DbaQuery). Requires sysadmin/db_owner on the targets .
4450#>
4551function Invoke-sqmUpdateStatistics {
4652 [CmdletBinding (SupportsShouldProcess = $true )]
@@ -67,42 +73,94 @@ function Invoke-sqmUpdateStatistics {
6773
6874 begin {
6975 $functionName = $MyInvocation.MyCommand.Name
70- if (-not (Get-Module - ListAvailable - Name dbatools)) {
71- throw " dbatools-Modul nicht gefunden."
76+ if (-not $ script :dbatoolsAvailable -and -not (Get-Module - ListAvailable - Name dbatools)) {
77+ throw " dbatools-Modul nicht gefunden. Bitte installieren: Install-Module dbatools "
7278 }
79+
80+ # PowerShell-Wildcards (* ?) -> SQL LIKE (% _)
81+ $tableLike = ($Table -replace ' \*' , ' %' ) -replace ' \?' , ' _'
82+ $statLike = ($Statistics -replace ' \*' , ' %' ) -replace ' \?' , ' _'
83+
84+ $connParams = @ { SqlInstance = $SqlInstance ; ErrorAction = ' Stop' }
85+ if ($SqlCredential ) { $connParams [' SqlCredential' ] = $SqlCredential }
86+
87+ Invoke-sqmLogging - Message " Starte $functionName auf $SqlInstance (Database='$Database ', Table='$Table ', Statistics='$Statistics ', SamplePercent=$SamplePercent , OnlyModified=$OnlyModified , Index=$Index )" - FunctionName $functionName - Level " INFO"
7388 }
7489
7590 process {
7691 try {
77- $params = @ {
78- SqlInstance = $SqlInstance
79- SqlCredential = $SqlCredential
80- Database = $Database
81- Table = $Table
82- Statistic = $Statistics
83- SamplePercent = $SamplePercent
84- OnlyModified = $OnlyModified
85- Index = $Index
86- EnableException = $EnableException
92+ # Zieldatenbanken aufloesen. System-DBs nur wenn explizit benannt (kein Wildcard, kein '*').
93+ $dbParams = $connParams.Clone ()
94+ if ($Database -notmatch ' [\*\?]' ) { $dbParams [' Database' ] = $Database } else { $dbParams [' ExcludeSystem' ] = $true }
95+ $targetDbs = @ (Get-DbaDatabase @dbParams | Where-Object { $_.IsAccessible -and $_.Name -like $Database })
96+
97+ if ($targetDbs.Count -eq 0 ) {
98+ Invoke-sqmLogging - Message " Keine passenden Datenbanken fuer Muster '$Database ' gefunden." - FunctionName $functionName - Level " WARNING"
99+ return
87100 }
88- if ($PSCmdlet.ShouldProcess (" UpdateStatistics on $SqlInstance " , " Update" )) {
89- $result = Update-DbaDbStatistic @params
90- $result | ForEach-Object {
91- [PSCustomObject ]@ {
92- Database = $_.Database
93- Table = $_.Table
94- Statistic = $_.Statistic
95- Status = ' Success'
96- Message = " Updated"
101+
102+ # WITH-Klausel: FULLSCAN oder SAMPLE n PERCENT
103+ $withClause = if ($SamplePercent -le 0 ) { ' FULLSCAN' } else { " SAMPLE $SamplePercent PERCENT" }
104+
105+ foreach ($db in $targetDbs ) {
106+ $dbName = $db.Name
107+
108+ # Zu aktualisierende Statistiken serverseitig ermitteln.
109+ # auto_created/user_created = Spaltenstatistiken; alles andere (index-gestuetzt) nur wenn -Index.
110+ $selectQuery = @"
111+ SELECT sch.name AS SchemaName, t.name AS TableName, s.name AS StatName,
112+ CASE WHEN i.object_id IS NOT NULL THEN 1 ELSE 0 END AS IsIndexStat,
113+ sp.modification_counter AS ModCounter
114+ FROM sys.stats s
115+ JOIN sys.objects t ON s.object_id = t.object_id AND t.type = 'U' AND t.is_ms_shipped = 0
116+ JOIN sys.schemas sch ON t.schema_id = sch.schema_id
117+ LEFT JOIN sys.indexes i ON i.object_id = s.object_id AND i.name = s.name
118+ OUTER APPLY sys.dm_db_stats_properties(s.object_id, s.stats_id) sp
119+ WHERE t.name LIKE @table AND s.name LIKE @stat
120+ "@
121+ $stats = @ (Invoke-DbaQuery @connParams - Database $dbName - Query $selectQuery - SqlParameter @ { table = $tableLike ; stat = $statLike })
122+
123+ foreach ($st in $stats ) {
124+ if (-not $Index -and $st.IsIndexStat -eq 1 ) { continue }
125+ if ($OnlyModified -and (($st.ModCounter -eq $null ) -or ($st.ModCounter -le 0 ))) { continue }
126+
127+ $tableEsc = " [$ ( $st.SchemaName -replace ' \]' , ' ]]' ) ].[$ ( $st.TableName -replace ' \]' , ' ]]' ) ]"
128+ $statEsc = " [$ ( $st.StatName -replace ' \]' , ' ]]' ) ]"
129+ $updateQuery = " UPDATE STATISTICS $tableEsc ($statEsc ) WITH $withClause "
130+ $target = " $dbName : $ ( $st.SchemaName ) .$ ( $st.TableName ) .$ ( $st.StatName ) "
131+
132+ if ($PSCmdlet.ShouldProcess ($target , " UPDATE STATISTICS WITH $withClause " )) {
133+ try {
134+ Invoke-DbaQuery @connParams - Database $dbName - Query $updateQuery | Out-Null
135+ [PSCustomObject ]@ {
136+ SqlInstance = $SqlInstance
137+ Database = $dbName
138+ Table = " $ ( $st.SchemaName ) .$ ( $st.TableName ) "
139+ Statistic = $st.StatName
140+ Status = ' Success'
141+ Message = " Updated WITH $withClause "
142+ }
143+ }
144+ catch {
145+ $errMsg = " Fehler bei UPDATE STATISTICS ($target ): $ ( $_.Exception.Message ) "
146+ Invoke-sqmLogging - Message $errMsg - FunctionName $functionName - Level " ERROR"
147+ if ($EnableException ) { throw }
148+ [PSCustomObject ]@ {
149+ SqlInstance = $SqlInstance
150+ Database = $dbName
151+ Table = " $ ( $st.SchemaName ) .$ ( $st.TableName ) "
152+ Statistic = $st.StatName
153+ Status = ' Failed'
154+ Message = $errMsg
155+ }
156+ }
97157 }
98158 }
99- } else {
100- Write-Verbose " WhatIf: UpdateStatistics would be executed on $SqlInstance "
101159 }
102160 }
103161 catch {
104162 Invoke-sqmLogging - Message $_.Exception.Message - FunctionName $functionName - Level " ERROR"
105163 if ($EnableException ) { throw }
106164 }
107165 }
108- }
166+ }
0 commit comments