Search results matching tags 'Speaking' and 'Dynamic Management'http://sqlblog.com/search/SearchResults.aspx?o=DateDescending&tag=Speaking,Dynamic+Management&orTags=0Search results matching tags 'Speaking' and 'Dynamic Management'en-USCommunityServer 2.1 SP2 (Build: 61129.1)Quest DMV Breakfast Code – Disk IOhttp://sqlblog.com/blogs/louis_davidson/archive/2009/11/04/quest-dmv-breakfast-code-disk-io.aspxWed, 04 Nov 2009 17:52:43 GMT21093a07-8b3d-42db-8cbf-3350fcbf5496:18532drsql<p>For any of you who attended the Quest breakfast at PASS (and anyone else really) I wanted to go ahead and post the code and give a little wrap up/explanation. (I will post the stuff on perf counters later. They are cool, but this is really what I wanted to make sure people saw.)</p> <p>I had a plan for my presentation, but time was less than I expected, and the good stuff kinda fell off. So here is the stuff around the Disk IO DMV section that I really messed up and didn’t show enough. I read a few of the comments that my presentation wasn’t that useful to you, and that is clearly on me.&#160; If the index ones are useful, these are too, and can be used to help spread load around your disks.</p> <p>So, here is the slide I presented:</p> <p>&#160;<a href="http://sqlblog.com/blogs/louis_davidson/image_4D31E3BE.png"><img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" border="0" alt="image" src="http://sqlblog.com/blogs/louis_davidson/image_thumb_710A954B.png" width="244" height="180" /></a> </p> <p>By knowing the amount of data written to a database file, you can see how busy the file is, the filegroup is, the database, the disk drive, etc, by aggregating the data in the following query in various way.&#160; The query is pretty simple and will return all files in all databases (there are parms on the function to change that, but check BOL for more info):</p> <p>--since reboot <br />SELECT db_name(mf.database_id) as databaseName, <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; mf.physical_name, divfs.num_of_reads, <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; divfs.num_of_bytes_read, divfs.io_stall_read_ms,&#160; <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; divfs.num_of_writes, divfs.num_of_bytes_written, <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; divfs.io_stall_write_ms, <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; divfs.io_stall,size_on_disk_bytes <br />FROM sys.dm_io_virtual_file_stats(null,null) as divfs <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; JOIN sys.master_files as mf <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ON mf.database_id = divfs.database_id <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; and mf.file_id = divfs.file_id</p> <p>&#160;</p> <p>The “stall” columns give you how long any processes have waited on your disk drives to serve up data for this file.&#160; This information plus the information in _bytes_written and _bytes_read columns can give you how much data was moved, and how long your CPU had to wait for the data before it could get working on it.&#160; Very powerful stuff, and can really give you a look at opportunities for performance tuning.</p> <p>That query gives you data from the last reboot of the server, but usually you want to see up to date values. So you have to get a baseline of values, then compare them at a later point.&#160; You can build tools that do this, and you can use the performance data warehouse in 2008, and I will demonstrate the former.&#160; Using a temp table and a WAITFOR DELAY command, I build a quick tool to see waits and stats over 20 seconds. Note that I use a #temp table to allow you to run the last query over and over to see the comparison to the baseline until you want to drop the #temp table.</p> <p>--over the following delay <br />declare @delay varchar(10) = '00:00:20' </p> <p>SELECT db_name(mf.database_id) as databaseName, <br />&#160;&#160;&#160;&#160;&#160;&#160; mf.physical_name, divfs.num_of_reads, <br />&#160;&#160;&#160;&#160;&#160;&#160; divfs.num_of_bytes_read, divfs.io_stall_read_ms, <br />&#160;&#160;&#160;&#160;&#160;&#160; divfs.num_of_writes, divfs.num_of_bytes_written, <br />&#160;&#160;&#160;&#160;&#160;&#160; divfs.io_stall_write_ms, <br />&#160;&#160;&#160;&#160;&#160;&#160; divfs.io_stall,size_on_disk_bytes, <br />&#160;&#160;&#160;&#160;&#160;&#160; getdate() as baselineDate <br />INTO #baseline <br />FROM sys.dm_io_virtual_file_stats(null,null) as divfs <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; JOIN sys.master_files as mf <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ON mf.database_id = divfs.database_id <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; and mf.file_id = divfs.file_id </p> <p>WAITFOR DELAY @delay </p> <p>;WITH currentLine as (&#160;&#160; <br />&#160;&#160;&#160; SELECT&#160; db_name(mf.database_id) as databaseName,&#160;&#160; <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; mf.physical_name,num_of_reads, num_of_bytes_read, <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; io_stall_read_ms, num_of_writes, <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; num_of_bytes_written, io_stall_write_ms, <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; io_stall,size_on_disk_bytes, <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; getdate() as currentlineDate <br />&#160;&#160;&#160;&#160; FROM sys.dm_io_virtual_file_stats(null,null) as divfs <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; JOIN sys.master_files as mf <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ON mf.database_id = divfs.database_id <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; and mf.file_id = divfs.file_id) </p> <p>SELECT&#160; DATEDIFF(s,#baseline.baselineDate,currentlineDate), <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; currentLine.databaseName, <br />&#160;&#160;&#160;&#160;&#160; left(currentLine.physical_name,1) as drive, <br />&#160;&#160;&#160;&#160;&#160; currentLine.physical_name <br />&#160;&#160;&#160;&#160; ,currentLine.io_stall - #baseline.io_stall as io_stall_ms <br />&#160;&#160;&#160;&#160; ,currentLine.io_stall_read_ms - <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; #baseline.io_stall_read_ms as io_stall_read_ms <br />&#160;&#160;&#160;&#160; ,currentLine.io_stall_write_ms - <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; #baseline.io_stall_write_ms as io_stall_write_ms <br />&#160;&#160;&#160;&#160; ,currentLine.num_of_reads - #baseline.num_of_reads as <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; num_of_reads </p> <p align="left">&#160;&#160;&#160; ,currentLine.num_of_writes - #baseline.num_of_writes <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; as num_of_writes <br />&#160;&#160; ,currentLine.num_of_bytes_written - <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; #baseline.num_of_bytes_written as num_of_bytes_written <br />FROM currentLine <br />&#160;&#160;&#160;&#160;&#160; join #baseline <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; on #baseLine.databaseName = currentLine.databaseName <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; and #baseLine.physical_name = <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; currentLine.physical_name <br />go <br />--drop table&#160; #baseline</p> <p align="left">The most interesting part of this query is often the stall columns.&#160; When I see really bad IO, the number of seconds waited can end up being way more than the actual number of seconds. Disk IO is more or less serial (particularly on my mini HP with Win7 Starter Edition), so if you have many queries running concurrently, every one of them needs data from the same IO source, and if one query used the disk for 1 second, the other processes might wait for 1 second each. When wait stats are really low, that means the disk were ready, willing, and able to serve all processes.</p> <p align="left">On your test server, you can use a query like:</p> <p>--create database DMV <br />--go <br />use DMV <br />go <br />create table testDMV <br />( <br />&#160;&#160;&#160; testDMVid int identity, <br />&#160;&#160;&#160; bigun&#160;&#160;&#160;&#160; char(8000) <br />) <br />go <br />set nocount on <br />insert into testDMV(bigun) <br />select REPLICATE('a',8000) <br />go 5000 </p> <p>--drop table testDmv </p> <p>select * <br />from&#160;&#160; testDMV</p> <p>&#160;</p> <p>To create some data.&#160; Note that data will be written to the disk in various counts.&#160; I set all of the rows to take a full data page, and each of the rows is an individual transaction.&#160; But it won’t be a 1-1 match with the number of rows written or read. SQL Server flushes data to the disk in the manner it wants to, and some manner of caching will change the number over time.&#160; Run the select * from testDMV query over and over and you will not see any change in the disk IO, because it is in cache now.</p> <p>I hope this is better. Sometimes as a presenter I am a good writer, and frankly the lack of bacon really threw me off this morning. Feel free to email me at <a href="mailto:louis@drsql.org">louis@drsql.org</a> or tweet me at drsql and I will be happy to share more.&#160; All of this will be in our RedGate book that will be coming out before the end of the millennium, at the very minimum.</p>