TSQL Challenge 13 - Load Testing



We tested the solutions that passed the Logic Testing with a very large set of data. Fabien, a very active supporter of TSQL Challenges has came up with a script that generates 1 million rows.

The Load Testing involves running each solutions three times with a large data set and collecting the performance statistics. Because of the complex nature of this challenge, it was taking hours and hours to run the tests with 1 million rows. So we decided to use a subset of the data and ended up testing the solutions with only 100,000 rows.

Here is the data used for the load testing of TSQL Challenge #13

-- Topic    : TSQL Challenge #13 - Create a one million rows table to test the query
-- Date     : 04 Sep 2009
-- Author   : Fabien "Waldar" Contaminard
-- Location : Paris
-- Email    : http://scr.im/waldar


-- Create Table
CREATE TABLE dbo.TC13
(
    InvID       INT IDENTITY ,
    BatchNumber INT          ,
    InvoiceNumber INT          ,
    VisitDate   SMALLDATETIME,
    Amount      MONEY
);

-- Variables
DECLARE @MAXROWSTABLE AS INT ;
SET @MAXROWSTABLE = 1e6;

-- Query
WITH Fill(Id, Nb, Tot, CT)

-- Creating the Batches with the number of rows they will hold
AS
(

-- I'm using Timestamp milliseconds to create random numbers
SELECT
    1,
    FLOOR(DATEPART(ms, CURRENT_TIMESTAMP)/10)+1,
-- I'm using ms divided by ten +1 for the number of batch rows to be somewhere between 1 and 100
    FLOOR(DATEPART(ms, CURRENT_TIMESTAMP)/10)+1,
    CURRENT_TIMESTAMP
UNION ALL
SELECT
    Id + 1,
    FLOOR(DATEPART(ms, CT + Tot*24.0000/60/60/1000)/10),
    FLOOR(DATEPART(ms, CT + Tot*24.0000/60/60/1000)/10) + Tot,
    CURRENT_TIMESTAMP + Tot*24.0000/60/60/1000
FROM Fill
WHERE
    Tot < @MAXROWSTABLE
),
     Fill2(Id1, Id2, Nb, Tot1, Tot2, CT)
-- Creating the Invoices with the number of rows they will hold
AS
(
SELECT
    Id, 1,
-- I'm using ms divided by one hundred +1 for the number of invoice rows to be somewhere between 1 and 10
    FLOOR(DATEPART(ms, CT)/100)+1,
-- This case is for the final batch who can be beyond the expected number of rows
    CASE WHEN Tot > @MAXROWSTABLE THEN Nb - Tot + @MAXROWSTABLE ELSE Nb END,
    FLOOR(DATEPART(ms, CT)/100)+1,
    CT
FROM Fill
UNION ALL
SELECT
    F2.Id1, 
    F2.Id2 + 1,
    FLOOR(DATEPART(ms, F2.CT + F2.Tot2*24.0000/60/60/58)/100)+1,
    F2.Tot1,
    FLOOR(DATEPART(ms, F2.CT + F2.Tot2*24.0000/60/60/58)/100)+1 + F2.Tot2,
    F2.CT + F2.Tot2*24.0000/60/60/58
FROM
    Fill AS F1
    INNER JOIN Fill2 AS F2
      ON F2.Id1 = F1.Id
WHERE
    F2.Tot2 < F2.Tot1
),
     Fact(Id)
-- I'm using a ten rows table to generate the table according the the invoice rows
AS
(
SELECT 1
UNION ALL
SELECT Id + 1 FROM Fact 
WHERE Id < 10
)
INSERT INTO TC13 (BatchNumber, InvoiceNumber, VisitDate, Amount)
SELECT TOP 100000 /*Reduced the number of rows to 100,000*/
    1000000 + F2.Id1 AS BatchNumber,
    DENSE_RANK() OVER(ORDER BY F2.Id1 + F2.Id2 / 100.0 ASC) AS InvoiceNumber,
    CONVERT(smalldatetime, '20090101', 112) + FA.Id - 1 AS VisitDate,
    1 AS Amount
FROM
    Fill2 AS F2
    INNER JOIN Fact AS FA
-- This case is for the final invoice of each batch who can be beyond the expected number of rows
      ON FA.Id <= CASE WHEN F2.Tot2 > F2.Tot1 THEN F2.Nb + F2.Tot1 - F2.Tot2 Else F2.Nb END
ORDER BY
    F2.Id1 ASC,
    F2.Id2 ASC,
    FA.Id ASC

-- For 1000000 rows there's a lot of recursion
OPTION (MAXRECURSION 32000);

-- Adding PK and Index, fasten my solution query by 20%
ALTER TABLE dbo.TC13
ADD CONSTRAINT PK_TC13 PRIMARY KEY (InvID);

CREATE INDEX I_TC13_Batch_Invoice
ON dbo.TC13 (BatchNumber, InvoiceNumber);

You can find the results of the "Load Testing" here.