Quantcast
Channel: SQL Server Wiki
Viewing all 33 articles
Browse latest View live

Find Queries in the Plan Cache That Are Missing an Index

$
0
0
Current Revision posted to SQL Server by Lars Astrom on 7/19/2013 1:52:38 PM

See Also: [[wiki:Main Page|Main_Page]] - [[wiki:Transact SQL Code Library|Transact SQL Code Library]] - [[wiki:Index Related DMV Queries|Index Performance Tuning]]

Queries in the Plan Cache That Are Missing an Index

This query goes against the proc cache and returns one row for every plan missing an index.

The cache is not permanent: servers with small amounts of memory (or large numbers of completely different queries) may want to run this periodically to catch queries while they're still in the cache. For historical tracking, the DBA could create a job that inserts this data into a permanent table every hour, and then check over time to see what queries have created problems.

This query is expensive in terms of server resources: use it with caution if the procedure cache is large.

Credit to Adi Cohen for replacing the LIKE wildcard filter.

T-SQL Code

If you copy/paste this query into your server and get an error about "VALUE", change the three "VALUE" words to lower-case "value". There's an issue with case-sensitivity in the SQL-rendering code we use here at the wiki to display code.

SELECT qp.query_plan
, total_worker_time/execution_count AS AvgCPU 
, total_elapsed_time/execution_count AS AvgDuration 
, (total_logical_reads+total_physical_reads)/execution_count AS AvgReads 
, execution_count 
, SUBSTRING(st.TEXT, (qs.statement_start_offset/2)+1 , ((CASE qs.statement_end_offset WHEN -1 THEN datalength(st.TEXT) ELSE qs.statement_end_offset END - qs.statement_start_offset)/2) + 1) AS txt 
, qp.query_plan.value('declare default element namespace "http://schemas.microsoft.com/sqlserver/2004/07/showplan"; (/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple/QueryPlan/MissingIndexes/MissingIndexGroup/@Impact)[1]' , 'decimal(18,4)') * execution_count AS TotalImpact
, qp.query_plan.value('declare default element namespace "http://schemas.microsoft.com/sqlserver/2004/07/showplan"; (/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple/QueryPlan/MissingIndexes/MissingIndexGroup/MissingIndex/@Database)[1]' , 'varchar(100)') AS [DATABASE]
, qp.query_plan.value('declare default element namespace "http://schemas.microsoft.com/sqlserver/2004/07/showplan"; (/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple/QueryPlan/MissingIndexes/MissingIndexGroup/MissingIndex/@Table)[1]' , 'varchar(100)') AS [TABLE]
FROM sys.dm_exec_query_stats qs
cross apply sys.dm_exec_sql_text(sql_handle) st
cross apply sys.dm_exec_query_plan(plan_handle) qp
WHERE qp.query_plan.exist('declare default element namespace "http://schemas.microsoft.com/sqlserver/2004/07/showplan";/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple/QueryPlan/MissingIndexes/MissingIndexGroup/MissingIndex[@Database!="m"]') = 1
ORDER BY TotalImpact DESC

Query Test Checklist

  • Works on SQL Server 2008: Yes
  • Works on SQL Server 2005: Yes
  • Works on SQL Server 2000: No - unfortunately, there's no way to gather this data on SQL Server 2000.
  • Works on Standard Edition: Yes
  • Works on case-sensitive servers: Yes (see note above the query)


Queries with Index Scans Due to Implicit Conversions

$
0
0
Current Revision posted to SQL Server by Lars Astrom on 7/19/2013 1:53:00 PM

See Also: [[wiki:Main Page|Main_Page]] - [[wiki:Transact SQL Code Library|Transact SQL Code Library]] - [[wiki:Procedure Cache Related Queries|Procedure Cache Related Queries]]

This query can find queries in cache that are doing index scans due to implicit conversions.

For more details see this post: http://statisticsio.com/Home/tabid/36/articleType/ArticleView/articleId/318/Finding-Index-Scans-due-to-Implicit-Conversions.aspx

T-SQL Script

If you get an error about "VALUE" when running this query, change "VALUE" to "value", lower case. The script rendering engine we use on SQLServerPedia may uppercase the "VALUE" keyword.

with XMLNAMESPACES 
('http://schemas.microsoft.com/sqlserver/2004/07/showplan' as sql)
select
total_worker_time/execution_count AS AvgCPU
, total_elapsed_time/execution_count AS AvgDuration
, (total_logical_reads+total_physical_reads)/execution_count AS AvgReads
, execution_count
, SUBSTRING(st.TEXT, (qs.statement_start_offset/2)+1 , ((CASE
qs.statement_end_offset WHEN -1 THEN datalength(st.TEXT) ELSE
qs.statement_end_offset END - qs.statement_start_offset)/2) + 1) AS txt
, qs.max_elapsed_time
, db_name(qp.dbid) as database_name
, quotename(object_schema_name(qp.objectid, qp.dbid)) + N'.' + 
quotename(object_name(qp.objectid, qp.dbid)) as obj_name
, qp.query_plan.value( 
N'(/sql:ShowPlanXML/sql:BatchSequence/sql:Batch/sql:Statements/sql:StmtSimple[@StatementType 
= 
"SELECT"]/sql:QueryPlan/sql:RelOp/descendant::*/sql:ScalarOperator[contains(@ScalarString, 
"CONVERT_IMPLICIT")])[1]/@ScalarString', 'nvarchar(4000)' ) as scalar_string
, qp.query_plan
from sys.dm_exec_query_stats as qs
cross apply sys.dm_exec_query_plan(qs.plan_handle) as qp
cross apply sys.dm_exec_sql_text(qs.sql_handle) st
where qp.query_plan.exist( 
N'/sql:ShowPlanXML/sql:BatchSequence/sql:Batch/sql:Statements/sql:StmtSimple[@StatementType 
= 
"SELECT"]/sql:QueryPlan/sql:RelOp/sql:IndexScan/descendant::*/sql:ScalarOperator[contains(@ScalarString, 
"CONVERT_IMPLICIT")]' ) = 1;

Query Test Checklist

  • Works on SQL Server 2008: Yes
  • Works on SQL Server 2005: Yes
  • Works on SQL Server 2000: No
  • Works on Standard Edition: Yes
  • Works on case-sensitive servers: Yes (see note above query)

Queries in Procedure Cache

$
0
0
Current Revision posted to SQL Server by Lars Astrom on 7/19/2013 1:53:14 PM

See Also: [[wiki:Main Page|Main_Page]] - [[wiki:Transact SQL Code Library|Transact SQL Code Library]] - [[wiki:Procedure Cache Related Queries|Procedure Cache Related Queries]]

This query can almost replace a trace. It is actually better if you want to correlate queries with xml query plans. Adjust the sort as needed.

Use with caution if your server suffers from procedure cache bloat: if you have a large number of application databases on a server running a wide variety of queries, it may have a very large procedure cache. Generally, start by running this on a server with a very low amount of load to get a feel for the amount of resources required. It's not uncommon for this query to take several minutes on a server with a large number of ad-hoc queries in the procedure cache.

T-SQL Script

select total_worker_time/execution_count as AvgCPU, total_worker_time AS TotalCPU
, total_elapsed_time/execution_count as AvgDuration, total_elapsed_time AS TotalDuration  
, total_logical_reads/execution_count as AvgReads, total_logical_reads AS TotalReads
, execution_count   
, substring(st.text, (qs.statement_start_offset/2)+1  
, ((case qs.statement_end_offset  when -1 then datalength(st.text)  
else qs.statement_end_offset  
end - qs.statement_start_offset)/2) + 1) as txt  
, query_plan
from sys.dm_exec_query_stats as qs  
cross apply sys.dm_exec_sql_text(qs.sql_handle) as st  
cross apply sys.dm_exec_query_plan (qs.plan_handle) as qp 
order by 1 desc

Query Test Checklist

  • Works on SQL Server 2008: Yes
  • Works on SQL Server 2005: Yes
  • Works on SQL Server 2000: No
  • Works on Standard Edition: Yes
  • Works on case-sensitive servers: Yes

Calculate Current Table Sizes

$
0
0
Current Revision posted to SQL Server by Lars Astrom on 7/19/2013 1:53:28 PM

See Also: [[wiki:Main Page|Main_Page]] - [[wiki:Transact SQL Code Library|Transact SQL Code Library]] - [[wiki:Size Calculations|Size Calculations]]

This script loops through all of the objects in the current database that are user tables, and runs sp_SpaceUsed for each of them. It returns a list of all objects in order of table name, but you can change the sort order to go by size instead.

T-SQL Code

If you get an error on a case-sensitive server saying that it can't find SP_SPACEUSED, it's due to the rendering engine we use on SQLServerPedia. Change that part of the code to read sp_spaceused instead, lower case.

DECLARE @CurrentTableName NVARCHAR(100)
CREATE TABLE #TableList

 (TableName NVARCHAR(100)
  , RowsCount INT
  , KBReserved VARCHAR(15)
  , KBData VARCHAR(15)
  , KBIndex VARCHAR(15)
  , KBUnused VARCHAR(15)
  )


-- Run a cursor through all of the tables
DECLARE result_cursor CURSOR FOR
SELECT '[' + name + ']' FROM dbo.sysobjects WHERE type = 'U'
OPEN result_cursor
FETCH NEXT FROM result_cursor INTO @CurrentTableName
WHILE @@FETCH_STATUS = 0
BEGIN 
	INSERT INTO #TableList
	  EXEC dbo.sp_spaceused @CurrentTableName
FETCH NEXT FROM result_cursor INTO @CurrentTableName
END
--end loop
--clean up
CLOSE result_cursor
DEALLOCATE result_cursor
UPDATE #TableList

 SET KBReserved = REPLACE(KBReserved, ' KB', )
   , KBData = REPLACE(KBData, ' KB', )
   , KBIndex = REPLACE(KBIndex, ' KB', )
   , KBUnused = REPLACE(KBUnused, ' KB', )


SELECT * FROM #TableList ORDER BY TableName
DROP TABLE #TableList

Query Test Checklist

  • Works on SQL Server 2008: Yes
  • Works on SQL Server 2005: Yes
  • Works on SQL Server 2000: No (but this could be rewritten to work on SQL 2000)
  • Works on Standard Edition: Yes
  • Works on case-sensitive servers: Yes (see note above query)

Misc DMV queries

$
0
0
Current Revision posted to SQL Server by Lars Astrom on 7/19/2013 1:53:40 PM

See Also: [[wiki:Main Page|Main_Page]] - [[wiki:Transact SQL Code Library|Transact SQL Code Library]] - [[wiki:Current Activity|Current Activity]]

This query gives you a good idea of what is going on with your server right now. It takes a snapshot and does a diff a second later. This can be so much more useful than the Activity Monitor GUI, and it also works in SQL Azure.

You can adjust the wait time or sort as needed.

T-SQL Script

DECLARE @OpenQueries TABLE (cpu_time INT, logical_reads INT, session_id INT)
INSERT INTO @OpenQueries(cpu_time, logical_reads, session_id)
select r.cpu_time ,r.logical_reads, r.session_id
from sys.dm_exec_sessions as s inner join sys.dm_exec_requests as r 
on s.session_id =r.session_id and s.last_request_start_time=r.start_time
where is_user_process = 1
and s.session_id <> @@SPID
waitfor delay '00:00:01'
select substring(h.text, (r.statement_start_offset/2)+1 , ((case r.statement_end_offset when -1 then datalength(h.text)  else r.statement_end_offset end - r.statement_start_offset)/2) + 1) as text
, r.cpu_time-t.cpu_time as CPUDiff 
, r.logical_reads-t.logical_reads as ReadDiff
, r.wait_type
, r.wait_time
, r.last_wait_type
, r.wait_resource
, r.command
, r.database_id
, r.blocking_session_id
, r.granted_query_memory
, r.session_id
, r.reads
, r.writes, r.row_count, s.[host_name]
, s.program_name, s.login_name
from sys.dm_exec_sessions as s inner join sys.dm_exec_requests as r 
on s.session_id =r.session_id and s.last_request_start_time=r.start_time
left join @OpenQueries as t on t.session_id=s.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) h
where is_user_process = 1
and s.session_id <> @@SPID
order by 3 desc

Query Test Checklist

  • Works on SQL Server 2008: Yes
  • Works on SQL Server 2005: Yes
  • Works on SQL Server 2000: No
  • Works on Standard Edition: Yes
  • Works on case-sensitive servers: Yes

SQL Server Agent Job Query Samples

$
0
0
Current Revision posted to SQL Server by Lars Astrom on 7/19/2013 1:54:57 PM

Contents

Querying for Failed Jobs

SET  NOCOUNT ON
DECLARE @MaxLength   INT
SET @MaxLength   = 50
DECLARE @xp_results TABLE (

                      job_id uniqueidentifier NOT NULL,
                      last_run_date nvarchar (20) NOT NULL,
                      last_run_time nvarchar (20) NOT NULL,
                      next_run_date nvarchar (20) NOT NULL,
                      next_run_time nvarchar (20) NOT NULL,
                      next_run_schedule_id INT NOT NULL,
                      requested_to_run INT NOT NULL,
                      request_source INT NOT NULL,
                      request_source_id sysname
                            COLLATE database_default NULL,
                      running INT NOT NULL,
                      current_step INT NOT NULL,
                      current_retry_attempt INT NOT NULL,
                      job_state INT NOT NULL
                   )


DECLARE @job_owner   sysname
DECLARE @is_sysadmin   INT
SET @is_sysadmin   = isnull (is_srvrolemember ('sysadmin'), 0)
SET @job_owner   = suser_sname ()
INSERT INTO @xp_results

  EXECUTE sys.xp_sqlagent_enum_jobs @is_sysadmin, @job_owner


UPDATE @xp_results

  SET last_run_time    = right ('000000' + last_run_time, 6),
      next_run_time    = right ('000000' + next_run_time, 6)


SELECT j.name AS JobName,

      j.enabled AS Enabled,
      CASE x.running
         WHEN 1
         THEN
            'Running'
         ELSE
            CASE h.run_status
               WHEN 2 THEN 'Inactive'
               WHEN 4 THEN 'Inactive'
               ELSE 'Completed'
            END
      END
         AS CurrentStatus,
      coalesce (x.current_step, 0) AS CurrentStepNbr,
      CASE
         WHEN x.last_run_date > 0
         THEN
            convert (datetime,
                       substring (x.last_run_date, 1, 4)
                     + '-'
                     + substring (x.last_run_date, 5, 2)
                     + '-'
                     + substring (x.last_run_date, 7, 2)
                     + ' '
                     + substring (x.last_run_time, 1, 2)
                     + ':'
                     + substring (x.last_run_time, 3, 2)
                     + ':'
                     + substring (x.last_run_time, 5, 2)
                     + '.000',
                     121
            )
         ELSE
            NULL
      END
         AS LastRunTime,
      CASE h.run_status
         WHEN 0 THEN 'Fail'
         WHEN 1 THEN 'Success'
         WHEN 2 THEN 'Retry'
         WHEN 3 THEN 'Cancel'
         WHEN 4 THEN 'In progress'
      END
         AS LastRunOutcome,
      CASE
         WHEN h.run_duration > 0
         THEN
              (h.run_duration / 1000000) * (3600 * 24)
            + (h.run_duration / 10000 % 100) * 3600
            + (h.run_duration / 100 % 100) * 60
            + (h.run_duration % 100)
         ELSE
            NULL
      END
         AS LastRunDuration
 FROM          @xp_results x
            LEFT JOIN
               msdb.dbo.sysjobs j
            ON x.job_id = j.job_id
         LEFT OUTER JOIN
            msdb.dbo.syscategories c
         ON j.category_id = c.category_id
      LEFT OUTER JOIN
         msdb.dbo.sysjobhistory h
      ON     x.job_id = h.job_id
         AND x.last_run_date = h.run_date
         AND x.last_run_time = h.run_time
         AND h.step_id = 0

Query Test Checklist

  • Works on SQL Server 2008: Yes
  • Works on SQL Server 2005: Yes
  • Works on SQL Server 2000: No
  • Works on Standard Edition: Yes
  • Works on case-sensitive servers: Yes

Retrieve and Disable All Active Jobs

DECLARE @weekDay TABLE (

     mask      INT
   , maskValue VARCHAR(32)

);
INSERT INTO @weekDay
SELECT 1, 'Sunday'  UNION All
SELECT 2, 'Monday'  UNION All
SELECT 4, 'Tuesday'  UNION All
SELECT 8, 'Wednesday'  UNION All
SELECT 16, 'Thursday'  UNION All
SELECT 32, 'Friday'  UNION All
SELECT 64, 'Saturday';
WITH myCTE
AS(

   SELECT sched.name AS 'scheduleName'
       , sched.schedule_id
       , jobsched.job_id
       , CASE WHEN sched.freq_type = 1 THEN 'Once' 
           WHEN sched.freq_type = 4 
               And sched.freq_interval = 1 
                   THEN 'Daily'
           WHEN sched.freq_type = 4 
               THEN 'Every ' + CAST(sched.freq_interval AS VARCHAR(5)) + ' days'
           WHEN sched.freq_type = 8 THEN 
               REPLACE( REPLACE( REPLACE(( 
                   SELECT maskValue 
                   FROM @weekDay AS x 
                   WHERE sched.freq_interval & x.mask <> 0 
                   ORDER BY mask FOR XML Raw)
               , '"/><row maskValue="', ', '), '<row maskValue="', ), '"/>', ) 
               + CASE WHEN sched.freq_recurrence_factor <> 0 
                       And sched.freq_recurrence_factor = 1 
                           THEN '; weekly' 
                   WHEN sched.freq_recurrence_factor <> 0 THEN '; every ' 
               + CAST(sched.freq_recurrence_factor AS VARCHAR(10)) + ' weeks' END
           WHEN sched.freq_type = 16 THEN 'On day ' 
               + CAST(sched.freq_interval AS VARCHAR(10)) + ' of every '
               + CAST(sched.freq_recurrence_factor AS VARCHAR(10)) + ' months' 
           WHEN sched.freq_type = 32 THEN 
               CASE WHEN sched.freq_relative_interval = 1 THEN 'First'
                   WHEN sched.freq_relative_interval = 2 THEN 'Second'
                   WHEN sched.freq_relative_interval = 4 THEN 'Third'
                   WHEN sched.freq_relative_interval = 8 THEN 'Fourth'
                   WHEN sched.freq_relative_interval = 16 THEN 'Last'
               END + 
               CASE WHEN sched.freq_interval = 1 THEN ' Sunday'
                   WHEN sched.freq_interval = 2 THEN ' Monday'
                   WHEN sched.freq_interval = 3 THEN ' Tuesday'
                   WHEN sched.freq_interval = 4 THEN ' Wednesday'
                   WHEN sched.freq_interval = 5 THEN ' Thursday'
                   WHEN sched.freq_interval = 6 THEN ' Friday'
                   WHEN sched.freq_interval = 7 THEN ' Saturday'
                   WHEN sched.freq_interval = 8 THEN ' Day'
                   WHEN sched.freq_interval = 9 THEN ' Weekday'
                   WHEN sched.freq_interval = 10 THEN ' Weekend'
               END
               + CASE WHEN sched.freq_recurrence_factor <> 0 
                       And sched.freq_recurrence_factor = 1 THEN '; monthly'
                   WHEN sched.freq_recurrence_factor <> 0 THEN '; every ' 
               + CAST(sched.freq_recurrence_factor AS VARCHAR(10)) + ' months' END
           WHEN sched.freq_type = 64 THEN 'StartUp'
           WHEN sched.freq_type = 128 THEN 'Idle'
         END AS 'frequency'
       , IsNull('Every ' + CAST(sched.freq_subday_interval AS VARCHAR(10)) + 
           CASE WHEN sched.freq_subday_type = 2 THEN ' seconds'
               WHEN sched.freq_subday_type = 4 THEN ' minutes'
               WHEN sched.freq_subday_type = 8 THEN ' hours'
           END, 'Once') AS 'subFrequency'
       , REPLICATE('0', 6 - LEN(sched.active_start_time)) 
           + CAST(sched.active_start_time AS VARCHAR(6)) AS 'startTime'
       , REPLICATE('0', 6 - LEN(sched.active_end_time)) 
           + CAST(sched.active_end_time AS VARCHAR(6)) AS 'endTime'
       , REPLICATE('0', 6 - LEN(jobsched.next_run_time)) 
           + CAST(jobsched.next_run_time AS VARCHAR(6)) AS 'nextRunTime'
       , CAST(jobsched.next_run_date AS CHAR(8)) AS 'nextRunDate'
   FROM msdb.dbo.sysschedules AS sched
   Join msdb.dbo.sysjobschedules AS jobsched
       ON sched.schedule_id = jobsched.schedule_id
   WHERE sched.enabled = 1

)
SELECT job.name AS 'jobName'

   , sched.scheduleName
   , sched.frequency
   , sched.subFrequency
   , SUBSTRING(sched.startTime, 1, 2) + ':' 
       + SUBSTRING(sched.startTime, 3, 2) + ' - ' 
       + SUBSTRING(sched.endTime, 1, 2) + ':' 
       + SUBSTRING(sched.endTime, 3, 2) 
       AS 'scheduleTime' -- HH:MM
   , SUBSTRING(sched.nextRunDate, 1, 4) + '/' 
       + SUBSTRING(sched.nextRunDate, 5, 2) + '/' 
       + SUBSTRING(sched.nextRunDate, 7, 2) + ' ' 
       + SUBSTRING(sched.nextRunTime, 1, 2) + ':' 
       + SUBSTRING(sched.nextRunTime, 3, 2) AS 'nextRunDate'
     /* Note: the sysjobschedules table refreshes every 20 min, 
       so nextRunDate may be out of date */
   , 'Execute msdb.dbo.sp_update_job @job_id =  
       + CAST(job.job_id AS CHAR(36)) + , @enabled = 0;' AS 'disableScript'

FROM msdb.dbo.sysjobs AS job
Join myCTE AS sched

   ON job.job_id = sched.job_id

WHERE job.enabled = 1 -- do not display disabled jobs
ORDER BY nextRunDate;

Query Test Checklist

  • Works on SQL Server 2008: Yes
  • Works on SQL Server 2005: Yes
  • Works on SQL Server 2000: No
  • Works on Standard Edition: Yes
  • Works on case-sensitive servers: Yes

Order all Job Steps Alphabetically

use msdb
begin try
DECLARE @jobname varchar(128)
--SET @jobname = 'Backup Data'
--SET @jobname = 'Backup Differentials'
--SET @jobname = 'DBCCs'
--SET @jobname = 'Rebuild Indexes'
SET @jobname = 'Update Stats'
begin transaction
	CREATE TABLE #reorder_jobsteps
	(newstepid int identity(1,1),
	jobname varchar(128),
	oldstepid int,
	stepname varchar(128)
	)
	insert #reorder_jobsteps (jobname,oldstepid,stepname)
		select j.name,step_id,step_name from sysjobsteps js inner join sysjobs j on js.job_id=j.job_id
			where j.name = @jobname
			order by step_name
	select * from #reorder_jobsteps
	update js SET step_id = newstepid 
		FROM sysjobsteps js inner join sysjobs j ON js.job_id = j.job_id
		inner join #reorder_jobsteps r ON js.step_name = r.stepname AND j.name = r.jobname
		where j.name = r.jobname and js.step_name = r.stepname
	select j.name,step_id,step_name from sysjobsteps js inner join sysjobs j on js.job_id=j.job_id
		where j.name = @jobname
		order by step_name
	declare @maxstep int
	SELECT @maxstep = max(newstepid) FROM #reorder_jobsteps
	drop table #reorder_jobsteps
	update js SET on_success_action = 3
		from sysjobsteps js INNER JOIN sysjobs j ON js.job_id = j.job_id
		WHERE j.name = @jobname
	update js SET on_success_action = 1
		from sysjobsteps js INNER JOIN sysjobs j ON js.job_id = j.job_id
		WHERE j.name = @jobname AND step_id = @maxstep
	update sysjobs SET start_step_id = 1
		WHERE name = @jobname
	commit transaction
end try
begin catch
	rollback transaction
end catch

Query Test Checklist

  • Works on SQL Server 2008: Yes
  • Works on SQL Server 2005: Yes
  • Works on SQL Server 2000: No
  • Works on Standard Edition: Yes
  • Works on case-sensitive servers: Yes

SQL Server Topics

$
0
0
Current Revision posted to SQL Server by Steve Hilker on 8/20/2013 5:33:27 PM

  • [[wiki:Architecture & Configuration|Architecture & Configuration]]
  • [[wiki:Business Intelligence|Business Intelligence]] - which is composed of these three subsections:
    • [[wiki:SQL Server Analysis Services Section|SQL Server Analysis Services Section]]
    • [[wiki:SQL Server Integration Services Section|SQL Server Integration Services Section]] - also includes DTS
    • [[wiki:SQL Server Reporting Services Section|SQL Server Reporting Services Section]]
  • [[wiki:Database Administration|Database Administration]]
  • [[wiki:Monitoring|Monitoring SQL Servers]]
  • [[wiki:Performance Tuning|Performance Tuning]]
  • [[wiki:SQL Server Book Reviews|SQL Server Book Reviews]]
  • [[wiki:Links|SQL Server Links]]
  • [[wiki:SQL Server Tutorials|SQL Server Tutorial Videos and Podcasts]]
  • [[wiki:Transact SQL Coding Techniques|Transact SQL Coding Techniques]]
  • [[wiki:T-SQL Coding and Naming Standards|Transact SQL Coding and Naming Standards]]
  • [[wiki:Transact SQL Code Library|Transact SQL Code Library (Examples)]]

Other Pages

$
0
0
Current Revision posted to SQL Server by Steve Hilker on 8/20/2013 5:34:07 PM

This section consists of miscellaneous submitted SQL Server articles that have not yet been merged into the SQL Server wiki.


Performance Monitor

$
0
0
Current Revision posted to SQL Server by Steve Hilker on 11/4/2013 1:01:39 PM

Contents

SQL Server Perfmon Monitoring: Overview

Database administrators need to know each SQL Server's weakest link so we know where to focus their hardware budgets and time. On any given server, we need to know what the slowest component is, and where it'll pay off to invest hours and dollars. This is performance tuning, and the first place to start is by using Performance Monitor.

Performance Monitor, or Perfmon, measures performance statistics on a regular interval, and saves those stats in a file. The database administrator picks the time interval, file format, and which statistics are monitored. After the stats are gathered over a period of time (hours or days), we can do analysis by opening the results in Excel and setting up some basic formulas.

Perfmon isn't just for SQL Server tuning: system administrators use it to monitor performance on Windows itself, Exchange, file & print servers, and anything else that can run into bottlenecks. As a result, it's easy to find Perfmon information online, but it's not always specific to SQL Server. Since every application has its own set of statistics, it helps to get SQL-related tips.

For more about why database administrators use Perfmon, watch this five-minute video by Brent Ozar explaining the basics:

For more tutorial videos like this, check out the Videos page.

Setting Up Perfmon for SQL Server Tuning

On your workstation, go into Control Panel, Administrative Tools, Performance. The first thing that comes up is a 1990's-looking line chart with a few basic performance stats on your workstation itself. Interesting, but not what we're after.

On the left side, expand Performance Logs and Alerts, and click on Counter Logs. Counter Logs let us pick a set of performance counters and log them to a file periodically. One counter log is listed by default, but we're going to add a new one. Right-click on Counter Logs and click New Log Settings. Name it with the name of your database server, because each server should have its own log settings. We could theoretically build a single counter log for all of our database servers, but then anytime we want to run the counter log against one of our servers to test its performance, it will log data for ALL servers, and that's not usually how we want to do performance tuning.

After typing in a name, we can start setting up the counters we want to log. Click the Add Counters button, and change the computer name to point to the SQL Server name instead of your workstation's name. (If you have multiple SQL Server instances on the machine, don't worry about it, that doesn't apply here.) After typing in the server name, hit Tab, and the workstation will pause for a few moments. It's gathering the list of performance objects available on that server. Each server will have different lists of performance objects depending on what software is installed on that server: for example, SQL Server 2005 offers a different set of counters than SQL Server 2000.

In the Performance object dropdown, choose the "Memory" object. The list of counters will change. Select the "Pages/sec" counter, and click the Add button. It will seem like nothing happened, but try clicking the Add button again. You'll get an error saying that the counter was already added. It's not exactly an elegant user interface, but it works. Technically. Now scroll up to the "Available MBytes" counter, highlight it, and click Add. Those are the only two memory counters we're going to monitor for now.

In the Performance object dropdown, choose the "Processor" object, and in the counters list, highlight the "% Processor Time" counter. Notice that in the right hand window, we now have more instances to choose from. We can track the % Processor Time statistic for each individual processor, or for all of them combined (_Total). Personally, I like to highlight each individual processor, and then click Add. I don't find the _Total statistic useful because it's simply an added number combined from all of the individual processors. On a 4-CPU box (single cores, no hyperthreading), that means our _Total statistic can be from 0 to 400. However, 100 can mean two different things: it could mean that each processor is running 25% utilization, or it could mean that one processor is pegged at 100% while the rest are twiddling their thumbs waiting for work. It could also mean any other number of combinations, like two processors at 50%. Therefore, the _Total number usually gives me more questions than answers, so I don't bother logging it. Highlight all of the processor instances except _Total, and click the Add button.

In the Performance object dropdown, choose Physical Disk, and choose the "% Disk Time" counter. Notice that again on the right side window, we get multiple instances; this time, we get one per physical disk. In performance terms, physical disk means one disk shown in Computer Management's Disk Management tool. One physical disk may have multiple partitions, each with its own drive letter, but for performance tuning, we want to know how hard that one physical disk is working.

This one "physical disk" may have a bunch of actual physical drives, like in RAID systems. However, Windows isn't quite smart enough to know exactly how many drives are in the RAID array, so the term "physical disk" is a little misleading here.

Highlight all of the physical disks in the instance list (again, leave off the _Total instance) and click the Add button. Then, in the counter list, choose the "Avg. Disk Queue Length" counter and add it too.

Performance Monitor Counters for SQL Server Analysis

Now that you've got the hang of adding counters, here's the full list we need to add, including the ones mentioned above:

  • These are listed OBJECT first, then COUNTER
  • Memory - Available MBytes
  • Paging File - % Usage
  • Physical Disk - % Disk Time
  • Physical Disk - Avg. Disk Queue Length
  • Physical Disk - Avg. Disk sec/Read
  • Physical Disk - Avg. Disk sec/Write
  • Physical Disk - Disk Reads/sec
  • Physical Disk - Disk Writes/sec
  • Processor - % Processor Time
  • SQLServer:Buffer Manager - Buffer cache hit ratio
  • SQLServer:Buffer Manager - Page life expectancy
  • SQLServer:General Statistics - User Connections
  • SQLServer:Memory Manager - Memory Grants Pending
  • System - Processor Queue Length

For more about specific Perfmon counters, check out these articles:

After adding those, click the Close button, and we're back to the counter log setup window. Under "Sample data every", the default should be 15 seconds, and that's fine. In the "Run As" entry, type in your domain username in the form domainnameusername, and click the Set Password button to save your password. This lets the Perfmon service gather statistics using your domain permissions - otherwise, it tries to use its own credentials, and they probably won't work on the remote server.

Click on the Log Files tab, and change the log file type to Text File (Comma delimited). This lets us import it into Excel easier. Click on the Configure button, and set the file path. I save mine in a file share called PerformanceLogs so that I can access it remotely via a mapped drive, and so that I can share it with other users who want to know how their server is performing. Click OK, and click OK again, and you'll be back at the main Performance screen listing the counter logs.

If all went well, your counter log is now running. To make sure, right-click on your new counter log's name, and the Start option should be grayed out. If it's not, most likely there was a permissions problem with the username & password you used. Click Properties, and try setting the username & password again.

Let Perfmon run for a day or two to gather a good baseline of the server's activity. It's not that invasive on the SQL Server being monitored, and the in-depth results will pay off. The more data we have, the better job we can do on analyzing the Perfmon results.

Turning Perfmon Logs Into Pretty Excel Spreadsheets

After Perfmon has run for a day or two, go back in and right-click on the counter log and click Stop. That will cease monitoring of the database server.

Open the results CSV in Excel. It's going to look ugly at first:

This is the data from Perfmon. Each column represents one of the metrics, and each row represents one time period. It's hard to see that with the way it's currently formatted, but we'll solve that. Time to put some lipstick on this pig. We're going to:

  • Get rid of the half-empty row #2 and cell A1
  • Format the dates
  • Format the numbers
  • Clean up the headers
  • Add formulas across the top (my Secret Sauce part)

Excel 2007 pros can figure out how to do this, but for the folks who don't spend too much time in spreadsheets, I'll explain how:

Getting Rid of the Half-Empty Row and Cell A

Row #2 in this screenshot only has numbers in the first few columns. That's typical for Perfmon - when it first starts monitoring a server, it takes it a round of checks before it'll gather all of the data. Highlight row 2 and hit the Delete key on your keyboard. (I figured we'd start easy.)

Then delete the contents of cell A1, which we don't need.

Format the Dates in Column 1

Click on cell A2 and look at the formula bar, and you'll see that it's a date - it's just that Excel picks the wrong format to display it. Highlight all of column A (by clicking on the "A" button at the top of the column). Right-click on that A button and click Format Cells. Pick a Date format that includes both the date and the time, and click OK.

At that point, the column will probably show all "#######" entries, which just means it's not wide-enough. Double-click on the line between the A and B columns, and Excel will autosize the column.

Format the Numbers

In our spreadsheet, some of the numbers have tons of stuff after the decimal place and it's hard to read. Highlight all of the columns except A (our dates), and right-click and Format Cells. Choose the Number format, zero decimals, and check the box for Use 1000 Separator.

Some of our numbers will have valid data less than zero, but we'll fix that later. Right now we're just getting the basics cleaned up.

At this point, your spreadsheet should look like this:

Now let's solve that mystery row of headers.

Cleaning Up the Headers

In row #1, notice how all of the cells in my screenshot start with \MYSERV. That's because the server is called MYSERVERNAME. (Well, not really, but I faked it for this demo.) Click on one of those cells, and you'll see the full text that Perfmon saves in the header, like "\MYSERVERNAMEMemoryAvailable MBytes".

Do a find & replace by hitting Control-H. In the "Find What" box type your server name with two backslashes, like \MYSERVERNAME. In the "Replace with" box, erase everything. We want to just delete everywhere that says \MYSERVERNAME. Click Replace All, and Excel should tell you how many replacements it made.

Now do the same for these strings, but be careful to note which ones have spaces:

  • Memory
  • Paging File
  • PhysicalDisk
  • Processor
  • SQLServer:Buffer Manager
  • SQLServer:General Statistics
  • SQLServer:Memory Manager
  • System

Now you'll be able to tell a little more about what's in each header, but to make it better, change the font size to 8 for that header row. Then highlight all of the columns and make them wider - not terribly wide, but just wide enough that you can see most of the headers for easier analysis. It'll end up looking like this:

Getting better. Before the next step, go ahead and save the spreadsheet in Excel format, because the calculations will be slow.

Add Formulas Across the Top

Here comes the secret sauce: we want formulas across the top to quickly summarize our findings. It'll be easier to understand by looking at the final desired result first:

In this particular example, don't be fooled by the zeroes in columns C through E - that's because this server didn't actually have any activity for those metrics.

Start by right-clicking on the Row 1 button at the far left of the screen and click Insert, and repeat that process seven times so that we've got seven empty rows at the top.

Then type in the labels in cells A2-A6 to match my screen shot.

In the B column, put in the formulas. In my typed examples below, I assume that your data goes from row 9 to row 100, but you'll want to change that 100 number to wherever your last data row is.

  • B2 (Average) will be =AVERAGE(B9:B100)
  • B3 (Median) will be =MEDIAN(B9:B100)
  • B4 (Min) will be =MIN(B9:B100)
  • B5 (Max) will be =MAX(B9:B100)
  • B6 (Std Deviation) will be =STDEV(B9:B100)

Finally, the icing on the cake: hit Control-Home, then move your cursor to cell B9, which should be your first cell with data. Hit Alt-W-F-Enter, which should Freeze Panes. That way we can move around our spreadsheet while we still see the dates on the left and the formulas & headers across the top.

Now, we've got a gorgeous spreadsheet that's easier to roam around and analyze.

Analyzing the Performance Monitor Results to Find Bottlenecks

Now for the detective work! There are a lot of smart people out there who have some great ways of interpreting Perfmon results. My favorite is the Microsoft SQL Server Customer Advisory Team (SQLCAT), who published two fantastic blog posts that sum up what counters to look at, and what they mean:

We'll also talk about some basic steps in the order we recommend doing them:

Look for Obvious CPU Bottlenecks

First, look at the Processor Queue Length for CPU pressure. If this number is averaging 1 or higher (except during the SQL Server's full backup window if you're using backup compression), this means things are waiting on CPUs to become available.

I'm suspicious when this number is over 1, because it often means that people have installed other software on the SQL Server such as applications or web sites. That's a problem. If you get pushback from management saying that they don't want to buy new servers, point out that two CPUs of SQL Server Enterprise licensing cost around $50-60k - which would pay for a separate server for the web app. If you can eliminate applications from the SQL Server, then you don't have to use as much CPU power, and less CPUs mean less licensing costs.

There are more in-depth Perfmon metrics that you can add to your capture if you see the Processor Queue Length showing up, but for junior DBAs, the first thing I would recommend is simply remote desktop into the SQL Server. Right-click on the taskbar, click Task Manager, and click on the Processes tab. Check the box that shows processes for all users, and then click on the CPU column to sort the CPU percentage from high to low. Sit and watch it for a minute or two. Which processes are using CPU power? If it's SQLServer, then we need to do more research, but there's a good chance it's another application, and we need to get that app off this server.

Generally speaking, enabling hyperthreading on a SQL Server is not going to fix that kind of a problem. Again, all of this is generally speaking, not specific to your environment.

Look for Obvious Memory Problems

Look at the % Usage metric, which monitors how much of the page file Windows is using. Generally speaking, you don't want to see a SQL Server swapping memory out to disk. If this number is averaging 1% or more, then this server would benefit from more memory or setting SQL to use less memory.

1% doesn't mean that money should be spent on more memory right away: in cost-sensitive shops, every server hits the page file sooner or later. It just points to a possible issue, and keep an eye on it.

On the Memory - Available MBytes statistic, look for fluctuations of a couple hundred megabytes or more. If that's happening, then either the SQL Server's memory is being adjusted dynamically (probably a bad idea for performance) or users are actively logging into the SQL Server via remote desktop and running software. Correlate these fluctuations with disk activity: when available memory drops, is disk activity also increasing? Is this disk activity affecting the page file drive? If so, use this as a demonstration to people using remote desktop - show them that this is why people shouldn't remote desktop into database servers.

If the Memory - Available MBytes dips below 100mb, that's an indication that the operating system may be getting starved for memory. Windows may be paging out your application to disk in order to keep some breathing room free for the OS. Make sure you have SQL Server's service account set up with permissions to lock pages in memory.

Look at Disk Metrics Last

The reason we don't look at disk performance metrics first is because memory problems can trigger disk problems. If a SQL Server doesn't have enough memory, or if the SQL Server account doesn't have the necessary permissions to lock pages in memory, then disk activity may be artificially high on the page file drive.

As we examine the disk numbers, make a mental note of which drive has the page file - and there may be multiple page files as well. Also, find out if one physical drive array is shared by multiple drive letters. This is especially important for servers that boot from SAN: the boot drive may contain the page file, and that boot drive may be on a shared set of spindles with several drive letters. Heavy page file activity will slow down access to all of the affected drive letters in Windows.

Another caveat: mount points. If the shop uses mount points, a drive letter may be broken up into several sets of physical drive arrays. If you don't know what a mount point is, then you're probably not using them, and you can ignore that advice.

Mining the Performance Data

The Microsoft SQL Server Data Mining team has created a tool to help do data mining in Excel without any data mining experience or knowledge. For more information, check out this link:

Tags: sql server

Move SQL Server 2008 Cluster to New Subnet and IP Address

$
0
0
Current Revision posted to SQL Server by Steve Hilker on 12/12/2013 2:03:31 PM

See Also: [[wiki:Main Page|Main_Page]] - [[wiki:Database Administration|Database Administration]] - [[wiki:Clustering|Clustering]] - [[wiki:Changing IP Addresses on Clusters|Changing IP Addresses on Clusters]]

Move a SQL Server 2008 Cluster to a New Subnet and IP Address Introduction

The goal and purpose of this article will be to provide step by step instructions of how to move a SQL Server 2008 / Windows Server 2008 cluster to a new subnet and IP address on your network. There are several reasons you may find yourself needing to perform this type of change for your SQL Server and those are listed below.

  • Your company is growing and you need to move the SQL Server 2008 cluster from one data center to another, which are on different subnets.
  • You need to move your SQL Server 2008 cluster behind a newly deployed firewall for increased security, which requires a subnet and IP address modification.
  • The network team has made a new subnet for all the company's SQL Servers to reside on and you must comply with their IP address schemes; thus a change of subnet and IP addresses is necessary.
  • The subnet you are on is full and your SQL Server 2008 cluster is chosen as the best candidate to move to a different subnet on the network to free up IP address space.
<this article needs to be completed>
Tags: sql server

SAN Performance Tuning with SQLIO

$
0
0
Current Revision posted to SQL Server by Steve Hilker on 3/24/2014 6:20:32 PM

SQLIO is a free utility from Microsoft that measures storage IO performance. The name "SQLIO" is horribly misleading, because it doesn't really have anything to do with SQL Server.

Contents

SQLIO Video Tutorial

In this ten-minute video, Brent Ozar explains how to get started with SQLIO, how to create a batch file to test your SAN, and how to analyze the results.

http://www.toadworld.com/platforms/sql-server/m/mediagallery/1231.aspx

For more video tutorials like this, check out the Media page.

Downloading and Configuring SQLIO

[Download SQLIO from Microsoft]

Notice that I said SQLIO, not SQLIOSIM. Experienced database administrators will often direct you to SQLIOSIM because it's easier to use and mimics SQL Server's disk activity patterns. Here's the catch: it won't necessarily test your SAN to its maximum potential. Your SAN team may indicate that if your SQLIOSIM results aren't fast enough, it's a SQL-related problem, not a SAN-related problem. They may use testing utilities from vendors that mimic results closer to what SQLIO will give you. We want to push the SAN's pedal to the metal and find out how fast it'll go in any situation.

After installing SQLIO, edit the param.txt file and change these two parameters:

  • First parameter - the physical location of the testing file. Change the drive letter to point to the SAN drive you want to test, like T:\testfile.dat.
  • Last parameter - the size of the testing file in megabytes. Increase this to 20480 or larger. Ideally, you want it to be larger than your SAN's cache, because your real databases will be larger than the SAN's cache.

After saving param.txt, run this at the command line in the same directory where SQLIO is installed in order to create the test file:

sqlio -kW -s10 -fsequential -o8 -b8 -LS -Fparam.txt timeout /T 10

When it finishes, your test file is created, and it's time to run our real tests.

Testing Your SAN Performance

Instead of picking and choosing individual parameters to use, I like to take the shotgun approach: try every possible combination of random versus sequential, low and high numbers of threads, read versus write, etc. The below batch file will take all of the possibilities and run 'em all. Copy/paste this into a text file called SANTest.bat:

sqlio -kW -t2 -s120 -dM -o1 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t2 -s120 -dM -o2 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t2 -s120 -dM -o4 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t2 -s120 -dM -o8 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t2 -s120 -dM -o16 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t2 -s120 -dM -o32 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t2 -s120 -dM -o64 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t2 -s120 -dM -o128 -frandom -b64 -BH -LS Testfile.dat

sqlio -kW -t4 -s120 -dM -o1 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t4 -s120 -dM -o2 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t4 -s120 -dM -o4 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t4 -s120 -dM -o8 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t4 -s120 -dM -o16 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t4 -s120 -dM -o32 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t4 -s120 -dM -o64 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t4 -s120 -dM -o128 -frandom -b64 -BH -LS Testfile.dat

sqlio -kW -t8 -s120 -dM -o1 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t8 -s120 -dM -o2 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t8 -s120 -dM -o4 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t8 -s120 -dM -o8 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t8 -s120 -dM -o16 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t8 -s120 -dM -o32 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t8 -s120 -dM -o64 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t8 -s120 -dM -o128 -frandom -b64 -BH -LS Testfile.dat

sqlio -kW -t16 -s120 -dM -o1 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t16 -s120 -dM -o2 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t16 -s120 -dM -o4 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t16 -s120 -dM -o8 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t16 -s120 -dM -o16 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t16 -s120 -dM -o32 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t16 -s120 -dM -o64 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t16 -s120 -dM -o128 -frandom -b64 -BH -LS Testfile.dat

sqlio -kW -t32 -s120 -dM -o1 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t32 -s120 -dM -o2 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t32 -s120 -dM -o4 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t32 -s120 -dM -o8 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t32 -s120 -dM -o16 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t32 -s120 -dM -o32 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t32 -s120 -dM -o64 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t32 -s120 -dM -o128 -frandom -b64 -BH -LS Testfile.dat

sqlio -kW -t64 -s120 -dM -o1 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t64 -s120 -dM -o2 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t64 -s120 -dM -o4 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t64 -s120 -dM -o8 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t64 -s120 -dM -o16 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t64 -s120 -dM -o32 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t64 -s120 -dM -o64 -frandom -b64 -BH -LS Testfile.dat
sqlio -kW -t64 -s120 -dM -o128 -frandom -b64 -BH -LS Testfile.dat

sqlio -kR -t2 -s120 -dM -o1 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t2 -s120 -dM -o2 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t2 -s120 -dM -o4 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t2 -s120 -dM -o8 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t2 -s120 -dM -o16 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t2 -s120 -dM -o32 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t2 -s120 -dM -o64 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t2 -s120 -dM -o128 -frandom -b64 -BH -LS Testfile.dat

sqlio -kR -t4 -s120 -dM -o1 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t4 -s120 -dM -o2 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t4 -s120 -dM -o4 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t4 -s120 -dM -o8 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t4 -s120 -dM -o16 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t4 -s120 -dM -o32 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t4 -s120 -dM -o64 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t4 -s120 -dM -o128 -frandom -b64 -BH -LS Testfile.dat

sqlio -kR -t8 -s120 -dM -o1 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t8 -s120 -dM -o2 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t8 -s120 -dM -o4 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t8 -s120 -dM -o8 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t8 -s120 -dM -o16 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t8 -s120 -dM -o32 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t8 -s120 -dM -o64 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t8 -s120 -dM -o128 -frandom -b64 -BH -LS Testfile.dat

sqlio -kR -t16 -s120 -dM -o1 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t16 -s120 -dM -o2 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t16 -s120 -dM -o4 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t16 -s120 -dM -o8 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t16 -s120 -dM -o16 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t16 -s120 -dM -o32 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t16 -s120 -dM -o64 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t16 -s120 -dM -o128 -frandom -b64 -BH -LS Testfile.dat

sqlio -kR -t32 -s120 -dM -o1 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t32 -s120 -dM -o2 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t32 -s120 -dM -o4 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t32 -s120 -dM -o8 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t32 -s120 -dM -o16 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t32 -s120 -dM -o32 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t32 -s120 -dM -o64 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t32 -s120 -dM -o128 -frandom -b64 -BH -LS Testfile.dat

sqlio -kR -t64 -s120 -dM -o1 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t64 -s120 -dM -o2 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t64 -s120 -dM -o4 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t64 -s120 -dM -o8 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t64 -s120 -dM -o16 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t64 -s120 -dM -o32 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t64 -s120 -dM -o64 -frandom -b64 -BH -LS Testfile.dat
sqlio -kR -t64 -s120 -dM -o128 -frandom -b64 -BH -LS Testfile.dat

sqlio -kW -t2 -s120 -dM -o1 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t2 -s120 -dM -o2 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t2 -s120 -dM -o4 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t2 -s120 -dM -o8 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t2 -s120 -dM -o16 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t2 -s120 -dM -o32 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t2 -s120 -dM -o64 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t2 -s120 -dM -o128 -fsequential -b64 -BH -LS Testfile.dat

sqlio -kW -t4 -s120 -dM -o1 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t4 -s120 -dM -o2 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t4 -s120 -dM -o4 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t4 -s120 -dM -o8 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t4 -s120 -dM -o16 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t4 -s120 -dM -o32 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t4 -s120 -dM -o64 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t4 -s120 -dM -o128 -fsequential -b64 -BH -LS Testfile.dat

sqlio -kW -t8 -s120 -dM -o1 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t8 -s120 -dM -o2 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t8 -s120 -dM -o4 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t8 -s120 -dM -o8 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t8 -s120 -dM -o16 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t8 -s120 -dM -o32 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t8 -s120 -dM -o64 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t8 -s120 -dM -o128 -fsequential -b64 -BH -LS Testfile.dat

sqlio -kW -t16 -s120 -dM -o1 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t16 -s120 -dM -o2 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t16 -s120 -dM -o4 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t16 -s120 -dM -o8 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t16 -s120 -dM -o16 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t16 -s120 -dM -o32 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t16 -s120 -dM -o64 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t16 -s120 -dM -o128 -fsequential -b64 -BH -LS Testfile.dat

sqlio -kW -t32 -s120 -dM -o1 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t32 -s120 -dM -o2 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t32 -s120 -dM -o4 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t32 -s120 -dM -o8 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t32 -s120 -dM -o16 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t32 -s120 -dM -o32 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t32 -s120 -dM -o64 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t32 -s120 -dM -o128 -fsequential -b64 -BH -LS Testfile.dat

sqlio -kW -t64 -s120 -dM -o1 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t64 -s120 -dM -o2 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t64 -s120 -dM -o4 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t64 -s120 -dM -o8 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t64 -s120 -dM -o16 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t64 -s120 -dM -o32 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t64 -s120 -dM -o64 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kW -t64 -s120 -dM -o128 -fsequential -b64 -BH -LS Testfile.dat

sqlio -kR -t2 -s120 -dM -o1 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t2 -s120 -dM -o2 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t2 -s120 -dM -o4 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t2 -s120 -dM -o8 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t2 -s120 -dM -o16 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t2 -s120 -dM -o32 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t2 -s120 -dM -o64 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t2 -s120 -dM -o128 -fsequential -b64 -BH -LS Testfile.dat

sqlio -kR -t4 -s120 -dM -o1 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t4 -s120 -dM -o2 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t4 -s120 -dM -o4 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t4 -s120 -dM -o8 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t4 -s120 -dM -o16 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t4 -s120 -dM -o32 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t4 -s120 -dM -o64 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t4 -s120 -dM -o128 -fsequential -b64 -BH -LS Testfile.dat

sqlio -kR -t8 -s120 -dM -o1 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t8 -s120 -dM -o2 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t8 -s120 -dM -o4 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t8 -s120 -dM -o8 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t8 -s120 -dM -o16 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t8 -s120 -dM -o32 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t8 -s120 -dM -o64 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t8 -s120 -dM -o128 -fsequential -b64 -BH -LS Testfile.dat

sqlio -kR -t16 -s120 -dM -o1 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t16 -s120 -dM -o2 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t16 -s120 -dM -o4 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t16 -s120 -dM -o8 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t16 -s120 -dM -o16 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t16 -s120 -dM -o32 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t16 -s120 -dM -o64 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t16 -s120 -dM -o128 -fsequential -b64 -BH -LS Testfile.dat

sqlio -kR -t32 -s120 -dM -o1 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t32 -s120 -dM -o2 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t32 -s120 -dM -o4 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t32 -s120 -dM -o8 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t32 -s120 -dM -o16 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t32 -s120 -dM -o32 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t32 -s120 -dM -o64 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t32 -s120 -dM -o128 -fsequential -b64 -BH -LS Testfile.dat

sqlio -kR -t64 -s120 -dM -o1 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t64 -s120 -dM -o2 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t64 -s120 -dM -o4 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t64 -s120 -dM -o8 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t64 -s120 -dM -o16 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t64 -s120 -dM -o32 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t64 -s120 -dM -o64 -fsequential -b64 -BH -LS Testfile.dat
sqlio -kR -t64 -s120 -dM -o128 -fsequential -b64 -BH -LS Testfile.dat

Whew! And that's just one pass - if you want to do multiple passes of the same tests for consistency's sake, like to eliminate the chance that other servers are running on the same SAN and affecting your performance results, you would want to paste that same set of 200+ lines multiple times into your batch file.

Let's take the first line of the batch file and analyze what it's doing:

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

The most important parameters are:

  • -kW means writes (as opposed to reads)
  • -t2 means two threads
  • -s120 means test for 120 seconds
  • -dM means drive letter M
  • -o1 means one outstanding request (not piling up requests)
  • -frandom means random access (as opposed to sequential)
  • -b64 means 64kb IOs

Do a find & replace in your text file and replace -dM with the drive letter of your choice. If you're testing on your S drive, for example, you would replace -dM with -dS.

Then go to the command prompt in the same directory as SQLIO is installed and type:

SANTEST.BAT > RESULTS.TXT

This will run our newly created batch file and dump the results into a text file. This will take a long time, like six hours or more, and it will be hammering your SAN. Don't run this on a production server, and don't even run it on the same SAN as a production server when the production server is under load because it may time out. I've had instances where this batch file has actually caused a SAN to restart itself, so use this with caution - preferably in a test lab or before your SAN goes live.

Hours later, when it finishes, you'll have a RESULTS.TXT file with lots of juicy metrics about your storage performance.

Importing SQLIO Results into SQL Server

Those text file results are cryptic - time to bring them into our favorite data analysis platform, Microsoft Access. Wait, I'm kidding, put the axe down - we'll import them into SQL Server.

Script to Create the Tables and and ETL Stored Procedure

Before we start, create a database that you'll use for SQLIO data storage or designate an existing utility database that you'll use. This script requires SQL Server 2005 or newer, since it uses the varchar(max) field.

In that database, run the below script to create the tables for results storage:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[SQLIO_Import](
	[RowID] [int] IDENTITY(1,1) NOT NULL,
	[ParameterRowID] [int] NULL,
	[ResultText] [varchar](max) NULL,
 CONSTRAINT [PK_SQLIO_Import] PRIMARY KEY CLUSTERED 
(
	[RowID] ASC
))
GO
CREATE TABLE [dbo].[SQLIO_TestPass](
	[TestPassID] [int] IDENTITY(1,1) NOT NULL,
	[ServerName] [nvarchar](50) NOT NULL,
	[DriveQty] [int] NOT NULL,
	[DriveRPM] [int] NOT NULL,
	[DriveRaidLevel] [nvarchar](10) NOT NULL,
	[TestDate] [datetime] NOT NULL,
	[SANmodel] [nvarchar](50) NOT NULL,
	[SANfirmware] [nvarchar](50) NULL,
	[PartitionOffset] [int] NULL,
	[Filesystem] [nvarchar](50) NULL,
	[FSClusterSizeBytes] [int] NULL,
	[SQLIO_Version] [nvarchar](20) NULL,
	[Threads] [int] NULL,
	[ReadOrWrite] [nchar](1) NULL,
	[DurationSeconds] [int] NULL,
	[SectorSizeKB] [int] NULL,
	[IOpattern] [nvarchar](50) NULL,
	[IOsOutstanding] [int] NULL,
	[Buffering] [nvarchar](50) NULL,
	[FileSizeMB] [int] NULL,
	[IOs_Sec] [decimal](18, 0) NULL,
	[MBs_Sec] [decimal](18, 0) NULL,
	[LatencyMS_Min] [int] NULL,
	[LatencyMS_Avg] [int] NULL,
	[LatencyMS_Max] [int] NULL,
 CONSTRAINT [PK_SQLIO_TestPass] PRIMARY KEY CLUSTERED 
(
	[TestPassID] ASC
))
GO

CREATE PROCEDURE [dbo].[USP_Import_SQLIO_TestPass]
                @ServerName         NVARCHAR(50),
                @DriveQty           INT,
                @DriveRPM           INT,
                @DriveRaidLevel     NVARCHAR(10),
                @TestDate           DATETIME,
                @SANmodel           NVARCHAR(50),
                @SANfirmware        NVARCHAR(50),
                @PartitionOffset    INT,
                @Filesystem         NVARCHAR(50),
                @FSClusterSizeBytes INT
AS
  SET nocount off
  
  IF @TestDate IS NULL
    SET @TestDate = Getdate()

  /* Add a blank record to the end so the last test result is captured */
  INSERT INTO dbo.SQLIO_Import
    (ParameterRowID, 
     ResultText)
  VALUES
    (0,
     '');
                               
  /* Update the ParameterRowID field for easier querying */
  UPDATE dbo.sqlio_import
  SET    parameterrowid = (SELECT   TOP 1 rowid
                           FROM     dbo.sqlio_import parm
                           WHERE    parm.resulttext LIKE '%\%'
                                    AND parm.rowid <= upd.rowid
                           ORDER BY rowid DESC)
  FROM   dbo.sqlio_import upd
         
  /* Add new SQLIO_TestPass records from SQLIO_Import */
  INSERT INTO dbo.sqlio_testpass
             (servername,
              driveqty,
              driverpm,
              driveraidlevel,
              testdate,
              sanmodel,
              sanfirmware,
              partitionoffset,
              filesystem,
              fsclustersizebytes,
              sqlio_version,
              threads,
              readorwrite,
              durationseconds,
              sectorsizekb,
              iopattern,
              iosoutstanding,
              buffering,
              filesizemb,
              ios_sec,
              mbs_sec,
              latencyms_min,
              latencyms_avg,
              latencyms_max)
  SELECT   @ServerName,
           @DriveQty,
           @DriveRPM,
           @DriveRaidLevel,
           @TestDate,
           @SANmodel,
           @SANfirmware,
           @PartitionOffset,
           @Filesystem,
           @FSClusterSizeBytes,
           (SELECT REPLACE(resulttext,'sqlio ','')
            FROM   dbo.sqlio_import impsqlio_version
            WHERE  imp.rowid + 1 = impsqlio_version.rowid) AS sqlio_version,
           (SELECT LEFT(resulttext,(Charindex(' threads',resulttext)))
            FROM   dbo.sqlio_import impthreads
            WHERE  imp.rowid + 3 = impthreads.rowid) AS threads,
           (SELECT Upper(Substring(resulttext,(Charindex('threads ',resulttext)) + 8,
                                   1))
            FROM   dbo.sqlio_import impreadorwrite
            WHERE  imp.rowid + 3 = impreadorwrite.rowid) AS readorwrite,
           (SELECT Substring(resulttext,(Charindex(' for',resulttext)) + 4,
                             (Charindex(' secs ',resulttext)) - (Charindex(' for',resulttext)) - 4)
            FROM   dbo.sqlio_import impdurationseconds
            WHERE  imp.rowid + 3 = impdurationseconds.rowid) AS durationseconds,
           (SELECT Substring(resulttext,7,(Charindex('KB',resulttext)) - 7)
            FROM   dbo.sqlio_import impsectorsizekb
            WHERE  imp.rowid + 4 = impsectorsizekb.rowid) AS sectorsizekb,
           (SELECT Substring(resulttext,(Charindex('KB ',resulttext)) + 3,
                             (Charindex(' IOs',resulttext)) - (Charindex('KB ',resulttext)) - 3)
            FROM   dbo.sqlio_import impiopattern
            WHERE  imp.rowid + 4 = impiopattern.rowid) AS iopattern,
           (SELECT Substring(resulttext,(Charindex('with ',resulttext)) + 5,
                             (Charindex(' outstanding',resulttext)) - (Charindex('with ',resulttext)) - 5)
            FROM   dbo.sqlio_import impiosoutstanding
            WHERE  imp.rowid + 5 = impiosoutstanding.rowid) AS iosoutstanding,
           (SELECT REPLACE(CAST(resulttext AS NVARCHAR(50)),'buffering set to ',
                           '')
            FROM   dbo.sqlio_import impbuffering
            WHERE  imp.rowid + 6 = impbuffering.rowid) AS buffering,
           (SELECT Substring(resulttext,(Charindex('size: ',resulttext)) + 6,
                             (Charindex(' for ',resulttext)) - (Charindex('size: ',resulttext)) - 9)
            FROM   dbo.sqlio_import impfilesizemb
            WHERE  imp.rowid + 7 = impfilesizemb.rowid) AS filesizemb,
           (SELECT RIGHT(resulttext,(Len(resulttext) - 10))
            FROM   dbo.sqlio_import impios_sec
            WHERE  imp.rowid + 11 = impios_sec.rowid) AS ios_sec,
           (SELECT RIGHT(resulttext,(Len(resulttext) - 10))
            FROM   dbo.sqlio_import impmbs_sec
            WHERE  imp.rowid + 12 = impmbs_sec.rowid) AS mbs_sec,
           (SELECT RIGHT(resulttext,(Len(resulttext) - 17))
            FROM   dbo.sqlio_import implatencyms_min
            WHERE  imp.rowid + 14 = implatencyms_min.rowid) AS latencyms_min,
           (SELECT RIGHT(resulttext,(Len(resulttext) - 17))
            FROM   dbo.sqlio_import implatencyms_avg
            WHERE  imp.rowid + 15 = implatencyms_avg.rowid) AS latencyms_avg,
           (SELECT RIGHT(resulttext,(Len(resulttext) - 17))
            FROM   dbo.sqlio_import implatencyms_max
            WHERE  imp.rowid + 16 = implatencyms_max.rowid) AS latencyms_max
  FROM     dbo.sqlio_import imp
           INNER JOIN dbo.sqlio_import impfulltest
             ON imp.rowid + 20 = impfulltest.rowid
                AND impfulltest.resulttext = ''
  WHERE    imp.rowid = imp.parameterrowid
           /*AND (SELECT Substring(resulttext,(Charindex('size: ',resulttext)) + 6,
                                 (Charindex(' for ',resulttext)) - (Charindex('size: ',resulttext)) - 9)
                FROM   dbo.sqlio_import impfilesizemb
                WHERE  imp.rowid + 7 = impfilesizemb.rowid) > 0 */
  ORDER BY imp.parameterrowid
           
  /* Empty out the ETL table */
  DELETE dbo.sqlio_import
         
  SET nocount off
GO

The script creates three things:

  • A table called SQLIO_Import where our results will first be dumped from the text file before they're processed
  • A table called SQLIO_TestPass where our results will be permanently stored in a report-friendly format
  • A stored procedure called USP_Import_SQLIO_TestPass. The stored procedure takes the data from our imported text file, parses it, and inserts records into the SQLIO_TestPass table.

The stored procedure expects these parameters, which it uses when inserting into SQLIO_TestPass. None of these have to be formatted a specific way - as long as they fit the SQL Server field definitions, they're fine:

  • @ServerName NVARCHAR(50) - the name of the server you're using for testing. This is mostly useful for servers with locally attached storage as opposed to SAN storage.
  • @DriveQty INT - the number of drives in the array you're testing.
  • @DriveRPM INT - you might be testing 10k and 15k variations of the same setup. I suggest lumping drives into categories - don't try to differentiate between drives that report 10,080 RPM or other odd numbers - just stick with 5400, 10000, 150000, etc. For SSD, I prefer to use a number for the generation of SSD, like 1 or 2.
  • @DriveRaidLevel NVARCHAR(10) - raid 5, raid 0, raid 10, raid DP, etc. (Yes, there are vendor-specific RAID implementations that use letters instead of numbers.)
  • @TestDate DATETIME - the date you're running the tests. I include this as a parameter because sometimes I've run the same tests on a quarterly basis and I want to track whether things are changing over time.
  • @SANmodel NVARCHAR(50) - the type of SAN, such as an IBM DS4800 or EMC CX300.
  • @SANfirmware NVARCHAR(50) - the version of firmware, which can impact SAN performance.
  • @PartitionOffset INT - Windows systems can use DISKPART to offset their partitions.
  • @Filesystem NVARCHAR(50) - usually NTFS. Can be used to track testing different filesystems.
  • @FSClusterSizeBytes INT - the file system cluster size.

Now that our framework is in place, let's import our first round of results.

Importing the Text File into SQL Server 2005

  • In SQL Server Management Studio, right-click on the database where you want to store the SQLIO performance data and click Tasks, Import Data.
  • For Data Source, choose "Flat File Source". Browse to your results.txt file, and set the Format to Delimited, Text Qualifier to None, Header row delimiter to {CR}{LF}, and Header Rows to Skip to 0.
  • Click on the Advanced tab on the left, and there should only be one column, Column 0. Set the DataType to text stream. Click Next.
  • Your database server and storage database should be shown. Click Next.
  • For the Destination Table, choose SQLIO_Import and click Edit Mappings. Set the Column 0 destination to be ResultText. Click OK, and click Next.
  • Click Next until the wizard finishes and imports the data, and then close the wizard.

Open a new query and verify that the data was successfully imported by typing:

SELECT * FROM dbo.SQLIO_Import

If there's no rows, something went wrong with the import process. Stop here and troubleshoot. Otherwise, execute the stored procedure to move the data into the reporting table, like this:

EXECUTE [dbo].[USP_Import_SQLIO_TestPass] 
   'MyServerName'
  ,10
  ,15000
  ,'RAID 10'
  ,'2008/5/6'
  ,'IBM DS4800'
  ,'6.62'
  ,1024
  ,'NTFS'
  ,'65536' -- 64K

The data will be parsed and inserted into the reporting table, which we can query:

SELECT * FROM dbo.SQLIO_TestPass

Now, the data is arranged in a way that's easier for reporting.

Analyzing the SQLIO Results

Start by analyzing the data to find the fastest SAN throughput:

SELECT * FROM dbo.SQLIO_TestPass ORDER BY MBs_Sec DESC

That column is the SAN's throughput. Notice the LatencyMS_Avg column, though, which indicates the milliseconds of latency. A high throughput number is not necessarily good if the system is taking a long time to respond. Look for five or so of the highest throughput numbers that represents a good balance of high throughput and low latency.

Then, look at the parameters that were used in order to achieve that throughput. Make a note of these, because if you need to do repeated throughput testing on your SAN to test different configurations, you can use these high-throughput configurations to run a much shorter testing pass. Instead of testing your SAN overnight, you can get a quick idea in a matter of minutes because you'll know what parameters tend to drive very high throughput on your SAN. You'll still want to test all parameters when possible, because changes to the SAN may affect how it handles other parameters, but this will give you a quick estimate of whether things are getting better or worse.

More Reading About SQLIO

Here's a few interesting links about other bloggers' experience with SQLIO:

Tags: sql server

Editing an SQL Server table in Excel

$
0
0
Revision 3 posted to SQL Server by Steve Hilker on 4/10/2014 4:55:01 PM

Anyone who lives in Microsoft Excel every day will get comfortable in that environment. This combined with the increasingly powerful toolset means you will be tempted to use Excel for much more than simple spreadsheets. How would you like to edit your database informationright from within Excel? In this article I would like to show you a neat way to edit SQL server data using Excel and ODBC!

Now, the immediate solution that comes to mind is to use an Excel sheet as an external Table in the SQL Server. This means that:

  1. The Excel sheet must be on the server
  2. You need a version of SQL Server and Excel that support this feature, along with the appropriate driver
  3. You need an agreeable DBA to allow this!

This, unfortunately, is not usually acceptable for a number of reasons.

Instead, here's a solution that allows editing a table within Excel that does not have these limitations and is likely to be more DBA-friendly! Editing SQL Data Using Microsoft Excel

If you want to follow along with this article we have provided an example to download called Update SQLServer.xlsm. It is an Excel file in which each sheet can be set to reflect an SQL Server's table.

When the sheet becomes active a macro will get the table's data from the server and display it. When a cell value is changed in the sheet the change will be written to the server (unless it's to a primary key column, which cannot be changed).

The idea here is that we retrieve the data from the table into the sheet, and when the user edits any cell, we write the change back to the server. To ensure we write the data into the correct row, we need to know a unique value in the table - basically, the primary key (which is unique in SQL Server). Because it must stay unique, and because we need it to edit the rest of the data, the current implementation does not allow changing the primary keys. For similar reasons, currently the implementation doesn't allow adding new rows to the table. Connecting to the Server

To use this file, first you have to connect it to your SQL Server. To do that, you'll need to update the connection string found in the Workbook_SheetActivate function:

sConnectionString = "Server=YOURSERVER;Database=YOURDB;UID=YOURUSERID;Pwd=YOURPASSWORD"

Replace:

  • 'YOURSERVER' with your server's address
  • 'YOURDB' with the database you wish to edit
  • 'YOURUSERID' with a user name that can edit the data
  • 'YOURPASSWORD' with the password of that user

Contents

Retrieving the Contents of a Table

Create a sheet in the file for each table you wish to edit, and name it in the name of the table. The Workbook_SheetActivate macro will automatically retrieve the data from the table; it is automatically run by Excel when you change sheets. Let's look at the contents of this macro:

Opening the connection to the database:

Set con = New ADODB.Connection
con.Provider = "sqloledb"
sConnectionString = "Server=YOURSERVER;Database=YOURDB;UID=YOURUSER;Pwd=*******"
con.OpensConnectionString

Now retrieve the primary key information, using SQL Server's table meta data:

Set rs = con.Execute("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS kcu ON tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME WHERE tc.CONSTRAINT_TYPE = 'PRIMARY KEY' AND tc.TABLE_NAME = '" & Sh.name & "'")

Fill up the primary key information

  While (Not rs.EOF)
    pk.AddCStr(rs(0))
    rs.MoveNext
  Wend

Next we clean up the data in the sheet. We then read the data from the table and populate the sheet with the field names on the first row and the data under it:

' Now get the table's data
Set rs = con.Execute("SELECT * FROM " & Sh.name)

' Set the name of the fields
  Dim TheCellsAs Range
  Set TheCells = Sh.Range("A1")
  For i = 0 Tors.Fields.Count - 1
     TheCells.Offset(0, i).Value = rs.Fields(i).name
  Next i

' Get value for each field
nRow = 1
  While (Not rs.EOF)
      For i = 0 Tors.Fields.Count - 1
         TheCells.Offset(nRow, i).Value = rs(i)
      Next
      rs.MoveNext
      nRow = nRow + 1
  Wend
nRecordCount = nRow - 1

That's basically it for getting the data. Note that whenever the user moves the selection to a new cell, we use the Workbook_SheetSelectionChange macro to remember the old value:

Private Sub Workbook_SheetSelectionChange(ByValSh As Object, ByVal Target As Range)
  If (Not bIgnoreChange) Then
' Remember the old value
     oldValue = Application.ActiveCell.Value
  End If
End Sub

This is important because we don't want to allow editing the cells in some cases, and remembering the value will allow us to change it back if necessary.

The editing part is done in the Workbook_SheetChange macro, which is called by Excel whenever the user changes a value in a cell. First we make sure that this sheet is actually connected to the server, and that something actually changed. If so, we then perform some tests to ensure that the value changed is in a cell we can actually write to the server:

' Don't allow changes in the column names or outside of the table borders
If Target.Row< 2 Or Sh.Cells(Target.Row ,1).Text = "" Or Sh.Cells(1, Target.Column) = "" Or (Target.Row>nRecordCount + 1) Then Target.Value = oldValue oldValue = Application.ActiveCell.Value MsgBox "You can only edit items inside the table" Exit Sub End If' Is this change is in a primary key column - if so, we can't edit it
If (IsInPrimaryKey(Sh.Cells(1, Target.Column).Text)) Then Target.Value = oldValue oldValue = Application.ActiveCell.Value MsgBox "This column is a part of the primary key, so it cannot be changed" Exit Sub End If

If we passed those tests, the value change be changed. So we build the SQL update query that will do the actual work:

' Build the primary key from the data in this row
  Dim Names As Range
  Set Names = Sh.Range("A1")
nColumn = 0
sWhere = ""
  While (Names.Offset(0, nColumn).Text <> "")
      If (IsInPrimaryKey(Names.Offset(0, nColumn).Text)) Then
          If (sWhere<> "") Then
              sWhere = sWhere& " AND "
          End If
          sWhere = sWhere&Sh.Cells(1, nColumn + 1).Text & " = " & MakeSQLText(Sh.Cells(Target.Row, nColumn + 1))
      End If
      nColumn = nColumn + 1
  Wend
  

And perform the change:

' Update the server!
sSQL = "UPDATE " & Sh.name & " SET " &Sh.Cells(1, Target.Column).Text & " = " &MakeSQLText(Target.Text) & " WHERE " &sWhere
con.ExecutesSQL
oldValue = Application.ActiveCell.Value

The Solution In Action

To demonstrate the functionality of this solution, we opened a connection the VersaForm's database and edited the facilities table.

Let's take a look at the table in MSQuery:

Next we open the file and rename one of the sheets to 'facilities':

Then we edited the facility name in Excel:

Now we refresh the MSQuery, which should reflect the table:

That's it; we have edited our SQL data table from within Excel!

Summary

Hopefully this article demonstrates how you and your colleagues can relatively easily edit your SQL Server data using only Microsoft Excel.

Unfortunately we have not implemented a solution for inserting new records, and obviously our solution precludes editing of primary keys. We hand solving those issues over to you, dear reader! Got any suggestions or questions? Feel free to comment or get in touch!

About the author

Yoav Ezer co-authors the technology and productivity blog Codswallop. He is also the CEO of a company that produces PDF to XLS conversion software.

For more Excel tips from Yoav, join him on Facebook or Twitter

Tags: sql server

Wait Types

$
0
0
Revision 3 posted to SQL Server Wiki by Steve Hilker on 11/2/2015 6:42:23 PM

See Also: [[wiki:Main Page|Main_Page]] - [[wiki:Monitoring & Tuning|Monitoring & Tuning]] - [[wiki:Wait Events|Wait Events]]


This article is the Collaboration of the Month for February 2010. Find out how it can be improved, read [[wiki:How To Help|how to edit articles]], then jump in to make this an article we can be proud of!

Contents

What Are SQL Server Waits?

Instead of measuring activity of CPU, storage, or memory, why not ask what SQL Server has been waiting on when executing queries? Starting with SQL Server 2005, some of SQL Server's [[wiki:DMVs|Dynamic Management Views (DMVs)]] return wait data - measurements of what the database engine has been waiting on.

In general there are three categories of waits that could affect any given request:

  • Resource waits are caused by a particular resource, perhaps a specific lock that is unavailable when the requested is submitted. Resource waits are the ones you should focus on for troubleshooting the large majority of performance issues.
  • External waits occur when SQL Server worker thread is waiting on an external process, such as extended stored procedure to be completed. External wait does not necessarily mean that the connection is idle; rather it might mean that SQL Server is executing an external code which it cannot control. Finally the queue waits occur if a worker thread is idle and is waiting for work to be assigned to it.
  • Queue waits normally apply to internal background tasks, such as ghost cleanup, which physically removes records that have been previously deleted. Normally you don't have to worry about any performance degradation due to queue waits.

You should expect some waits on a busy system. This is completely normal and doesn't necessarily translate into a performance issue. Wait events become a problem if they tend to be consistently long over a significant period of time. For example, waits that take few milliseconds over a 2 hour monitoring window are not concerning. Those waits taking over 15 minutes over a 2 hour monitoring window should be investigated more closely.

Queries to Check SQL Server Waits

  • [[wiki:Misc DMV queries|Current SQL Server Activity]] - a replacement for SP_Who2 that checks active queries, waits one second, then checks again. For all active queries, it shows their command and what wait type is holding them up.

Want to add more queries here? Go to the [[wiki:Transact SQL Code Library|Transact SQL Code Library]], click Edit, and add a new link on that page to describe your query. Just copy/paste one of the other links and edit it. After you save the page, your newly created link will appear red. You can click on it to edit a new page. Then come back here and add a link to it.

Explanations of SQL Server Wait Types

Some of these waits occur for internal operations and no tuning is necessary to avoid such waits - we identify those as well. Some of the following have more than one wait type. If you're looking for QUERY_NOTIFICATION_SUBSCRIPTION_MUTEX, for example, click on the QUERY_NOTIFICATION_* group and each of the underlying waits will be listed there.

  • [[wiki:ABR|ABR]] -
  • [[wiki:ASSEMBLY LOAD|ASSEMBLY_LOAD]] -
  • [[wiki:ASYNC DISKPOOL LOCK|ASYNC_DISKPOOL_LOCK]] - I/O
  • [[wiki:ASYNC IO COMPLETION|ASYNC_IO_COMPLETION]] - I/O Used to indicate a worker is waiting on a asynchronous I/O operation to complete not associated with database pages
  • [[wiki:ASYNC NETWORK IO|ASYNC_NETWORK_IO]] - Network
  • [[wiki:AUDIT GROUPCACHE LOCK|AUDIT_GROUPCACHE_LOCK]] -
  • [[wiki:AUDIT LOGINCACHE LOCK|AUDIT_LOGINCACHE_LOCK]] -
  • [[wiki:AUDIT ON DEMAND TARGET LOCK|AUDIT_ON_DEMAND_TARGET_LOCK]] -
  • [[wiki:AUDIT XE SESSION MGR|AUDIT_XE_SESSION_MGR]] -
  • [[wiki:BACKUP|BACKUP]] - Backup
  • [[wiki:BACKUP CLIENTLOCK|BACKUP_CLIENTLOCK]] - Backup
  • [[wiki:BACKUP OPERATOR|BACKUP_OPERATOR]] - Backup
  • [[wiki:BACKUPBUFFER|BACKUPBUFFER]] - Backup
  • [[wiki:BACKUPIO|BACKUPIO]] - Backup
  • [[wiki:BACKUPTHREAD|BACKUPTHREAD]] - Backup
  • [[wiki:BAD PAGE PROCESS|BAD_PAGE_PROCESS]] - Memory
  • [[wiki:BROKER *|BROKER_*]] - Service Broker
  • [[wiki:BUILTIN HASHKEY MUTEX|BUILTIN_HASHKEY_MUTEX]] - Internal
  • [[wiki:CHECK PRINT RECORD|CHECK_PRINT_RECORD]] -
  • [[wiki:CHECKPOINT QUEUE|CHECKPOINT_QUEUE]] - Buffer Used by background worker that waits on events on queue to process checkpoint requests. This is an "optional" wait type see Important Notes section in blog
  • [[wiki:CHKPT|CHKPT]] - Buffer Used to coordinate the checkpoint background worker thread with recovery of master so checkpoint won't start accepting queue requests until master online
  • [[wiki:CLEAR DB|CLEAR_DB]] -
  • [[wiki:CLR *|CLR_*]] - Common Language Runtime (CLR)
  • [[wiki:CLRHOST STATE ACCESS|CLRHOST_STATE_ACCESS]] -
  • [[wiki:CMEMTHREAD|CMEMTHREAD]] - Memory
  • [[wiki:COMMIT TABLE|COMMIT_TABLE]] -
  • [[wiki:CURSOR|CURSOR]] - Internal
  • [[wiki:CURSOR ASYNC|CURSOR_ASYNC]] - Internal
  • [[wiki:CXPACKET|CXPACKET]] - Query Used to synchronize threads involved in a parallel query. This wait type only means a parallel query is executing.
  • [[wiki:CXROWSET SYNC|CXROWSET_SYNC]] -
  • [[wiki:DAC INIT|DAC_INIT]] -
  • [[wiki:DBMIRROR *|DBMIRROR_*]] - Database Mirroring
  • [[wiki:DBMIRRORING CMD|DBMIRRORING_CMD]] - Database Mirroring
  • [[wiki:DBTABLE|DBTABLE]] - Internal
  • [[wiki:DEADLOCK ENUM MUTEX|DEADLOCK_ENUM_MUTEX]] - Lock
  • [[wiki:DEADLOCK TASK SEARCH|DEADLOCK_TASK_SEARCH]] - Lock
  • [[wiki:DEBUG|DEBUG]] - Internal
  • [[wiki:DISABLE VERSIONING|DISABLE_VERSIONING]] - Row versioning
  • [[wiki:DISKIO SUSPEND|DISKIO_SUSPEND]] - BACKUP Used to indicate a worker is waiting to process I/O for a database or log file associated with a SNAPSHOT BACKUP
  • [[wiki:DISPATCHER QUEUE SEMAPHORE|DISPATCHER_QUEUE_SEMAPHORE]] -
  • [[wiki:DLL LOADING MUTEX|DLL_LOADING_MUTEX]] - XML
  • [[wiki:DROPTEMP|DROPTEMP]] - Temporary Objects
  • [[wiki:DTC|DTC]] - Distributed Transaction Coordinator (DTC)
  • [[wiki:DTC ABORT REQUEST|DTC_ABORT_REQUEST]] - DTC
  • [[wiki:DTC RESOLVE|DTC_RESOLVE]] - DTC
  • [[wiki:DTC STATE|DTC_STATE]] - DTC
  • [[wiki:DTC TMDOWN REQUEST|DTC_TMDOWN_REQUEST]] - DTC
  • [[wiki:DTC WAITFOR OUTCOME|DTC_WAITFOR_OUTCOME]] - DTC
  • [[wiki:DUMP LOG *|DUMP_LOG_*]] -
  • [[wiki:DUMPTRIGGER|DUMPTRIGGER]] -
  • [[wiki:EC|EC]] -
  • [[wiki:EE PMOLOCK|EE_PMOLOCK]] - Memory
  • [[wiki:EE SPECPROC MAP INIT|EE_SPECPROC_MAP_INIT]] - Internal
  • [[wiki:ENABLE VERSIONING|ENABLE_VERSIONING]] - Row versioning
  • [[wiki:ERROR REPORTING MANAGER|ERROR_REPORTING_MANAGER]] - Internal
  • [[wiki:EXCHANGE|EXCHANGE]] - Parallelism (processor)
  • [[wiki:EXECSYNC|EXECSYNC]] - Parallelism (processor)
  • [[wiki:EXECUTION PIPE EVENT INTERNAL|EXECUTION_PIPE_EVENT_INTERNAL]] -
  • [[wiki:Failpoint|Failpoint]] -
  • [[wiki:FCB REPLICA *|FCB_REPLICA_*]] - Database snapshot
  • [[wiki:FS FC RWLOCK|FS_FC_RWLOCK]] -
  • [[wiki:FS GARBAGE COLLECTOR SHUTDOWN|FS_GARBAGE_COLLECTOR_SHUTDOWN]] -
  • [[wiki:FS HEADER RWLOCK|FS_HEADER_RWLOCK]] -
  • [[wiki:FS LOGTRUNC RWLOCK|FS_LOGTRUNC_RWLOCK]] -
  • [[wiki:FSA FORCE OWN XACT|FSA_FORCE_OWN_XACT]] -
  • [[wiki:FSAGENT|FSAGENT]] -
  • [[wiki:FSTR CONFIG *|FSTR_CONFIG_*]] -
  • [[wiki:FT *|FT_*]] - Full Text Search
  • [[wiki:GUARDIAN|GUARDIAN]] -
  • [[wiki:HTTP ENDPOINT COLLCREATE|HTTP_ENDPOINT_COLLCREATE]] -
  • [[wiki:HTTP ENUMERATION|HTTP_ENUMERATION]] - Service Broker
  • [[wiki:HTTP START|HTTP_START]] - Service Broker
  • [[wiki:IMP IMPORT MUTEX|IMP_IMPORT_MUTEX]] -
  • [[wiki:IMPPROV IOWAIT|IMPPROV_IOWAIT]] - I/O
  • [[wiki:INDEX USAGE STATS MUTEX|INDEX_USAGE_STATS_MUTEX]] -
  • [[wiki:INTERNAL TESTING|INTERNAL_TESTING]] -
  • [[wiki:IO AUDIT MUTEX|IO_AUDIT_MUTEX]] - Profiler Trace
  • [[wiki:IO COMPLETION|IO_COMPLETION]] - I/O Used to indicate a wait for I/O for operation (typically synchronous) like sorts and various situations where the engine needs to do a synchronous I/O
  • [[wiki:IO RETRY|IO_RETRY]] -
  • [[wiki:IOAFF RANGE QUEUE|IOAFF_RANGE_QUEUE]] -
  • [[wiki:KSOURCE WAKEUP|KSOURCE_WAKEUP]] - Shutdown Used by the background worker "signal handler" which waits for a signal to shutdown SQL Server
  • [[wiki:KTM *|KTM_*]] -
  • [[wiki:LATCH *|LATCH_*]] - Latch
  • [[wiki:LAZYWRITER SLEEP|LAZYWRITER_SLEEP]] - Buffer Used by the Lazywriter background worker to indicate it is sleeping waiting to wake up and check for work to do
  • [[wiki:LCK M *|LCK_M_*]] - Lock
  • [[wiki:LOGBUFFER|LOGBUFFER]] - Transaction Log Used to indicate a worker thread is waiting for a log buffer to write log blocks for a transaction
  • [[wiki:LOGGENERATION|LOGGENERATION]] -
  • [[wiki:LOGMGR *|LOGMGR_*]] - Internal
  • [[wiki:LOWFAIL MEMMGR QUEUE|LOWFAIL_MEMMGR_QUEUE]] - Memory
  • [[wiki:METADATA LAZYCACHE RWLOCK|METADATA_LAZYCACHE_RWLOCK]] -
  • [[wiki:MIRROR SEND MESSAGE|MIRROR_SEND_MESSAGE]] -
  • [[wiki:MISCELLANEOUS|MISCELLANEOUS]] - Ignore This really should be called "Not Waiting".
  • [[wiki:MSQL DQ|MSQL_DQ]] - Distributed Query
  • [[wiki:MSQL SYNC PIPE|MSQL_SYNC_PIPE]] -
  • [[wiki:MSQL XACT MGR MUTEX|MSQL_XACT_MGR_MUTEX]] - Transaction
  • [[wiki:MSQL XACT MUTEX|MSQL_XACT_MUTEX]] - Transaction
  • [[wiki:MSQL XP|MSQL_XP]] - Extended Procedure
  • [[wiki:MSSEARCH|MSSEARCH]] - Full-Text Search
  • [[wiki:NET WAITFOR PACKET|NET_WAITFOR_PACKET]] - Network
  • [[wiki:NODE CACHE MUTEX|NODE_CACHE_MUTEX]] -
  • [[wiki:OLEDB|OLEDB]] - OLEDB
  • [[wiki:ONDEMAND TASK QUEUE|ONDEMAND_TASK_QUEUE]] - Internal
  • [[wiki:PAGEIOLATCH *|PAGEIOLATCH_*]] - Latch
  • [[wiki:PAGELATCH *|PAGELATCH_*]] - Latch
  • [[wiki:PARALLEL BACKUP QUEUE|PARALLEL_BACKUP_QUEUE]] - Backup or Restore
  • [[wiki:PERFORMANCE COUNTERS RWLOCK|PERFORMANCE_COUNTERS_RWLOCK]] -
  • [[wiki:PREEMPTIVE ABR|PREEMPTIVE_ABR]] -
  • [[wiki:PREEMPTIVE AUDIT *|PREEMPTIVE_AUDIT_*]] -
  • [[wiki:PREEMPTIVE CLOSEBACKUPMEDIA|PREEMPTIVE_CLOSEBACKUPMEDIA]] -
  • [[wiki:PREEMPTIVE CLOSEBACKUPTAPE|PREEMPTIVE_CLOSEBACKUPTAPE]] -
  • [[wiki:PREEMPTIVE CLOSEBACKUPVDIDEVICE|PREEMPTIVE_CLOSEBACKUPVDIDEVICE]] -
  • [[wiki:PREEMPTIVE CLUSAPI CLUSTERRESOURCECONTROL|PREEMPTIVE_CLUSAPI_CLUSTERRESOURCECONTROL]] -
  • [[wiki:PREEMPTIVE COM *|PREEMPTIVE_COM_*]] -
  • [[wiki:PREEMPTIVE CONSOLEWRITE|PREEMPTIVE_CONSOLEWRITE]] -
  • [[wiki:PREEMPTIVE CREATEPARAM|PREEMPTIVE_CREATEPARAM]] -
  • [[wiki:PREEMPTIVE DEBUG|PREEMPTIVE_DEBUG]] -
  • [[wiki:PREEMPTIVE DFSADDLINK|PREEMPTIVE_DFSADDLINK]] -
  • [[wiki:PREEMPTIVE DFS*|PREEMPTIVE_DFS*]] -
  • [[wiki:PREEMPTIVE DTC *|PREEMPTIVE_DTC_*]] -
  • [[wiki:PREEMPTIVE FILESIZEGET|PREEMPTIVE_FILESIZEGET]] -
  • [[wiki:PREEMPTIVE FSAOLEDB *|PREEMPTIVE_FSAOLEDB_*]] -
  • [[wiki:PREEMPTIVE FSRECOVER UNCONDITIONALUNDO|PREEMPTIVE_FSRECOVER_UNCONDITIONALUNDO]] -
  • [[wiki:PREEMPTIVE GETRMINFO|PREEMPTIVE_GETRMINFO]] -
  • [[wiki:PREEMPTIVE LOCKMONITOR|PREEMPTIVE_LOCKMONITOR]] -
  • [[wiki:PREEMPTIVE MSS RELEASE|PREEMPTIVE_MSS_RELEASE]] -
  • [[wiki:PREEMPTIVE ODBCOPS|PREEMPTIVE_ODBCOPS]] -
  • [[wiki:PREEMPTIVE OLE UNINIT|PREEMPTIVE_OLE_UNINIT]] -
  • [[wiki:PREEMPTIVE OLEDB *|PREEMPTIVE_OLEDB_*]] -
  • [[wiki:PREEMPTIVE OLEDBOPS|PREEMPTIVE_OLEDBOPS]] -
  • [[wiki:PREEMPTIVE OS *|PREEMPTIVE_OS_*]] -
  • [[wiki:PREEMPTIVE REENLIST|PREEMPTIVE_REENLIST]] -
  • [[wiki:PREEMPTIVE RESIZELOG|PREEMPTIVE_RESIZELOG]] -
  • [[wiki:PREEMPTIVE ROLLFORWARDREDO|PREEMPTIVE_ROLLFORWARDREDO]] -
  • PREEMPTIVE_ROLLFORWARDUNDO -
  • PREEMPTIVE_SB_STOPENDPOINT -
  • PREEMPTIVE_SERVER_STARTUP -
  • PREEMPTIVE_SETRMINFO -
  • PREEMPTIVE_SHAREDMEM_GETDATA -
  • PREEMPTIVE_SNIOPEN -
  • PREEMPTIVE_SOSHOST -
  • PREEMPTIVE_SOSTESTING -
  • PREEMPTIVE_STARTRM -
  • PREEMPTIVE_STREAMFCB_CHECKPOINT -
  • PREEMPTIVE_STREAMFCB_RECOVER -
  • PREEMPTIVE_STRESSDRIVER -
  • PREEMPTIVE_TESTING -
  • PREEMPTIVE_TRANSIMPORT -
  • PREEMPTIVE_UNMARSHALPROPAGATIONTOKEN -
  • PREEMPTIVE_VSS_CREATESNAPSHOT -
  • PREEMPTIVE_VSS_CREATEVOLUMESNAPSHOT -
  • [[wiki:PREEMPTIVE XE *|PREEMPTIVE_XE_*]] -
  • PREEMPTIVE_XETESTING -
  • PREEMPTIVE_XXX - Varies Used to indicate a worker is running coded that is not under the SQLOS Scheduling Systems
  • PRINT_ROLLBACK_PROGRESS - Alter Database state
  • QNMANAGER_ACQUIRE -
  • QPJOB_KILL - Update of statistics
  • QPJOB_WAITFOR_ABORT - Update of statistics
  • QRY_MEM_GRANT_INFO_MUTEX -
  • QUERY_ERRHDL_SERVICE_DONE -
  • QUERY_EXECUTION_INDEX_SORT_EVENT_OPEN - Building indexes
  • [[wiki:QUERY NOTIFICATION *|QUERY_NOTIFICATION_*]] - Query Notification Manager
  • QUERY_OPTIMIZER_PRINT_MUTEX - Query Notification Manager
  • QUERY_TRACEOUT - Query Notification Manager
  • QUERY_WAIT_ERRHDL_SERVICE -
  • RECOVER_CHANGEDB - Internal
  • REPL_CACHE_ACCESS - Replication
  • REPL_HISTORYCACHE_ACCESS -
  • REPL_SCHEMA_ACCESS - Replication
  • REPL_TRANHASHTABLE_ACCESS -
  • REPLICA_WRITES - Database Snapshots
  • REQUEST_DISPENSER_PAUSE - Backup or Restore
  • REQUEST_FOR_DEADLOCK_SEARCH - Lock Used by background worker "Lock Monitor" to search for deadlocks. This is an "optional" wait type see Important Notes section in blog
  • RESMGR_THROTTLED -
  • RESOURCE_QUERY_SEMAPHORE_COMPILE - Query Used to indicate a worker is waiting to compile a query due to too many other concurrent query compilations that require "not small" amounts of memory.
  • RESOURCE_QUEUE - Internal
  • [[wiki:RESOURCE SEMAPHORE *|RESOURCE_SEMAPHORE_*]] - Query Used to indicate a worker is waiting to be allowed to perform an operation requiring "query memory" such as hashes and sorts
  • RG_RECONFIG -
  • SEC_DROP_TEMP_KEY - Security
  • SECURITY_MUTEX -
  • SEQUENTIAL_GUID -
  • SERVER_IDLE_CHECK - Internal
  • SHUTDOWN - Internal
  • [[wiki:SLEEP *|SLEEP_*]] - Internal
  • [[wiki:SNI *|SNI_*]] - Internal
  • [[wiki:SOAP *|SOAP_*]] - SOAP
  • [[wiki:SOS *|SOS_*]] - Internal
  • [[wiki:SOSHOST *|SOSHOST_*]] - CLR
  • [[wiki:SQLCLR *|SQLCLR_*]] - CLR
  • SQLSORT_NORMMUTEX -
  • SQLSORT_SORTMUTEX -
  • [[wiki:SQLTRACE *|SQLTRACE_*]] - Trace
  • SRVPROC_SHUTDOWN -
  • TEMPOBJ -
  • THREADPOOL - SQLOS Indicates a wait for a task to be assigned to a worker thread
  • TIMEPRIV_TIMEPERIOD -
  • TRACE_EVTNOTIF -
  • [[wiki:TRACEWRITE|TRACEWRITE]] -
  • [[wiki:TRAN *|TRAN_*]] - TRAN_MARKLATCH
  • TRANSACTION_MUTEX -
  • UTIL_PAGE_ALLOC -
  • VIA_ACCEPT -
  • VIEW_DEFINITION_MUTEX -
  • WAIT_FOR_RESULTS -
  • WAITFOR - Background
  • WAITFOR_TASKSHUTDOWN -
  • WAITSTAT_MUTEX -
  • WCC -
  • WORKTBL_DROP -
  • WRITE_COMPLETION -
  • WRITELOG - I/O Indicates a worker thread is waiting for LogWriter to flush log blocks.
  • XACT_OWN_TRANSACTION -
  • XACT_RECLAIM_SESSION -
  • XACTLOCKINFO -
  • XACTWORKSPACE_MUTEX -
  • [[wiki:XE *|XE_*]] - XEvent

Related Reading

Tags: sql server
Viewing all 33 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>