Skip to content

Commit 562e3ac

Browse files
Expand-DbaDbLogFile - Add -TargetVlfCount parameter (#10272)
1 parent 7c7b8ed commit 562e3ac

2 files changed

Lines changed: 95 additions & 0 deletions

File tree

public/Expand-DbaDbLogFile.ps1

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ function Expand-DbaDbLogFile {
5656
Controls the size of each growth operation in megabytes during the expansion process.
5757
If not specified, the function calculates an optimal increment size based on your target size and SQL Server version to minimize VLF fragmentation. Only specify this if you need to override the intelligent defaults.
5858
59+
.PARAMETER TargetVlfCount
60+
Sets the desired maximum number of Virtual Log Files (VLFs) after the expansion completes.
61+
When specified, the function calculates the optimal increment size to keep total VLFs at or below this value. If the current VLF count already meets or exceeds this target, a warning is issued and the database is skipped — use -ShrinkLogFile to first reduce the VLF count. If the target is mathematically impossible given the required growth, a warning is issued and the database is skipped.
62+
5963
.PARAMETER LogFileId
6064
Targets a specific transaction log file by its file ID number when databases have multiple log files.
6165
Use this when you need to expand secondary log files instead of the primary log file. Get the file ID from sys.database_files or SSMS properties.
@@ -161,6 +165,16 @@ function Expand-DbaDbLogFile {
161165
162166
Grows the transaction logs for databases db1 and db2 on SQL server SQLInstance to 100MB, sets the incremental growth to 10MB, shrinks the transaction log to 10MB and uses the directory R:\MSSQL\Backup for the required backups.
163167
168+
.EXAMPLE
169+
PS C:\> Expand-DbaDbLogFile -SqlInstance sqlcluster -Database db1 -TargetLogSize 10000 -TargetVlfCount 16
170+
171+
Grows the transaction log for database db1 on sqlcluster to 10000MB and automatically calculates an increment size that keeps the total VLF count at or below 16.
172+
173+
.EXAMPLE
174+
PS C:\> Expand-DbaDbLogFile -SqlInstance sqlcluster -Database db1 -TargetLogSize 10000 -ShrinkLogFile -ShrinkSize 10 -BackupDirectory R:\MSSQL\Backup -TargetVlfCount 8
175+
176+
Shrinks the transaction log for db1 to 10MB, then re-grows it to 10000MB using an increment size calculated to keep the final VLF count at or below 8.
177+
164178
#>
165179
[CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'Default')]
166180
param (
@@ -175,6 +189,7 @@ function Expand-DbaDbLogFile {
175189
[int]$TargetLogSize,
176190
[parameter(Position = 6)]
177191
[int]$IncrementSize = -1,
192+
[int]$TargetVlfCount = -1,
178193
[parameter(Position = 7)]
179194
[int]$LogFileId = -1,
180195
[parameter(Position = 8, ParameterSetName = 'Shrink', Mandatory)]
@@ -455,6 +470,85 @@ function Expand-DbaDbLogFile {
455470
}
456471
}
457472

473+
# If -TargetVlfCount is specified, calculate optimal increment size to achieve target VLF count
474+
if ($TargetVlfCount -gt 0) {
475+
# When ShrinkLogFile was used, remeasure VLFs post-shrink as the new baseline
476+
if ($ShrinkLogFile) {
477+
$vlfCountBaseline = Measure-DbaDbVirtualLogFile -SqlInstance $server -Database $dbName
478+
Write-Message -Level Verbose -Message "$step - VLF count after shrinking: $($vlfCountBaseline.Total)"
479+
} else {
480+
$vlfCountBaseline = $initialVLFCount
481+
}
482+
483+
$additionalVlfsAllowed = $TargetVlfCount - $vlfCountBaseline.Total
484+
485+
if ($additionalVlfsAllowed -le 0) {
486+
Write-Message -Level Warning -Message "$step - Current VLF count ($($vlfCountBaseline.Total)) is already at or above the target VLF count ($TargetVlfCount) for database '$dbName'. Use -ShrinkLogFile to reduce VLF count first, then re-expand."
487+
continue
488+
}
489+
490+
$totalGrowthKB = $TargetLogSizeKB - $currentSize
491+
492+
if ($totalGrowthKB -gt 0) {
493+
$calculatedIncrementKB = $null
494+
495+
# For SQL 2014+ (version 12+), a growth smaller than 1/8 of the current file size creates only 1 VLF
496+
if ($server.Version.Major -ge 12) {
497+
$oneVlfThresholdKB = [long]($currentSize / 8)
498+
$maxIterationsAt1 = $additionalVlfsAllowed
499+
if ($maxIterationsAt1 -gt 0) {
500+
$requiredIncrementKB = [long][Math]::Ceiling($totalGrowthKB / $maxIterationsAt1)
501+
if ($requiredIncrementKB -lt $oneVlfThresholdKB -and $requiredIncrementKB -ge 1024) {
502+
$calculatedIncrementKB = $requiredIncrementKB
503+
Write-Message -Level Verbose -Message "$step - SQL 2014+: using 1-VLF-per-growth strategy with increment $([Math]::Round($calculatedIncrementKB / 1024.0, 2))MB."
504+
}
505+
}
506+
}
507+
508+
# 4 VLFs per growth: increment < 64MB
509+
if ($null -eq $calculatedIncrementKB) {
510+
$maxIterationsAt4 = [Math]::Floor($additionalVlfsAllowed / 4)
511+
if ($maxIterationsAt4 -gt 0) {
512+
$requiredIncrementKB = [long][Math]::Ceiling($totalGrowthKB / $maxIterationsAt4)
513+
if ($requiredIncrementKB -lt (64 * 1024)) {
514+
$calculatedIncrementKB = [Math]::Max($requiredIncrementKB, 1024)
515+
Write-Message -Level Verbose -Message "$step - Using 4-VLF-per-growth strategy with increment $([Math]::Round($calculatedIncrementKB / 1024.0, 2))MB."
516+
}
517+
}
518+
}
519+
520+
# 8 VLFs per growth: 64MB <= increment < 1024MB
521+
if ($null -eq $calculatedIncrementKB) {
522+
$maxIterationsAt8 = [Math]::Floor($additionalVlfsAllowed / 8)
523+
if ($maxIterationsAt8 -gt 0) {
524+
$requiredIncrementKB = [long][Math]::Ceiling($totalGrowthKB / $maxIterationsAt8)
525+
if ($requiredIncrementKB -lt (1024 * 1024)) {
526+
$calculatedIncrementKB = [Math]::Max($requiredIncrementKB, 64 * 1024)
527+
Write-Message -Level Verbose -Message "$step - Using 8-VLF-per-growth strategy with increment $([Math]::Round($calculatedIncrementKB / 1024.0, 2))MB."
528+
}
529+
}
530+
}
531+
532+
# 16 VLFs per growth: increment >= 1024MB
533+
if ($null -eq $calculatedIncrementKB) {
534+
$maxIterationsAt16 = [Math]::Floor($additionalVlfsAllowed / 16)
535+
if ($maxIterationsAt16 -gt 0) {
536+
$requiredIncrementKB = [long][Math]::Ceiling($totalGrowthKB / $maxIterationsAt16)
537+
$calculatedIncrementKB = [Math]::Max($requiredIncrementKB, 1024 * 1024)
538+
Write-Message -Level Verbose -Message "$step - Using 16-VLF-per-growth strategy with increment $([Math]::Round($calculatedIncrementKB / 1024.0, 2))MB."
539+
}
540+
}
541+
542+
if ($null -eq $calculatedIncrementKB) {
543+
Write-Message -Level Warning -Message "$step - Cannot achieve target VLF count of $TargetVlfCount for database '$dbName': the VLF budget is too small for the required growth from $currentSizeMB MB to $TargetLogSize MB. Increase -TargetVlfCount or use -ShrinkLogFile to start from a lower base."
544+
continue
545+
}
546+
547+
Write-Message -Level Verbose -Message "$step - TargetVlfCount ${TargetVlfCount}: overriding increment size to $([Math]::Round($calculatedIncrementKB / 1024.0, 2))MB (was $([Math]::Round($LogIncrementSize / 1024.0, 2))MB)."
548+
$LogIncrementSize = [int]$calculatedIncrementKB
549+
}
550+
}
551+
458552
#start growing file
459553
If ($Pscmdlet.ShouldProcess($($server.name), "Starting log growth. Increment chunk size: $($LogIncrementSize/1024)MB for database '$dbName'")) {
460554
Write-Message -Level Verbose -Message "Starting log growth. Increment chunk size: $($LogIncrementSize/1024)MB for database '$dbName'"

tests/Expand-DbaDbLogFile.Tests.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Describe $CommandName -Tag UnitTests {
1717
"ExcludeDatabase",
1818
"TargetLogSize",
1919
"IncrementSize",
20+
"TargetVlfCount",
2021
"LogFileId",
2122
"ShrinkLogFile",
2223
"ShrinkSize",

0 commit comments

Comments
 (0)