The SP Benchmark code

 

All benchmarks are using the Northwind database on SqlServer. Northwind is shipped with every SqlServer installation as also the MSDE installation.

The Stored Procedure.
The stored procedure used is the following. Add this one to the Northwind database.

CREATE PROCEDURE pr_Orders_SelectMultiWCustomerEmployeeShipper
	@sCustomerID nchar(5),
	@iEmployeeID int,
	@iShipperID int
AS
SELECT 	*
FROM	Orders
WHERE	CustomerID = COALESCE(@sCustomerID, CustomerID)
	AND
	EmployeeID = COALESCE(@iEmployeeID, EmployeeID)
	AND
	ShipVia = COALESCE(@iShipperID, ShipVia)

The C# code.
The following code was used to run the benchmarks. There are two routines, one tests the dynamic query, the other tests the stored procedure. Call either one to see how they are performing. You have to change the server name in the connection string constant.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Text;

namespace Benchmarker
{
    public class Benchmarker
    {
        private const int   iAMOUNT_LOOPS=10000;
        private const string sEXAMPLE_CUSTOMERID="CHOPS";
        private const string sCONNECTION_STRING="data source=MyServer;initial catalog=Northwind;integrated security=SSPI;persist security info=False;packet size=4096";
        private const bool bPRINT_ROWCOUNT=false;

        public void Start()
        {
            BenchmarkSelfBuildQuery();
            //BenchmarkStoredProcedure();
            Console.ReadLine();
        }

        private void BenchmarkSelfBuildQuery()
        {
            Random rdmGenerator = new Random(unchecked((int)DateTime.Now.Ticks)); 

            Console.WriteLine("Dynamic query benchmark");
            DateTime daStartTime = DateTime.Now;
            Console.WriteLine("Benchmark started on: {0}.", daStartTime);
            int iMaxAmountRowsRetrieved = 0;
            for(int i=0;i<iAMOUNT_LOOPS;i++)
            {
                SqlString sCustomerID = SqlString.Null;
                SqlInt32 iEmployeeID = SqlInt32.Null;
                SqlInt32 iShipperID = SqlInt32.Null;

                // determine random value to check which values should be null. 0 means no value, 1 means shipper is NULL, 
                // 2 means shipper and employee are NULL, 3 means all are NULL
                int iNullValueDeterminer = rdmGenerator.Next(4);
                string sWhereClause="";
                SqlConnection scoCon = new SqlConnection(sCONNECTION_STRING);
                SqlCommand scmCom = new SqlCommand();
                SqlDataAdapter sdaAdapter = new SqlDataAdapter(scmCom);

                switch(iNullValueDeterminer)
                {
                    case 0:
                        // All parameters have a value
                        sCustomerID = sEXAMPLE_CUSTOMERID;
                        iEmployeeID = rdmGenerator.Next(1,10);
                        iShipperID = rdmGenerator.Next(1,4);
                        sWhereClause = " WHERE CustomerID=@sCustomerID AND EmployeeID=@iEmployeeID AND ShipVia=@iShipperID";
                        // add parameters
                        scmCom.Parameters.Add(new SqlParameter("@sCustomerID", SqlDbType.NChar, 5, ParameterDirection.Input, false, 0, 0, "", DataRowVersion.Current, sCustomerID));
                        scmCom.Parameters.Add(new SqlParameter("@iEmployeeID", SqlDbType.Int, 0, ParameterDirection.Input, false, 10, 0, "", DataRowVersion.Current, iEmployeeID));
                        scmCom.Parameters.Add(new SqlParameter("@iShipperID", SqlDbType.Int, 0, ParameterDirection.Input, false, 10, 0, "", DataRowVersion.Current, iShipperID));
                        break;
                    case 1:
                        sCustomerID = sEXAMPLE_CUSTOMERID;
                        iEmployeeID = rdmGenerator.Next(1,10);
                        sWhereClause = " WHERE CustomerID=@sCustomerID AND EmployeeID=@iEmployeeID";
                        // add parameters
                        scmCom.Parameters.Add(new SqlParameter("@sCustomerID", SqlDbType.NChar, 5, ParameterDirection.Input, false, 0, 0, "", DataRowVersion.Current, sCustomerID));
                        scmCom.Parameters.Add(new SqlParameter("@iEmployeeID", SqlDbType.Int, 0, ParameterDirection.Input, false, 10, 0, "", DataRowVersion.Current, iEmployeeID));
                        break;
                    case 2:
                        sCustomerID = sEXAMPLE_CUSTOMERID;
                        sWhereClause = " WHERE CustomerID=@sCustomerID";
                        // add parameters
                        scmCom.Parameters.Add(new SqlParameter("@sCustomerID", SqlDbType.NChar, 5, ParameterDirection.Input, false, 0, 0, "", DataRowVersion.Current, sCustomerID));
                        break;
                    case 3:
                        // do nothing, they're already NULL;
                        break;
                }

                // create the query
                StringBuilder sbQuery = new StringBuilder("SELECT * FROM Orders");
                sbQuery.Append(sWhereClause);

                scmCom.CommandText = sbQuery.ToString();
                scmCom.Connection = scoCon;

                // run the query
                DataTable dt = new DataTable("Test");
                sdaAdapter.Fill(dt);
                if(bPRINT_ROWCOUNT)
                {
                    Console.WriteLine("Run no.: {0}", i);
                    Console.WriteLine("Amount of rows returned: {0}", dt.Rows.Count);
                }

                if(dt.Rows.Count > iMaxAmountRowsRetrieved)
                {
                    iMaxAmountRowsRetrieved=dt.Rows.Count;
                }

                if((i%100)==0)
                {
                    Console.WriteLine("Amount of runs done: {0}", i);
                }
            }
            DateTime daEndTime = DateTime.Now;

            Console.WriteLine("Benchmark ended on: {0}.\nTotal time: {1}.", daEndTime, (daEndTime - daStartTime));
            Console.WriteLine("Amount of runs: {0}. Max. amount of rows retrieved: {1}", iAMOUNT_LOOPS, iMaxAmountRowsRetrieved);
        }

        private void BenchmarkStoredProcedure()
        {
            Random rdmGenerator = new Random(unchecked((int)DateTime.Now.Ticks)); 

            Console.WriteLine("Stored procedure benchmark");
            DateTime daStartTime = DateTime.Now;
            Console.WriteLine("Benchmark started on: {0}.", daStartTime);
            int iMaxAmountRowsRetrieved = 0;
            for(int i=0;i<iAMOUNT_LOOPS;i++)
            {
                SqlString sCustomerID = SqlString.Null;
                SqlInt32 iEmployeeID = SqlInt32.Null;
                SqlInt32 iShipperID = SqlInt32.Null;

                // determine random value to check which values should be null. 0 means no value, 1 means shipper is NULL, 
                // 2 means shipper and employee are NULL, 3 means all are NULL
                int iNullValueDeterminer = rdmGenerator.Next(4);
                SqlConnection scoCon = new SqlConnection(sCONNECTION_STRING);
                SqlCommand scmCom = new SqlCommand("pr_Orders_SelectMultiWCustomerEmployeeShipper", scoCon);
                scmCom.CommandType = CommandType.StoredProcedure;
                SqlDataAdapter sdaAdapter = new SqlDataAdapter(scmCom);

                scmCom.Parameters.Add(new SqlParameter("@sCustomerID", SqlDbType.NChar, 5, ParameterDirection.Input, false, 0, 0, "", DataRowVersion.Current, sCustomerID));
                scmCom.Parameters.Add(new SqlParameter("@iEmployeeID", SqlDbType.Int, 0, ParameterDirection.Input, false, 10, 0, "", DataRowVersion.Current, iEmployeeID));
                scmCom.Parameters.Add(new SqlParameter("@iShipperID", SqlDbType.Int, 0, ParameterDirection.Input, false, 10, 0, "", DataRowVersion.Current, iShipperID));

                switch(iNullValueDeterminer)
                {
                    case 0:
                        // All parameters have a value
                        sCustomerID = sEXAMPLE_CUSTOMERID;
                        iEmployeeID = rdmGenerator.Next(1,10);
                        iShipperID = rdmGenerator.Next(1,4);
                        break;
                    case 1:
                        sCustomerID = sEXAMPLE_CUSTOMERID;
                        iEmployeeID = rdmGenerator.Next(1,10);
                        break;
                    case 2:
                        sCustomerID = sEXAMPLE_CUSTOMERID;
                        break;
                    case 3:
                        // do nothing, they're already NULL;
                        break;
                }

                scmCom.Parameters["@sCustomerID"].Value = sCustomerID;
                scmCom.Parameters["@iEmployeeID"].Value = iEmployeeID;
                scmCom.Parameters["@iShipperID"].Value = iShipperID;

                // run the query
                DataTable dt = new DataTable("Test");
                sdaAdapter.Fill(dt);

                if(bPRINT_ROWCOUNT)
                {
                    Console.WriteLine("Run no.: {0}", i);
                    Console.WriteLine("Amount of rows returned: {0}", dt.Rows.Count);
                }

                if(dt.Rows.Count > iMaxAmountRowsRetrieved)
                {
                    iMaxAmountRowsRetrieved=dt.Rows.Count;
                }

                if((i%100)==0)
                {
                    Console.WriteLine("Amount of runs done: {0}", i);
                }
            }
            DateTime daEndTime = DateTime.Now;

            Console.WriteLine("Benchmark ended on: {0}.\nTotal time: {1}.", daEndTime, (daEndTime - daStartTime));
            Console.WriteLine("Amount of runs: {0}. Max. amount of rows retrieved: {1}", iAMOUNT_LOOPS, iMaxAmountRowsRetrieved);
        }
    }


    /// <summary>
    /// Starts up a test
    /// </summary>
    class Startup
    {
        [STAThread]
        static void Main(string[] args)
        {
            Benchmarker bm = new Benchmarker();
            bm.Start();
        }
    }
}

1 Comment

  • Would you happen to have the VB version of the

    &quot;The SP Benchmark code&quot;. I am new to VB.NET and I am trying to take your advice and go with the Parmeterized Dyanamic Query rather than Stored Procedures.

    Regards,

    Majid Haeri

    majid_97@yahoo.com

Comments have been disabled for this content.