Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 6ac5ea4

Browse files
committed
Massive improvement of sp_BenchmarkTSQL stored procedure
- Change date time format on DATETIME2(7) to increase benchmark calculation - Add @durationAccuracy parameter - Improve accuracy of duration calculation - Add BenchmarkTSQLID IDENTITY column to results table - Fix issue with arithmetic overflow, change INT to BIGINT data type
1 parent e3000a2 commit 6ac5ea4

File tree

1 file changed

+168
-55
lines changed

1 file changed

+168
-55
lines changed

‎Stored_Procedure/sp_BenchmarkTSQL.sql‎

Lines changed: 168 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ GO
44

55

66
ALTER PROCEDURE dbo.sp_BenchmarkTSQL(
7-
@tsqlStatement NVARCHAR(MAX)=N''
7+
@tsqlStatement NVARCHAR(MAX)
88
, @numberOfExecution INT = 10
99
, @saveResults BIT = 0
1010
, @clearCache BIT = 0
1111
, @calcMedian BIT = 0
1212
, @printStepInfo BIT = 1
13+
, @durationAccuracy VARCHAR(10) = 'ns'
1314
)
1415
/*
1516
.SYNOPSIS
@@ -44,11 +45,13 @@ ALTER PROCEDURE dbo.sp_BenchmarkTSQL(
4445
EXEC sp_BenchmarkTSQL @tsqlStatement = 'SELECT * FROM sys.databases';
4546
4647
.EXAMPLE
47-
EXEC sp_BenchmarkTSQL @tsqlStatement = 'SELECT TOP(10000) * FROM sys.objects AS o1 CROSS JOIN sys.objects AS o2;'
48+
EXEC sp_BenchmarkTSQL @tsqlStatement = 'SELECT TOP(100000) * FROM sys.objects AS o1 CROSS JOIN sys.objects AS o2 CROSS JOIN sys.objects AS o3;'
4849
, @numberOfExecution = 100
50+
, @saveResults = 1
4951
, @calcMedian = 1
5052
, @clearCache = 1
51-
, @printStepInfo = 0;
53+
, @printStepInfo = 0
54+
, @durationAccuracy = 'ms';
5255
5356
.NOTE
5457
Author: Aleksei Nagorskii
@@ -60,8 +63,8 @@ ALTER PROCEDURE dbo.sp_BenchmarkTSQL(
6063
Version: 1.1
6164
6265
Author: Konstantin Taranov
63-
Modified date: 2017-12-16
64-
Version: 1.2
66+
Modified date: 2017-12-23
67+
Version: 2.0
6568
*/
6669
AS
6770
BEGIN TRY
@@ -71,7 +74,23 @@ BEGIN TRY
7174
IF @tsqlStatement IS NULL
7275
THROW 55001, '@tsqlStatement is NULL, please specify TSQL statement.', 1;
7376
IF @tsqlStatement = N''
74-
THROW 55001, '@tsqlStatement is empty, please specify TSQL statement.', 1;
77+
THROW 55002, '@tsqlStatement is empty, please specify TSQL statement.', 1;
78+
79+
IF @durationAccuracy NOT IN (
80+
'ns' -- nanosecond
81+
, 'mcs' -- microsecond
82+
, 'ms' -- millisecond
83+
, 'ss' -- second
84+
, 's' -- second
85+
, 'mi' -- minute
86+
, 'n' -- minute
87+
, 'hh' -- hour
88+
, 'wk' -- week
89+
, 'ww' -- week
90+
, 'dd' -- day
91+
, 'd' -- day
92+
)
93+
THROW 55003, '@durationAccuracy can be only in this values: ns, mcs, ms, ss, s, mi, n, hh. See DATEDIFF https://docs.microsoft.com/en-us/sql/t-sql/functions/datediff-transact-sql' , 1;
7594

7695
IF EXISTS (
7796
SELECT 1
@@ -90,114 +109,208 @@ BEGIN TRY
90109
FROM sys.dm_exec_describe_first_result_set(@tsqlStatement, NULL, 0)
91110
WHERE column_ordinal = 0;
92111

93-
THROW 55002, @err_msg, 1;
112+
THROW 55004, @err_msg, 1;
94113
END
95114

96115
DECLARE @crlf VARCHAR(10) = CHAR(10);
97-
DECLARE @cts DATETIME = CURRENT_TIMESTAMP;
116+
DECLARE @cts DATETIME2(7) = CURRENT_TIMESTAMP;
98117
DECLARE @r INT = 0;
99-
DECLARE @handle VARBINARY(64);
100-
DECLARE @min INT;
101-
DECLARE @avg INT;
102-
DECLARE @max INT;
118+
DECLARE @min BIGINT;
119+
DECLARE @avg BIGINT;
120+
DECLARE @max BIGINT;
103121
DECLARE @median REAL;
104122
DECLARE @plan_handle VARBINARY(64);
105-
DECLARE @rts DATETIME;
123+
DECLARE @rts DATETIME2(7);
124+
DECLARE @finishTime DATETIME2(7);
125+
DECLARE @duration INT;
126+
106127
DECLARE @t TABLE (
107-
StartTimeStamp DATETIME2,
108-
RunTimeStamp DATETIME2,
109-
FinishTimeStamp DATETIME2,
110-
TsqlStatement NVARCHAR(MAX),
111-
ClearCache BIT
128+
StartTimeStamp DATETIME2(7)
129+
, RunTimeStamp DATETIME2(7)
130+
, FinishTimeStamp DATETIME2(7)
131+
, Duration BIGINT
132+
, TsqlStatement NVARCHAR(MAX)
133+
, ClearCache BIT
134+
, PrintStepInfo BIT
135+
, DurationAccuracy VARCHAR(10)
112136
);
113137

114-
PRINT('Benchmark started at ' + CONVERT(VARCHAR(23), CURRENT_TIMESTAMP, 121));
138+
PRINT('Benchmark started at ' + CONVERT(VARCHAR(27), CAST(CURRENT_TIMESTAMPASDATETIME2(7)), 121));
115139

116140
WHILE @r < @numberOfExecution
117141
BEGIN
118142
SET @r = @r + 1;
119-
SET @rts = CURRENT_TIMESTAMP;
143+
SET @rts = CAST(CURRENT_TIMESTAMPASDATETIME2(7));
120144

121145
IF @clearCache = 1
122146
BEGIN
123-
SELECT @handle = plan_handle
147+
SELECT @plan_handle = plan_handle
124148
FROM sys.dm_exec_cached_plans
125149
CROSS APPLY sys.dm_exec_sql_text(plan_handle)
126-
WHERE [text] LIKE @tsqlStatement;
150+
WHERE [text] LIKE @tsqlStatement;-- LIKE instead = (equal) because = ignoring trailing spaces
127151

128-
IF @handle IS NOT NULL DBCC FREEPROCCACHE (@handle);
152+
IF @plan_handle IS NOT NULL DBCC FREEPROCCACHE (@plan_handle);
129153
END;
130154

131155
EXECUTE sp_executesql @tsqlStatement;
132156

133-
IF @printStepInfo = 1
134-
PRINT (
135-
'Run ' + CASE WHEN @r < 10 THEN ' ' + CAST(@r AS VARCHAR(30))
136-
WHEN @r < 100 THEN ' ' + CAST(@r AS VARCHAR(30))
137-
ELSE CAST(@r AS VARCHAR(30))
138-
END +
139-
', start: ' + CONVERT(VARCHAR(23), @rts, 121) +
140-
', finish: ' + CONVERT(VARCHAR(23), CURRENT_TIMESTAMP, 121) +
141-
', duration: ' + CAST(DATEDIFF(ms, @rts, CURRENT_TIMESTAMP) AS VARCHAR(MAX)) + 'ms.'
142-
);
157+
SET @finishTime = CAST(CURRENT_TIMESTAMP AS DATETIME2(7));
158+
SET @duration = CASE WHEN @durationAccuracy = 'ns' THEN CAST(DATEDIFF(ns, @rts, @finishTime) AS INT)
159+
WHEN @durationAccuracy = 'mcs' THEN CAST(DATEDIFF(mcs, @rts, @finishTime) AS INT)
160+
WHEN @durationAccuracy = 'ms' THEN CAST(DATEDIFF(ms, @rts, @finishTime) AS INT)
161+
WHEN @durationAccuracy = 'ss' THEN CAST(DATEDIFF(ss, @rts, @finishTime) AS INT)
162+
WHEN @durationAccuracy = 's' THEN CAST(DATEDIFF(s, @rts, @finishTime) AS INT)
163+
WHEN @durationAccuracy = 'mi' THEN CAST(DATEDIFF(mi, @rts, @finishTime) AS INT)
164+
WHEN @durationAccuracy = 'n' THEN CAST(DATEDIFF(n, @rts, @finishTime) AS INT)
165+
WHEN @durationAccuracy = 'hh' THEN CAST(DATEDIFF(hh, @rts, @finishTime) AS INT)
166+
WHEN @durationAccuracy = 'wk' THEN CAST(DATEDIFF(wk, @rts, @finishTime) AS INT)
167+
WHEN @durationAccuracy = 'ww' THEN CAST(DATEDIFF(ww, @rts, @finishTime) AS INT)
168+
WHEN @durationAccuracy = 'dd' THEN CAST(DATEDIFF(dd, @rts, @finishTime) AS INT)
169+
WHEN @durationAccuracy = 'd' THEN CAST(DATEDIFF(d, @rts, @finishTime) AS INT)
170+
ELSE 0
171+
END;
143172

144173
INSERT @t (
145174
StartTimeStamp
146175
, RunTimeStamp
147176
, FinishTimeStamp
177+
, Duration
148178
, TsqlStatement
149179
, ClearCache
180+
, PrintStepInfo
181+
, DurationAccuracy
150182
)
151183
VALUES (
152184
@cts
153185
, @rts
154-
, CURRENT_TIMESTAMP
186+
, @finishTime
187+
, @duration
155188
, @tsqlStatement
156189
, @clearCache
190+
, @printStepInfo
191+
, @durationAccuracy
157192
);
193+
194+
IF @printStepInfo = 1
195+
PRINT (
196+
'Run ' + CASE WHEN @r < 10 THEN ' ' + CAST(@r AS VARCHAR(30))
197+
WHEN @r < 100 THEN ' ' + CAST(@r AS VARCHAR(30))
198+
ELSE CAST(@r AS VARCHAR(30))
199+
END +
200+
', start: ' + CONVERT(VARCHAR(27), @rts, 121) +
201+
', finish: ' + CONVERT(VARCHAR(27), CAST(CURRENT_TIMESTAMP AS DATETIME2(7)), 121) +
202+
', duration: ' + CAST(@duration AS VARCHAR(100)) + @durationAccuracy + '.'
203+
);
204+
158205
END;
159206

160-
SELECT @min = MIN(DATEDIFF(ms, RunTimeStamp, FinishTimeStamp))
161-
, @avg = AVG(DATEDIFF(ms, RunTimeStamp, FinishTimeStamp))
162-
, @max = MAX(DATEDIFF(ms, RunTimeStamp, FinishTimeStamp))
207+
SELECT @min = MIN(Duration)
208+
, @avg = AVG(Duration)
209+
, @max = MAX(Duration)
163210
FROM @t;
164211

165212
IF @calcMedian = 1
166213
BEGIN
167214
SELECT @median = (
168-
(SELECT MAX(TMIN) FROM
169-
(SELECT TOP 50 PERCENT DATEDIFF(ms, RunTimeStamp, FinishTimeStamp) AS TMIN FROM @t ORDER BY TMIN) AS BottomHalf)
170-
+
171-
(SELECT MIN(TMAX) FROM
172-
(SELECT TOP 50 PERCENT DATEDIFF(ms, RunTimeStamp, FinishTimeStamp) AS TMAX FROM @t ORDER BY TMAX DESC) AS TopHalf)
173-
) / 2.0;
215+
(SELECT MAX(TMIN) FROM
216+
(SELECT TOP(50) PERCENT
217+
CASE WHEN @durationAccuracy = 'ns' THEN CAST(DATEDIFF(ns, RunTimeStamp, FinishTimeStamp) AS INT)
218+
WHEN @durationAccuracy = 'mcs' THEN CAST(DATEDIFF(mcs, RunTimeStamp, FinishTimeStamp) AS INT)
219+
WHEN @durationAccuracy = 'ms' THEN CAST(DATEDIFF(ms, RunTimeStamp, FinishTimeStamp) AS INT)
220+
WHEN @durationAccuracy = 'ss' THEN CAST(DATEDIFF(ss, RunTimeStamp, FinishTimeStamp) AS INT)
221+
WHEN @durationAccuracy = 's' THEN CAST(DATEDIFF(s, RunTimeStamp, FinishTimeStamp) AS INT)
222+
WHEN @durationAccuracy = 'mi' THEN CAST(DATEDIFF(mi, RunTimeStamp, FinishTimeStamp) AS INT)
223+
WHEN @durationAccuracy = 'n' THEN CAST(DATEDIFF(n, RunTimeStamp, FinishTimeStamp) AS INT)
224+
WHEN @durationAccuracy = 'hh' THEN CAST(DATEDIFF(hh, RunTimeStamp, FinishTimeStamp) AS INT)
225+
WHEN @durationAccuracy = 'wk' THEN CAST(DATEDIFF(wk, RunTimeStamp, FinishTimeStamp) AS INT)
226+
WHEN @durationAccuracy = 'ww' THEN CAST(DATEDIFF(ww, RunTimeStamp, FinishTimeStamp) AS INT)
227+
WHEN @durationAccuracy = 'dd' THEN CAST(DATEDIFF(dd, RunTimeStamp, FinishTimeStamp) AS INT)
228+
WHEN @durationAccuracy = 'd' THEN CAST(DATEDIFF(d, RunTimeStamp, FinishTimeStamp) AS INT)
229+
ELSE 0
230+
END AS TMIN
231+
FROM @t
232+
ORDER BY TMIN
233+
) AS BottomHalf
234+
)
235+
+
236+
(SELECT MIN(TMAX) FROM
237+
(SELECT TOP 50 PERCENT
238+
CASE WHEN @durationAccuracy = 'ns' THEN CAST(DATEDIFF(ns, RunTimeStamp, FinishTimeStamp) AS INT)
239+
WHEN @durationAccuracy = 'mcs' THEN CAST(DATEDIFF(mcs, RunTimeStamp, FinishTimeStamp) AS INT)
240+
WHEN @durationAccuracy = 'ms' THEN CAST(DATEDIFF(ms, RunTimeStamp, FinishTimeStamp) AS INT)
241+
WHEN @durationAccuracy = 'ss' THEN CAST(DATEDIFF(ss, RunTimeStamp, FinishTimeStamp) AS INT)
242+
WHEN @durationAccuracy = 's' THEN CAST(DATEDIFF(s, RunTimeStamp, FinishTimeStamp) AS INT)
243+
WHEN @durationAccuracy = 'mi' THEN CAST(DATEDIFF(mi, RunTimeStamp, FinishTimeStamp) AS INT)
244+
WHEN @durationAccuracy = 'n' THEN CAST(DATEDIFF(n, RunTimeStamp, FinishTimeStamp) AS INT)
245+
WHEN @durationAccuracy = 'hh' THEN CAST(DATEDIFF(hh, RunTimeStamp, FinishTimeStamp) AS INT)
246+
WHEN @durationAccuracy = 'wk' THEN CAST(DATEDIFF(wk, RunTimeStamp, FinishTimeStamp) AS INT)
247+
WHEN @durationAccuracy = 'ww' THEN CAST(DATEDIFF(ww, RunTimeStamp, FinishTimeStamp) AS INT)
248+
WHEN @durationAccuracy = 'dd' THEN CAST(DATEDIFF(dd, RunTimeStamp, FinishTimeStamp) AS INT)
249+
WHEN @durationAccuracy = 'd' THEN CAST(DATEDIFF(d, RunTimeStamp, FinishTimeStamp) AS INT)
250+
ELSE 0
251+
END AS TMAX
252+
FROM @t
253+
ORDER BY TMAX DESC
254+
) AS TopHalf
255+
)
256+
) / 2.0;
174257
END;
175258

176259
PRINT (
177-
'Min: ' + CAST(@min AS VARCHAR(30)) +
178-
'ms, Max: ' + CAST(@max AS VARCHAR(30)) +
179-
'ms, Average: ' + CAST(@avg AS VARCHAR(30)) +
180-
CASE WHEN @calcMedian = 1 THEN 'ms, Median: ' + CAST(@median AS VARCHAR(30)) ELSE '' END +
181-
'ms.'+@crlf +
260+
'Min: ' + CAST(@min AS VARCHAR(30))+ @durationAccuracy +
261+
', Max: ' + CAST(@max AS VARCHAR(30))+ @durationAccuracy +
262+
', Average: ' + CAST(@avg AS VARCHAR(30))+ @durationAccuracy +
263+
CASE WHEN @calcMedian = 1 THEN ', Median: ' + CAST(@median AS VARCHAR(30))+ @durationAccuracy ELSE '' END +
264+
@crlf +
182265
'Benchmark finished at ' + CONVERT(VARCHAR(23), CURRENT_TIMESTAMP, 121) + '.'
183266
);
184267

185-
186268
IF @saveResults = 1
187-
IF OBJECT_ID('.[dbo].[BenchmarkTSQL]', 'U') IS NULL
188-
SELECT * INTO dbo.BenchmarkTSQL FROM @t
269+
IF OBJECT_ID('dbo.BenchmarkTSQL', 'U') IS NULL
270+
BEGIN
271+
CREATE TABLE dbo.BenchmarkTSQL(
272+
BenchmarkTSQLID INT IDENTITY
273+
, StartTimeStamp DATETIME2(7)
274+
, RunTimeStamp DATETIME2(7)
275+
, FinishTimeStamp DATETIME2(7)
276+
, Duration BIGINT
277+
, TsqlStatement NVARCHAR(MAX)
278+
, ClearCache BIT
279+
, PrintStepInfo BIT
280+
, DurationAccuracy VARCHAR(10)
281+
);
282+
INSERT INTO dbo.BenchmarkTSQL(
283+
StartTimeStamp
284+
, RunTimeStamp
285+
, FinishTimeStamp
286+
, Duration
287+
, TsqlStatement
288+
, ClearCache
289+
, PrintStepInfo
290+
, DurationAccuracy
291+
)
292+
SELECT StartTimeStamp
293+
, RunTimeStamp
294+
, FinishTimeStamp
295+
, Duration
296+
, TsqlStatement
297+
, ClearCache
298+
, PrintStepInfo
299+
, DurationAccuracy
300+
FROM @t;
301+
END
189302
ELSE
190303
INSERT INTO dbo.BenchmarkTSQL SELECT * FROM @t;
191304

192305
SET NOCOUNT ON;
193306
END TRY
194307

195308
BEGIN CATCH
196-
PRINT 'Error: ' + CONVERT(varchar(50), ERROR_NUMBER()) +
309+
PRINT 'Error: ' + CONVERT(varchar(50), ERROR_NUMBER()) +
197310
', Severity: ' + CONVERT(varchar(5), ERROR_SEVERITY()) +
198-
', State: ' + CONVERT(varchar(5), ERROR_STATE()) +
199-
', Procedure: ' + ISNULL(ERROR_PROCEDURE(), '-') +
200-
', Line: ' + CONVERT(varchar(5), ERROR_LINE()) +
311+
', State: ' + CONVERT(varchar(5), ERROR_STATE()) +
312+
', Procedure: ' + ISNULL(ERROR_PROCEDURE(), '-') +
313+
', Line: ' + CONVERT(varchar(5), ERROR_LINE()) +
201314
', User name: ' + CONVERT(sysname, CURRENT_USER);
202315
PRINT ERROR_MESSAGE();
203316
END CATCH;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /