Click here to monitor SSC

FatherJack

SQL Q+A forum at ask.sqlservercentral.com | Follow fatherjack on Twitter

Don't even believe SSMS when you think it's telling the truth

Published Monday, February 28, 2011 3:00 AM

LiveJournal Tags: ,,,

This is in follow up to my last post How to make sure you see the truth in Management Studio which explained that the time that you see at the bottom of a Management Studio window cannot be believed to represent the time it takes for a query to execute as it also includes the time taken for SSMS to receive and format the data grid.

Now, very soon after that went live I received a comment from Dave Ballantyne (Blog | Twitter) mentioning that having SET STATISTICS TIME ON affects the time TSQL takes to execute. Really? That sounds dumb. Not Dave's comment, but the fact that the turning on of a setting to collect statistics actually affect the statistics you are collecting. That's a bit like timing the 100m by making the runners carry a guy with a stopwatch on their backs. Dave actually blogged about it here - The Observer Effect In Action and after reading that I started thinking about how much effect the TIME ON setting was having.

Now you can wrap a piece of code with a few lines of other code and easily come up with a way of measuring the time taken. Declare a variable to hold the time, set it to GETDATE(), run your script, subtract the time now from the variable ...

StatisticsTimeOn01

So, if I wrap the execution of the UDF and TVF from my previous post in this code and execute it twice, once with TIME ON and once with TIME OFF I'll see the difference that this causes.

StatisticsTimeOn02_QueryThe scalar UDF wrapped in the Start/Stop timing code twice - once for TIME ON and once for TIME OFF 

So running this I thought I might see a few ms difference as SQL Server takes a CPU cycle or two to log the time taken.

 

 

WRONG!


StatisticsTimeOn03_Results

Over 2s is added to the execution time of the Scalar UDF when you have STATISTICS TIME ON.

 


OK, what about the TVF? That only took 3/10ths of a second in my last test, how would this be affected? I re-wrote the script to use the TVF and return the times as above and the results were pretty variable, sometimes TIME ON was quicker, sometimes TIME OFF was quicker, only ever by a few ms though. This was intriguing, and annoying. SQL Server was skewing my results without so much as a mention in Books OnLine that it might happen.

Having seen the TVF results vary I set about running these queries a lot of times and seeing how much things did actually vary. This is the resulting code:

USE [adventureworks]
GO
IF OBJECT_ID('TimeOnOffResults') > 0
  
BEGIN
   RAISERROR
('table exists',0,0,1) WITH NOWAIT
  
END
ELSE
   BEGIN
      
--DROP TABLE TimeOnOffResults
  
CREATE TABLE TimeOnOffResults
      
(
              
RunID INT IDENTITY ,
              
TimeOnOff CHAR(3) ,
              
TVF_results INT ,
              
Scalar_Results INT
      
)
  
END
GO
DECLARE @x INT
   SET
@x = 1
WHILE @x <200
  
BEGIN
      SET STATISTICS
TIME OFF
      SET
ROWCOUNT 1000000
  
DECLARE @Now DATETIME
   DECLARE
@TVF INT
   DECLARE
@Scalar INT
   DECLARE
@TimeON_Off CHAR(3)
  
SELECT @TimeON_Off = 'Off'
  
SELECT @Now = GETDATE()
  
DECLARE @d1 DATETIME
   DECLARE
@d2 DATETIME
   DECLARE
@r1 INT
   DECLARE
@r2 INT
   SELECT
@d1 = [dbo].[fn_01]() ,
      
@r1 = [dbo].[Numbers].[N]
      
FROM [dbo].[Numbers]
  
SELECT @Scalar = DATEDIFF(ms, @now, GETDATE())
  
SELECT @Now = GETDATE()
  
SELECT @r2 = [n].[N] ,
      
@d2 = [f].[FinancialYearStartDate]
      
FROM [dbo].[Numbers] AS n
            
CROSS APPLY fn_02() AS f
  
SELECT @TVF = DATEDIFF(ms, @now, GETDATE())
  
INSERT INTO [dbo].[TimeOnOffResults]
      
( [TimeOnOff] ,
              
[TVF_results] ,
              
[Scalar_Results]
      
)
        
VALUES ( @TimeON_Off , -- TimeOnOff - char(3)
        
@TVF , -- TVF_results - smalldatetime
        
@Scalar-- Scalar_Results - smalldatetime
      
)
  
SET STATISTICS TIME ON
   SELECT
@TimeON_Off = 'On'
  
SELECT @Now = GETDATE()
      
SET ROWCOUNT 1000000
  
SELECT @d1 = [dbo].[fn_01]() ,
      
@r1 = [dbo].[Numbers].[N]
      
FROM [dbo].[Numbers]
  
SELECT @Scalar = DATEDIFF(ms, @now, GETDATE())
  
SELECT @Now = GETDATE()
  
SELECT @r2 = [n].[N] ,
      
@d2 = [f].[FinancialYearStartDate]
      
FROM [dbo].[Numbers] AS n
            
CROSS APPLY fn_02() AS f
  
SELECT @TVF = DATEDIFF(ms, @now, GETDATE())
  
INSERT INTO [dbo].[TimeOnOffResults]
      
( [TimeOnOff] ,
              
[TVF_results] ,
              
[Scalar_Results]
      
)
        
VALUES ( @TimeON_Off , -- TimeOnOff - char(3)
        
@TVF , -- TVF_results - smalldatetime
        
@Scalar-- Scalar_Results - smalldatetime
      
)
  
SET @x = @x +1
  
RAISERROR(@x,0,0,1) WITH nowait
  
END

I left this run for almost an hour on my home machine and the results are quite interesting
SummaryResults

Of the 199 executions the TVF averaged 8ms faster execution with TIME ON whereas the Scalar UDF over the same number of executions was on average 2.6s faster with TIME OFF.

So what does this mean?
To be honest, other than advising people to not use SET STATISTICS TIME as an absolute measure of their query execution times, I don't know. I can find no details online about why this is the case or any way to mitigate it other than, as Dave suggested, using variables in the way I have above. It seems an arbitrary 'weight' that comes along when Scalar UDF's are involved, it does even scale with the number of rows returned.

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

Matt Whitfield said:

This is definitely a troublesome topic. Because SQL Server will stream results to the client before it has finished executing. For example, if you're doing a group by - then rows can be streamed to the client after the first group by is done (i'm massively over-simplifying here - but i'm getting to a point :) ).

So - how long did your query take to execute? If you are waiting for the client to stream data, does that count? In SQL Everywhere, I give times as 'Execution' and 'Network' - 'Execution' being time from batch submitted to first result row, and 'Network' being time from first to last result row. But even that can be misleading - because execution can still be going on while results are going to the client.

Hard topic.
February 28, 2011 1:34 PM
 

John Sansom said:

Another great post.

This discovery is both very interesting and annoying! I need to know more.......
March 2, 2011 1:34 PM
 

Something for the Weekend – SQL Server Links 04/03/11 | John Sansom - SQL Server DBA in the UK said:

March 4, 2011 10:06 AM

What do you think?

(required) 
(optional)
(required) 

About fatherjack

DBA since 1999 working for not-for-profit company. http://twitter.com/fatherjack,
Latest articles
Checking Out SQL Backup Pro 7’s New Automatic Backup Verification
 Wouldn't it be great to offload the daily chore of checking the integrity of your production... Read more...

Chuck Lathrope: DBA of the Day
 Chuck Lathrope was a finalist for the Exceptional DBA of the Year award in 2009. We contacted him to... Read more...

Backups, What Are They Good For?
 Pixar recently confessed, in an engaging video, that Toy Story 2 was almost lost due to a bad backup,... Read more...

C# Async: What is it, and how does it work?
 The biggest new feature in C#5 is Async, and its associated Await (contextual) keyword. Anybody who is... Read more...

SQL Server 2012 AlwaysOn
 SQL Server AlwaysOn provides a high-availability and Disaster-recovery solution for SQL Server 2012. It... Read more...