T-SQL & Development

How to Fake Load Tests with SQLQueryStress

Load testing – real, serious load testing – is hard.

In a perfect world, you want to exactly simulate the kinds of queries that the end users will be throwing at your SQL Server. However, in the words of a timeless philosopher, ain’t nobody got time for that.

Instead, let’s use the neato open source tool SqlQueryStress (latest exe) to fake it. This is an oldie but goldie app that will run any one query thousands of times (or more) from dozens of sessions (or more), all from the comfort of your desktop:

SQLQueryStress in action
SQLQueryStress in action

After you install it on your desktop (or a VM in the data center, whatever, just not the SQL Server you’re trying to load test), click the Database button to set up your connection string. In this instance, I’m pointing it at one of my Availability Groups, using Windows authentication. As soon as I set the server and auth methods, the database list gets populated so I can set my default database:

Setting up the connection string
Setting up the connection string

Then it’s time to pick the query to run.

But you want to test more than one query at a time, right? You want to test a variety of different queries running all at once.

Rather than calling a single query, call a “shell” stored procedure that runs other queries. Here’s how it works:

  1. Declare an integer, and set it to a random number
  2. Based on the mod of that number, run a stored procedure
    (for example, if it’s divisible by 3, run sp_C,
    else if it’s divisible by 2, run sp_B,
    else run sp_A.)

Since SQLQueryStress will be calling this stored proc dozens of times at once, you’ll end up with a variety of different queries running simultaneously.

Let’s get a little more complex. Here’s what mine looks like for one of my query tuning demos:

WITH RECOMPILE – I use this because I don’t want the usp_RandomQ stored procedure to show up in my execution plan stats. The work involved with building this execution plan isn’t significant, and it won’t be the largest part of my workload. (Oh, I wish it were.) All of the stored procs it calls will still show up in the plan cache, though.

@Id parameter – note that some of the stored procs take an @Id. For example, the stored proc GetBadgesDetails takes @Id, and uses that to look up a particular badge number’s details. This is handy because each of my stored procedures don’t have random number generators – they’re designed to mimic more real-world stored procs that have input values. If you wanted to get really fancy and test procs with lots of parameters, you’ll need to generate those in usp_RandomQ. You don’t want to hard-code the same values because then that relevant table data will end up getting cached in memory.

@@SPID – some of my workload queries simulate blocking. Due to the wonders of random number generation and very fast queries, if a blocking chain starts on any two sessions, then eventually the rest of the sessions will also call the stored proc that’s susceptible to blocking. After a few seconds, the only symptom my server will have is blocking – and that’s no fun. Instead, by using @@SPID %2 before calling GetVotesDetails (which gets blocked in my scenario), I make sure that no more than half of my sessions will get blocked at once.

The end result is beautiful – well, at least if you want something that looks like a production server getting hammered with all kinds of different queries:

AAAAAHHHH, THE SERVER'S ON FIRE
AAAAAHHHH, THE SERVER’S ON FIRE

I love using this quick-load-generation technique in our performance tuning classes. It’s a great way to show a server that looks like home, and gets students to figure out which queries are causing problems – and which ones are just harmless background noise.

Go get SQLQueryStress now, and get the usp_RandomQ scripts for the top queries from Data.StackExchange.com that hit the Stack Overflow database.

Free, 3× a week

Get my new posts by email

Three posts a week, plus a Monday roundup of the best database news from around the web.

45 comments

  1. Hi Brent, Can you elaborate little more on your true skills like menu advice,interpretive dancing… Well I suppose your hidden true skills are Database Consulting,Correcting Mis-Interpreted SQL Query Optimizer

    Cheers,
    Basava

    1. I think I figured it out myself. Just Exited the tool and looks like that terminated all associated sessions.

  2. Hi, I am trying to simulate 1000 concurrent users, but Im unable to run more than 4-6 instances of the sqlquerystress tool from my machine. And I dont have enough machines to simulate 1000 users like this. Are there any other tools I could use for testing concurrent users?

  3. I was not able to simulate many connections thru ‘SQLQuery stress’. I did paste above query in sql query stress box with 50 connections but only show 1.

    Query:
    CREATE PROCEDURE [dbo].[usp_RandomQ] WITH RECOMPILE
    AS
    SET NOCOUNT ON
    DECLARE @Id INT
    SELECT @Id = CAST(RAND() * 10000000 AS INT)
    IF @Id % 7 = 0
    EXEC dbo.Refresh_ReportByVoteType
    ELSE IF @Id % 6 = 0
    EXEC dbo.Refresh_ReportByBadge
    ELSE IF @Id % 5 = 0
    EXEC dbo.GetBadgesDetails @Id
    ELSE IF @Id % 4 = 0
    EXEC dbo.GetCommentsDetails @Id
    ELSE IF @Id % 3 = 0
    EXEC dbo.GetPostsDetails @Id
    ELSE IF @Id % 2 = 0 AND @@SPID % 2 = 0
    EXEC dbo.GetUsersDetails @Id
    ELSE
    EXEC dbo.GetVotesDetails @Id
    GO

    1. Dan – don’t put that query in SQLQueryStress. That query creates the stored procedure. Create the procedure (and the underlying stored procs as described in the post), and then in SQLQueryStress, just run the stored procedure with EXEC usp_RandomQ.

  4. Can I run this against the AdventureWorks sample database? I need to simulate SQL load without having a real database to query.

    1. Brian – sure, in the sense that you can write your own queries and build your own load test with it. It’s a set of tools – it’s not a prebuilt house. (I’m giving you a house above.)

  5. is it a bad practive to use this on production server ? should we limited this usage on tes environnement that have different server configuration than in production ?

  6. If your still hunting for the tool after going to all of these links. I finally found it in the Microsoft App Store.

  7. I am not able to connect to my local database. When I clear Default Database and test connection, it is successful otherwise not.

  8. Very powerful concept. So much easier encapsulating the randomness in TSQL / usp_RandomQ sp versus doing it client side.

  9. because in “WorkloadTools” its visible only the query “usp_RandomQ …” i wrote this powershell – Script:

    Add-PSSnapin SqlServerCmdletSnapin100
    Add-PSSnapin SqlServerProviderSnapin100

    $timeout = New-TimeSpan -Minutes 10
    $endTime = (Get-Date).Add($timeout)
    do {
    $rndv=get-random 10000000
    if ($rndv % 12 -eq 0) {invoke-sqlcmd -server d10t105a “EXEC dbo.usp_Q3160 $rndv”}
    elseif ($rndv % 11 -eq 0) {invoke-sqlcmd -server d10t105a “EXEC dbo.usp_Q36660 $rndv”}
    elseif ($rndv % 10 -eq 0) {invoke-sqlcmd -server d10t105a “EXEC dbo.usp_Q466 $rndv”}
    #elseif ($rndv % 9 -eq 0) {invoke-sqlcmd -server d10t105a “EXEC dbo.usp_Q6627 $rndv”}
    elseif ($rndv % 8 -eq 0) {invoke-sqlcmd -server d10t105a “EXEC dbo.usp_Q6772 $rndv”}
    elseif ($rndv % 7 -eq 0) {invoke-sqlcmd -server d10t105a “EXEC dbo.usp_Q6856 $rndv”}
    elseif ($rndv % 6 -eq 0) {invoke-sqlcmd -server d10t105a “EXEC dbo.usp_Q7521 $rndv”}
    elseif ($rndv % 5 -eq 0) {invoke-sqlcmd -server d10t105a “EXEC dbo.usp_Q8116 $rndv”}
    elseif ($rndv % 4 -eq 0) {invoke-sqlcmd -server d10t105a “EXEC dbo.usp_Q947 $rndv”}
    elseif ($rndv % 3 -eq 0) {invoke-sqlcmd -server d10t105a “EXEC dbo.usp_Q949 $rndv”}
    elseif ($rndv % 2 -eq 0) {invoke-sqlcmd -server d10t105a “EXEC dbo.usp_Q952 $rndv”}
    else {invoke-sqlcmd -server d10t105a “EXEC dbo.usp_Q975 $rndv”}
    }
    until ((Get-Date) -gt $endTime)

    But the drawback is, that you must generate Workload without the features of SQLquerystress…

Leave a comment

Your email address will not be published. Required fields are marked *

Email me about new comments: