2011-04-24

SQLIO Batch

SQLIO is a tool that must be installed on the computer where you want to test the storage. The installation is rather simple. I did a few changes away from the default installation.
Default settings. I changed to "Everyone" so that my collegueages can use the tool. The folder was changed to "C:\SQLAdmin\SQLIO".
The tool is 32-bit no matter what Windows build you install it on.
If you want to keep the registry clean, you can install SQLIO on a workstation using the MSI file and copy "sqlio.exe" to the server.

Syntax

Sqlio.exe –k{R|W} –t<threads> -s<seconds> -d<drive(-s)> -R<drive(-s)> -f<stripe> -p[I]<affinity> -a[R[I]]<mask> -o -b<size> -i<ios> -m[{C|S}]<blocks> -L[{S|P}][i]<latency> -B[{N|Y|H|S}] –S<blocks> -v1.1.1 –F<parmfile>

Default

sqlio -kR -t1 -s30 -f64 -b2 -i64 -BN testfile.dat

Example

sqlio -kW -t2 -s120 -dM -o1 -frandom -b64 -BH -LS Testfile.dat

Parameters

  • -k{R|W}: Kind of IO (R=reads, W=writes). Do Write before Read, so that there is something to read.
  • -t<threads>: Number of threads. Maximum is 256.
  • -s<seconds>: Number of seconds to run.
  • -d<drive(-s)>: Use same filename on each drive letter given. Multiple drives are possible. Write driveletters without space delimiter. Maximum is 256.
  • -R<drive(-s)>: Raw drive letters/number for I/O. Multiple drives are possible. Maximum is 256.
  • -f<stripe>: Stripe size in blocks, random, or sequential.
  • -p[I]<affinity>: CPU number for affinity. 0 (zero) based (I=ideal).
  • -a[R[I]]<mask>: CPU mask for (R=roundrobin (I=ideal)) affinity.
  • -o<outstanding>: Depth to use for completion routines. Requests are not piling up.
  • -b<size>: I/O block size in KiB.
  • -i<IOs>: Number of I/Os per I/O run.
  • -m[{C|S}]<blocks>: Do multi block IO (C=copy, S=scatter/gather).
  • -L[{S|P}][i]<latency>: Latencies from (S=system, P=processor) timer.
  • -B[{N|Y|H|S}]: Set buffering (N=none, Y=all, H=hardware, S=software).
  • -S<blocks>: Start I/Os number of blocks into file.
  • -v1.1.1: I/Os runs use same blocks, as in version 1.1.1. sqlio.exe is version 1.5.SG. Check version with the parameter “-?”.
  • -F<parmfile>: Read parameters from <parmfile>. The length of the filename has a maximum of 256.

Scenario

All tests use up to 8 processing threads, run for 10 minutes each, are enabled for multi-IO, and allow up to between 16 and 64 outstanding IOs each.
Files used include 2 data files and 1 log file.
  • Aligned or not.
  • 4 or 64 KB NTFS cluster size
  • VRAID5 or -10
The tests include each of the following:
  1. 8 KB random writes to the data files (pattern for checkpoints, tempdb, etc.)
  2. 8 KB random reads to the data files (pattern for random data reads, singleton seeks, etc.)
  3. 64 KB sequential writes to the log file (bulk log writes)
  4. 8 KB random reads to the log file (rollbacks, log reader, etc.)
  5. 1 KB sequential writes to the log file (small log writes)
  6. 64 KB sequential writes to the data files (checkpoints, reindex, bulk inserts)
  7. 64 KB sequential reads to the data files (read-ahead, reindex, checkdb)
  8. 128 KB sequential reads to the data files (read-ahead, reindex, checkdb)
  9. 128 KB sequential writes to the data files (bulk inserts, reindex)
  10. 256 KB sequential reads to the data files (read-ahead, reindex)
  11. 1 MB sequential reads to the data files (backups)

Batch

This PowerShell script executes SQLIO with various parameter values
#requires -version 2.0
$Drive = @('G', 'H', 'I', 'J')

$IO_Kind = @('W', 'R')  # Write before read so that there is something to read.
$Threads = @(2, 4, 8)
#$Threads = @(2, 4, 8, 16, 32, 64)
$Seconds = 10*60  # Five minutes
$Factor = @('random', 'sequential')
$Outstanding = @(1, 2, 4, 8, 16, 32, 64, 128)
$BlockSize = @(1, 8, 64, 128, 256, 1024)

Clear-Host

$ResultFileName = "SQLIO_Result.{0:yyyy-MM-dd}.txt" -f $([System.DateTime]::Now)
"{0:s}  Results are written to the file `"$ResultFileName`"." -f $([System.DateTime]::Now)
$InvokeNumber = 0
$InvokeCount = $($IO_Kind.Count * $Threads.Count * $Drive.Count * $Factor.Count * $Outstanding.Count * $BlockSize.Count)

"{0:s}  Batch executed by the user `"$([Security.Principal.WindowsIdentity]::GetCurrent().Name)`" on the computer `"$($env:COMPUTERNAME)(.$($env:USERDNSDOMAIN))`"." -f $([System.DateTime]::Now) > $ResultFileName

foreach ($_blocksize in $BlockSize) {
foreach ($_outstanding in $Outstanding) {
foreach ($_factor in $Factor) {
foreach ($_drive in $Drive) {
foreach ($_threads in $Threads) {
$IO_Kind | ForEach-Object {
$InvokeNumber++
"`n{0:s}  Step $InvokeNumber of $InvokeCount." -f $([System.DateTime]::Now) >> $ResultFileName
$SqlioCmd = "-k$_ -t$_threads -s$Seconds -d$_drive -f$_factor -o$_outstanding -b$_blocksize -LS -BH sqlio.test.dat"
Write-Progress -Activity 'Running SQLIO (sqlio.exe).' -Status "Step $InvokeNumber of $($InvokeCount): $SqlioCmd" -Id 1 -PercentComplete ($InvokeNumber/$InvokeCount * 100)
"{0:s}  SQLIO parameters: $SqlioCmd" -f $([System.DateTime]::Now)  >> $ResultFileName
Invoke-Expression -Command ".\sqlio.exe $SqlioCmd" >> $ResultFileName
if ($InvokeNumber -ne $InvokeCount) {
"{0:s}  Step finshed. Batch paused 60 seconds to allow I/O idle state." -f $([System.DateTime]::Now) >> $ResultFileName
Start-Sleep -Seconds 60
}
}
}
}
}
}
}
"`n{0:s}  SQLIO batch finshed." -f $([System.DateTime]::Now)  >> $ResultFileName

The usage of the script is just calling the script:
./SQLIO_Batch.ps1
Typically a batch run will take about three days and will generate a 1.1 MiB result file.

Parse

This PowerShell script parse a result file from the script above "SQLIO_Batch.ps1". The parse script is based on Perl script from Linchi Shea "Parse the sqlio.exe Output".
#requires -version 2.0
param ([string]$ResultFileName = $(throw 'The parameter "ResultFileName" requires a file name.'))

$Sqlio = @()
ForEach($line in Get-Content $ResultFileName) {
$match = $line -match "-k(?<kind>\w) -t(?<threads>\d+) -s(?<seconds>\d+) -d(?<drive>\w*) -f(?<stripe>\w*) -o(?<outstanding>\d+) -b(?<size>\d+)"

if ($match -eq $true) {

$Kind = $Matches['kind']

$Threads = [int]$Matches['threads']
$Seconds = [int]$Matches['seconds']
$Drive = $Matches['drive']
$Stripe = $Matches['stripe']
$Outstanding = [int]$Matches['outstanding']
$Size = [int]$Matches['size']
}
$match = $line -match "^IOs/sec: *(?<ios_per_sec>\d+.\d+)"
if ($match -eq $true) { $IOs = [float]$Matches['ios_per_sec'] }
$match = $line -match "^MBs/sec: *(?<mbs_per_sec>\d+.\d+)"
if ($match -eq $true) { $MBs = [float]$Matches['mbs_per_sec'] }
$match = $line -match "^Min_Latency\(ms\): *(?<min_latency>\d+)"
if ($match -eq $true) { $Latency_min = [int]$Matches['min_latency'] }
$match = $line -match "^Avg_Latency\(ms\): *(?<avg_latency>\d+)"
if ($match -eq $true) { $Latency_avg = [int]$Matches['avg_latency'] }

$match = $line -match "^Max_Latency\(ms\): *(?<max_latency>\d+)"
if ($match -eq $true) { 
$Sqlio += New-Object PSObject -Property @{
Kind = $Kind
Threads = $Threads
Seconds = $Seconds
Drive = $Drive
Stripe = $Stripe
Outstanding = $Outstanding
Size = $Size
IOs = $IOs
MBs = $MBs
Latency_min = $Latency_min
Latency_avg = $Latency_avg
Latency_max = [int]$Matches['max_latency']
}
}
}

#$Sqlio | Format-Table -Property IOs,MBs,Latency_min,Latency_avg,Latency_max -AutoSize
$Sqlio | Format-Table -Property Kind,Threads,Seconds,Drive,Stripe,Outstanding,Size,IOs,MBs,Latency_min,Latency_avg,Latency_max -AutoSize

#$Sqlio | Export-Csv SQLIO_Parse.csv
The script can in the end be altered to give a filtered output in a table or output in a CSV file. A CSV file can be imported in a spreadsheet for further analysis.
Usage of the script requires the name of a result file in the parameter "ResultFileName":
./SQLIO-Parse.ps1 -ResultFileName <file name>
This is an example on a script execution:
./SQLIO-Parse.ps1 -ResultFileName 'SQLIO_Result.2010-12-24.txt'

Discussion

The amount of data is so large, so a deeper analysis could be done using SQL Server Analysis Services.
The results has in my case been rather usefull to get a nice talk with the storage guys about storage and its usage and configuration.

History

2011-04-24 : Entry postet.
2013-09-10 : Parse script fixed on threads as described in comment by Manuel (2013-02-27).
2015-02-03 : Solution discussed by David Klee in the blog post "Storage Benchmarking with SQLIO Batch".
2017-08-22 : Solution mentioned in session on PASS Summit 2014 by David Klee about "Right-Sizing Your SQL Server Virtual Machine" (46:50).

2011-04-14

Token-based server access validation failed

After installing the first SQL Server 2008 R2 in a new domain, I got this error when I tried to log on the database instance:
2011-04-14 13:46:51.35 Logon       Error: 18456, Severity: 14, State: 11.
2011-04-14 13:46:51.35 Logon       Login failed for user 'SANDBOX\myadministrator'. Reason: Token-based server access validation failed with an infrastructure error. Check for previous errors. [CLIENT: <local machine>]

A restart of the database service did not help. Neither did a "Run as administrator" to circumvent the UAC.
A discussion on SQL Server Central showed me the way.
I logged off all computers in the domain to refresh my security token, and then a login could be done - also without "Run as administrator"

Reference:

2011-03-29

Installing DTS Components

I had to work on a installation with DTS packages and was forced to install the DTS components "DTS Designer Components" and "DTS Run-Time Components".

After the installation I could still not open DTS packages. I got a error like
SQL Server 2000 DTS Designer components are required to edit DTS packages. Install the special Web download, "SQL Server 2000 DTS Designer Components" to use this feature. (Microsoft.SqlServer.DtsObjectExplorerUI)

A quick search gave me the thread "SQL Server 2000 DTS Designer components are required to edit DTS packages - in SQL 2008". I changed the environmental variable as described where I put the value for DTS before anything from SQL Server 2008 and Visual Studio.
The thread is saying that restarting Management Studio is enough to get the new setting, but I had to restart the workstation. Perhaps as I am not local administrator with the my normal user.

Reference

MSDN Library: "Support for SQL Server 2000 DTS in SQL Server 2008 R2"
SQL Server Forums: "SQL Server 2000 DTS Designer components are required to edit DTS packages - in SQL 2008"

2011-03-14

Could not load file or assembly Microsoft.AnalysisServices

After a Service Pack upgrade on a SQL 2005 installation from SP2 to SP4, a job failed with
Executed as user: *****. A .NET Framework error occurred during execution of user-defined routine or aggregate "NameOfUserDefinedStoredProcedure":   System.IO.FileLoadException: Could not load file or assembly 'Microsoft.AnalysisServices, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91' or one of its dependencies. Assembly in host store has a different signature than assembly in GAC. (Exception from HRESULT: 0x80131050)  System.IO.FileLoadException:      at nnn.mmm.fff(String s. The step failed.

Searching the internet gave me the MSDN Forum thread "Framework error:Could not load file or assembly 'Microsoft.AnalysisServices, Version=9.0.242.0". Here I was directed to KB949080 and the handling of assemblies.

A look at the assemblies in the database with
SELECT * FROM sys.assemblies;
and their files with
SELECT * FROM sys.assembly_files;
gave me the details to refresh the assembly registrations with
ALTER ASSEMBLY [Microsoft.AnalysisServices]
FROM N'C:\Program Files (x86)\Microsoft SQL Server\90\SDK\Assemblies\Microsoft.AnalysisServices.DLL';


Now everything is working again.

Reference

MSDN Library: "ALTER ASSEMBLY (Transact-SQL)"
KB949080: "... Assembly in host store has a different signature than assembly in GAC..."

2011-03-11

Using a SMO object as parameter value

It looks like a SMO object is implicit converted to a String object, when it is used in a function call by a parameter name.

I have a function, where the parameter is defined as
function Import-FileGroup {
param ([Microsoft.SqlServer.Management.Smo.Database]$smoDatabase = $(throw 'Value requered for parameter "smoDatabase" in function Import-FileGroup.'))

...
}

When I call the function with a parameter name
Import-FileGroup -$smoDatabase $smoDb
it fail with this message
Import-FileGroup : Cannot process argument transformation on parameter 'smoDatabase'. Cannot convert the "-" value of type "System.String" to type "Microsoft.SqlServer.Management.Smo.Database".
At U:\sqladmin\dn_sqladmin\Development\Import-Database.ps1:***** char:17
+ Import-FileGroup <<<<  -$smoDatabase $smoDb
    + CategoryInfo          : InvalidData: (:) [Import-FileGroup], ParameterBindin...mationException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,Import-FileGroup


But when I call the function without a parameter name
Import-FileGroup $smoDb
everything is working fine.

Not what I expected, but I have now made the note for future use...

The variable „$smoDb“ is created like this
$smoSrv = New-Object Microsoft.SqlServer.Management.Smo.Server 'SANDY.sqladmin.lan'
$smoDb = $smoSrv.Databases['my_database']