Skip to content

Commit e314ee2

Browse files
Invoke-DbaBalanceDataFiles - Add -TargetFileGroup parameter
Adds a -TargetFileGroup parameter that allows rebuilding clustered indexes into a specific filegroup, enabling data migration between filegroups. When -TargetFileGroup is specified: - All tables with clustered indexes are eligible (bypasses the 2+ files requirement) - The target filegroup is validated to exist and be writable - Each clustered index's FileGroup property is set before rebuild - The original filegroup is restored in memory if the rebuild fails Resolves #8863 (do Invoke-DbaBalanceDataFiles) Co-authored-by: Andreas Jordan <andreasjordan@users.noreply.github.com>
1 parent 97d03be commit e314ee2

2 files changed

Lines changed: 58 additions & 5 deletions

File tree

public/Invoke-DbaBalanceDataFiles.ps1

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ function Invoke-DbaBalanceDataFiles {
1818
A file group would have at least have 2 data files and should be writable.
1919
If a table is within such a file group it will be subject for processing. If not the table will be skipped.
2020
21+
When the -TargetFileGroup parameter is specified, indexes can be moved from their current filegroup
22+
to the specified target filegroup regardless of how many data files the current filegroup contains.
23+
This allows consolidating or migrating data between filegroups.
24+
2125
Note: this command does not perform a disk space check for non-Windows machines so make sure you have enough space on the disk.
2226
2327
.PARAMETER SqlInstance
@@ -38,6 +42,12 @@ function Invoke-DbaBalanceDataFiles {
3842
Specifies which tables to balance data for within the target databases. Only tables with clustered indexes in file groups containing multiple data files will be processed.
3943
When omitted, all eligible tables in the database will be processed. Use this to target specific large tables that need data redistribution.
4044
45+
.PARAMETER TargetFileGroup
46+
The name of the filegroup to rebuild indexes into. When specified, indexes can be moved from their current filegroup
47+
to the target filegroup, regardless of how many data files the current filegroup contains.
48+
49+
When not specified, the function only processes tables in filegroups with at least 2 data files.
50+
4151
.PARAMETER RebuildOffline
4252
Forces all clustered index rebuilds to occur offline, which redistributes data between files but blocks table access during the operation.
4353
Use this switch when you need to balance data files but can accept downtime, or when working with SQL Server editions that don't support online index operations (Standard, Express, Web).
@@ -107,6 +117,16 @@ function Invoke-DbaBalanceDataFiles {
107117
This command will consider the fact that there might be a SQL Server edition that does not support online rebuilds of indexes.
108118
By supplying this parameter you give permission to do the rebuilds offline if the edition does not support it.
109119
120+
.EXAMPLE
121+
PS C:\> Invoke-DbaBalanceDataFiles -SqlInstance sql1 -Database db1 -TargetFileGroup "SECONDARY"
122+
123+
This command will rebuild all clustered indexes into the SECONDARY filegroup, moving data from whatever filegroup each table currently resides in.
124+
125+
.EXAMPLE
126+
PS C:\> Invoke-DbaBalanceDataFiles -SqlInstance sql1 -Database db1 -Table table1,table2 -TargetFileGroup "SECONDARY" -RebuildOffline
127+
128+
This command will rebuild the clustered indexes of table1 and table2 offline, moving them into the SECONDARY filegroup.
129+
110130
#>
111131
[CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess, ConfirmImpact = "Medium")]
112132
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification = "Singular Noun doesn't make sense")]
@@ -117,6 +137,7 @@ function Invoke-DbaBalanceDataFiles {
117137
[object[]]$Database,
118138
[Alias("Tables")]
119139
[object[]]$Table,
140+
[string]$TargetFileGroup,
120141
[switch]$RebuildOffline,
121142
[switch]$EnableException,
122143
[switch]$Force
@@ -264,13 +285,30 @@ function Invoke-DbaBalanceDataFiles {
264285
# ARray to hold the file groups with properties
265286
$balanceableTables = @()
266287

267-
# Loop through each of the file groups
288+
if ($TargetFileGroup) {
289+
# Validate the target filegroup exists and is writable
290+
$targetFG = $fileGroups[$TargetFileGroup]
291+
if (-not $targetFG) {
292+
Stop-Function -Message "FileGroup '$TargetFileGroup' does not exist in database $db on instance $instance" -Target $instance -Continue
293+
continue
294+
}
295+
if ($targetFG.Readonly) {
296+
Stop-Function -Message "FileGroup '$TargetFileGroup' is read-only in database $db on instance $instance" -Target $instance -Continue
297+
continue
298+
}
268299

269-
foreach ($fg in $fileGroups) {
300+
# When a target filegroup is specified, all tables are eligible
301+
Write-Message -Message "Target filegroup '$TargetFileGroup' specified - all tables with clustered indexes are eligible" -Level Verbose
302+
$balanceableTables = $db.Tables
303+
} else {
304+
# Loop through each of the file groups
270305

271-
# If there is less than 2 files balancing out data is not possible
272-
if (($fg.Files.Count -ge 2) -and ($fg.Readonly -eq $false)) {
273-
$balanceableTables += $fg.EnumObjects() | Where-Object { $_.GetType().Name -eq 'Table' }
306+
foreach ($fg in $fileGroups) {
307+
308+
# If there is less than 2 files balancing out data is not possible
309+
if (($fg.Files.Count -ge 2) -and ($fg.Readonly -eq $false)) {
310+
$balanceableTables += $fg.EnumObjects() | Where-Object { $_.GetType().Name -eq 'Table' }
311+
}
274312
}
275313
}
276314

@@ -313,6 +351,9 @@ function Invoke-DbaBalanceDataFiles {
313351
# Get the original index operation
314352
[bool]$originalIndexOperation = $ci.OnlineIndexOperation
315353

354+
# Save the original filegroup in case of error
355+
$originalFileGroup = $ci.FileGroup
356+
316357
# Set the rebuild option to be either offline or online
317358
if ($RebuildOffline) {
318359
$ci.OnlineIndexOperation = $false
@@ -321,6 +362,12 @@ function Invoke-DbaBalanceDataFiles {
321362
$ci.OnlineIndexOperation = $true
322363
}
323364

365+
# Set the target filegroup if specified
366+
if ($TargetFileGroup) {
367+
Write-Message -Message "Setting filegroup for index $($ci.Name) to $TargetFileGroup" -Level Verbose
368+
$ci.FileGroup = $TargetFileGroup
369+
}
370+
324371
# Rebuild the index
325372
try {
326373
Write-Message -Message "Rebuilding index $($ci.Name)" -Level Verbose
@@ -332,6 +379,11 @@ function Invoke-DbaBalanceDataFiles {
332379
# Set the original index operation back for the index
333380
$ci.OnlineIndexOperation = $originalIndexOperation
334381

382+
# Restore the original filegroup if we changed it
383+
if ($TargetFileGroup) {
384+
$ci.FileGroup = $originalFileGroup
385+
}
386+
335387
# Set the success flag
336388
$success = $false
337389

tests/Invoke-DbaBalanceDataFiles.Tests.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Describe $CommandName -Tag UnitTests {
1515
"SqlCredential",
1616
"Database",
1717
"Table",
18+
"TargetFileGroup",
1819
"RebuildOffline",
1920
"Force",
2021
"EnableException"

0 commit comments

Comments
 (0)