Reading and writing to the
disk is the heart of what
any database management
system does, SQL Server
included. Input/Output (I/O)
performance can make or
break an application. This
article discusses the
diagnostic tools that can be
used to examine SQL Server's
I/O statistics so that you
can make fact-based
judgments about disk
configurations.There are
several ways to request I/O
statistics from SQL Server
such as the System
Statistical functions,
sp_monitor, and
fn_virtualfilestats. Each
method has its advantages
and disadvantages. I'll show
you how they work and their
pros and cons.
I rely primarily on
fn_virtualfilestats because
it gives the most detailed
information. The other
methods aggregate
information at the instance
level. The instance level
may be the only meaningful
alternative when 'you are
accounting for the CPU, but
when working with file I/O
having the detailed
breakdown is helpful.
One of the limitations of
all of system statistical
functions and
fn_virtualfilestats is that
their reports are always
based on the resources
consumed since the instance
started. This includes both
peak usage times and low
usage times. If your
instance has been running
through several cycles of
peak to low usage these
overall aggregates may be of
some interest, but they are
usually most interesting
during times of peak usage.
After we discuss the various
methods for statistics
gathering, I will show you a
stored procedure for
gathering I/O statistics
during peak time periods.
Ways to get I/O
Statistics
Although the statistics
are nearly identical, there
are several ways to request
them from SQL Server 2000.
The methods are:
- The system
statistical functions
such as @@CPU_BUSY
- sp_monitor
- fn_virtualfilestats
The first two methods
give you information that is
aggregated at the instance
level. Let's take a look at
them first.
Using the System
Statistical Functions
The system statistical
functions cover I/O, network
and CPU resource
utilization. Table 1 lists
them.
Table 1 System
Statistical Functions
Function
|
Description |
|
@@CONNECTIONS |
The number of
connections or
attempted
connections. |
|
@@CPU_BUSY |
Timer ticks that the
CPU has been working
for SQL Server. |
|
@@IDLE |
Time in timer ticks
that SQL Server has
been idle. |
|
@@IO_BUSY |
Timer ticks that SQL
Server has spent
performing I/O
operations. |
|
@@PACKET_ERRORS |
Number of network
packet errors that
have occurred. |
|
@@PACK_RECEIVED |
Number of packets
read from the
network. |
|
@@PACK_SENT |
Number of packets
written to the
network. |
|
@@TIMETICKS |
Number of millionths
of a second in a
timer tick. |
|
@@TOTAL_ERRORS |
Number of read/write
errors during I/O
operations. |
|
@@TOTAL_READ |
Number of disk
reads. |
|
@@TOTAL_WRITE |
Number of disk
writes. |
For monitoring I/O the
most interesting numbers are
@@IO_BUSY, @@Total_READ and
@@TOTAL_WRITE. Here is a
simple query that shows the
raw statistics:
-- Take a look at raw I/O Statistics
SELECT @@TOTAL_READ [Total Reads]
, @@TOTAL_WRITE as [Total Writes]
, CAST(@@IO_BUSY as FLOAT) * @@TIMETICKS / 1000000.0 as [IO Sec]
GO
(Results)
Total Reads Total Writes IO Sec
----------- ------------ -----------
85336 322109 25.375
When using the functions
@@IO_BUSY, @@CPU_BUSY, and
@@IDLE, the function returns
clock ticks. To convert
ticks to seconds, multiply
by @@TIMERTICKS and then
divide by one million. Be
sure to convert the
quantities to floating
point, numeric, or bigint to
avoid integer overflow
during intermediate
calculations.
The raw numbers alone
aren't very interesting. 'It
is more informative to turn
the numbers into rates. To
do that you need to know how
long the instance has been
running. This next script
uses a user-defined function
(UDF),
udf_SQL_StartDT,
which uses the start time of
the Lazy Writer process as a
proxy for the start time of
the instance.
udf_SQL_StartDT is
available from my free T-SQL
UDF of the Week Newsletter
Volume 1 #11.
The start time is turned
into a number of seconds and
the script performs the
division, being careful to
CAST to data types that
'will not lose information
due to rounding or integer
division:
-- Turn the raw statistics into rates
DECLARE @SecFromStart bigint
SET @SecFromStart = DATEDIFF(s, dbo.udf_SQL_StartDT(), getdate())
SELECT CAST(CAST(@@TOTAL_READ as Numeric (18,2))/@SecFromStart
as Numeric (18,2)) as [Reads/Sec]
, CAST(CAST(@@TOTAL_WRITE as Numeric (18,2))/@SecFromStart
as Numeric (18,2)) as [Writes/Sec]
, CAST(@@IO_BUSY * @TIMETICKS/10000.0/@SecFromStart
as Numeric (18,2)) as [Percent I/O Time]
GO
(Results)
Reads/Sec Writes/Sec Percent I/O Time
-------------------- -------------------- --------------------
24.34 92.53 .42
The read and write rates
are often in the tens or
hundreds, at least over
short time spans. You might
ask, "Why do you bother to
retain even two digits to
the right of the decimal?"
Most of the time these extra
two digits do not come into
play. However, when a system
has been idle for a long
time, let's say over the
weekend after being
restarted on Friday night,
it's possible to have rates
that are less than one.
Showing zero for the rates
is confusing, so I have
tried to be sure that at
least a small number shows
up.
Showing rates from the
time the instance started
until the query is run
forces you to average over a
long time period. SQL Server
supplies a stored procedure
that shows the values of the
system statistical functions
since it was last run, this
let's you get a quick
snapshot of your I/O rates.