Click here to Skip to main content
Click here to Skip to main content

Stored Procedures DO NOT increase performance

By , 2 Oct 2012
 

Table of contents

Introduction

I assume that you have clicked on this article / blog because you are an awesome fan of stored procedures (like me) and you cannot see these kind of loose statements. My sincere suggestion would be to read this article once, give a thought on the experiments, and then the comments section is always there to throw bricks at me.

Stored Procedures are precompiled so they are faster

Ask any one why he prefers stored procedures as compared to inline queries and most will reply back with a standard statement:

“Stored procedures are precompiled and cached so the performance is much better.”

Let me just explain the above sentence more diagrammatically. When we fire SQL for the first time, three things happen:

  • The SQL syntax is checked for any errors.
  • The best plan is selected to execute the SQL (choice to use clustered index, non-clustered etc.).
  • Finally the SQL is executed.

The above statement states that when you run a stored procedure for the first time it will go through all the above steps and the plan will be cached in-memory. So the next time when the stored procedure is executed it just takes the plan from the cache and executes the same. This increases performance as the first two steps are completely eliminated.

The above statement also says / implies that for inline queries all the above steps are repeated again and again which brings down the performance considerably.

The above explanation was pretty valid and true for older versions of SQL Server, but from 2005 onwards, all SQL statements, irrespective of it’s a SQL coming from inline code or stored procedure or from anywhere else, they are compiled and cached.

OK, now walk your talk

Image from http://www.stegman.com/site/wp-content/uploads/2011/07/Man-walking-rope.jpg

In order prove the above point I did a couple of experiments. I wrote a simple .NET application which makes calls to SQL Server by using both methodologies, i.e., simple inline SQL and stored procedure.

Below is a simple experiment to prove the same.

We have created two scenarios: one which will run a simple inline SQL as shown below. This SQL goes and queries a simple “Users” table to check if a user exists in the database or not.

SqlCommand objCommand = new SqlCommand("Select * from Users where UserName='"
                                        + UserName + "' and Password='"
                                        + Password + "'", objConnection);

In the second scenario the same inline SQL is wrapped in a stored procedure called “sp_login”.

SqlCommand objCommand = new SqlCommand("sp_Login", objConnection);
objCommand.Parameters.Add(new SqlParameter("UserName", UserName));
objCommand.Parameters.Add(new SqlParameter("Password", Password));
objCommand.CommandType = CommandType.StoredProcedure;

Both these SQLs are fired from the application with a profiler running in the background. We capture two events when we ran the profiler: CacheHit and CacheInsert. The CacheInsert event is fired when the plan is inserted in the cache while CacheHit is fired when the plan is used from the cache.

When we ran the experiment with the stored procedure we saw the below results. You can see in the trace below:

CacheInsert” first creates the plan and inserts it into the cache. Once the plan is cached the CacheHit event occurs which means it has taken the plan from the cache rather than recreating it from scratch.

When we ran the experiment with inline SQL we saw similar kinds of results. You can see how the CacheHit event is hit after the CacheInsert event is fired.

Cheater, change the data?

If you see look at the previous experiment, the data is absolutely the same. The time I change the data as shown in the figure below, you can see it’s no longer using the cache, rather creating new cache entries. 

 

Let me go ahead and tweak the ADO.NET code to support parameters as shown below.

SqlCommand objCommand = new SqlCommand(
   "Select * from Users where UserName=@userName and Password=@Password", objConnection);
objCommand.Parameters.AddWithValue("@userName", UserName);
objCommand.Parameters.AddWithValue("@Password", Password);

When I capture the cache events in the profiler it is using the cache. You can see in the below figure how first the cache insert event occurs and after that it always hits the cache for the plan rather than recreating it.

Dynamic SQL and Dynamic SQL

One of the most confusing terminologies people use is Dynamic SQL. Let’s refine this word further. There are two types of dynamic SQL: one is dynamic SQL and the other is parameterized dynamic SQL.

Courtesy: Spiderman 3

Dynamic SQL is of the form as shown below (it can be more dynamic where column names are also built on the fly).

SqlCommand objCommand = new SqlCommand("Select * from Users where UserName='"
                                        + UserName + "' and Password='"
                                        + Password + "'", objConnection);

The above dynamic SQL will probably not use the plan from the cache until auto parameterization helps (http://msdn.microsoft.com/en-us/library/aa175264(v=sql.80).aspx).

If you use parameterized dynamic SQL like below, it will use the SQL plan from the cache as done by stored procedures.

SqlCommand objCommand = new SqlCommand("Select * from Users where UserName=@userName and Password=@Password", objConnection);

objCommand.Parameters.AddWithValue("@userName", UserName);
objCommand.Parameters.AddWithValue("@Password", Password);

In simple words performance of inline parameterized SQL is the same as that of Stored Procedures.

Hmm, what about network traffic?

If you have read so far you must be embarrassed, the way I was when I lost this argument. To counter protect many developers would also argue that network traffic decrease when using stored procedures is less as compared to that for inline SQL.

In simple words if we use stored procedures we just send:

Sp_login 

If we use inline SQL we send the complete SQL which will increase traffic.

'Select * from Users where UserName=@UserName and Password=@Password'

Must be this is a valid point if we are having many Windows apps pounding on one SQL Server. That can lead to a lot of network traffic if there are a lot of transactions.

In case of web applications where the SQL and the ASP.NET code (in the same data center) are very much near I do not really buy this point out.

As said this is just my personal opinion.

I will still use stored procedures

At the end of the day I will still prefer stored procedures. The choice of choosing stored procedures will not be performance but it will be more from the aspect of security and maintenance. Below are some of the points where stored procedures are definitely a plus over inline SQL.

Abstraction

By putting all your SQL code into a stored procedure, your application is completely abstracted from the field names, tables names, etc. So when you make changes in the SQL, you have less impact in your C# code.

Security

This is the best part where stored procedures again score, you can assign execution rights on users and roles.

Maintenance ease

Now because we have centralized our stored procedures any issue like fixing defects and other changes can be easily done in a stored procedure and it will be reflected across the installed clients. At least we do not need to compile and deploy DLLs and EXEs.

Centralized tuning

If we know we have a slow running stored procedure, we can isolate it and the DBA guys can performance tune it separately.

Cursors, temp table complications

Simple TSQLs are OK. But what if you have a bunch of statements with IF, ELSE, Cursors, etc? For those kind of scenarios, again stored procedures are very handy.

References

You can also watch the below video where I have demonstrated my point using samples if you still do not trust this article:

and also feel free to visit my site for more SQL Server interview questions.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Shivprasad koirala
Architect http://www.questpond.com
India India
Member

I am a Microsoft MVP for ASP/ASP.NET and currently a CEO of a small
E-learning company in India. We are very much active in making training videos ,
writing books and corporate trainings. Do visit my site for 
.NET, C# , design pattern , WCF , Silverlight
, LINQ , ASP.NET , ADO.NET , Sharepoint , UML , SQL Server  training 
and Interview questions and answers


Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralRe: I might get this wrong, but...memberNaerling9 Jul '12 - 6:38 
Looks much better, although the title is a bit misleading.
Also, your 'dynamic sql' isn't quite dynamic. You simply built up a query in C#, but the resulting sql query is not dynamic.
Dynamic queries are about building strings in sql and executing them as strings (which then get executed as if they were actual queries).
This is an interesting and thorough article about dynamic sql[^], you should read it.
Anyway, since you've fixed the problematic error I will revote your article. Nice work.
It's an OO world.
public class Naerling : Lazy<Person>{
    public void DoWork(){ throw new NotImplementedException(); }
}

GeneralMy vote of 2memberCristian Amarie7 Jul '12 - 21:17 
You might want to say *lazy written* say stored procedures do not increase performance. And they do increase performance on many levels (not just measuring the same statement).
 
But it's not just performance.
Arguments are not convincing:
- vendor lock-in: isn't the same with hand written SQL? Or you do just SELECT INSERT UPDATE DELETE. It's inevitable to reach a sp_getapplock form or another; mutexes (for avoid transactions on whole tables or records), semaphores - basically emulating OS objects and synchronization primitives are what differentiates good SQL systems.
- statements caching: yes and no. You give 2-3 one line examples with the same SQL - but what if you have if this 100-lines-sql else if that 200-lines-sql else 150-lines-sql, and parametrized, where arguments changing etc. you will see the caching is not so clear anymore. SP resides on server and just parameters are passed.
 
And my 0.02:
- SP controls the flow and enforces logic. It's not just a bunch of SQL
- SP can be written by SQL/business guys that can't do C# or whatever (seriously, do we need a compiler to write queries?)
- SP *and* the synchronization objects resides on server (they are not created and flown from client to server back and forth)
- SP can use other SPs and let the code do just the driving
- queries and scattered all over (best scenario is that we get them together in some file or files), SP can be maintained/deployed very quickly, *without* touching the code
 
Basically I favor SPs mainly because they enforce users to have a single point of doing something. Throwing SELECTs all over code is at least unpleasant - or you are forced to do the same on client side.
 
So - arguments are correct, but not convincing to me. And the title is clearly misleading (for newbies, at least).
GeneralRe: My vote of 2memberShivprasad koirala7 Jul '12 - 23:28 
I agree to all your points ( i have also mentioned those points in the later stages) but as the title says they definitely do not increase performance by any way. All SQL go through the same engine , same caching mechanism.
 
You can see my experiments on this video http://youtu.be/hISdcezP7ik?hd=1[^]
 
Thanks
My book .NET interview questions with 500 mostly asked questions in .NET world .NET Interview questions and answers

QuestionVideo demonstration addedmemberShivprasad koirala7 Jul '12 - 20:48 
I have also added a video demonstration http://youtu.be/hISdcezP7ik?hd=1[^] as many people have raised a issue that will the above SQL work or not for caching.
 
Thanks
My book .NET interview questions with 500 mostly asked questions in .NET world .NET Interview questions and answers

QuestionYou Might Want to...memberPatrick Harris3 Jul '12 - 17:47 
read this article (if you're not familiar with this topic already). And then re-evaluate your performance concerns. Any time I encounter a stored procedure that does not out perform inline SQL, I address the issue of parameter sniffing to solve my problem:
http://www.sqlpointers.com/2006/11/parameter-sniffing-stored-procedures.html[^]
AnswerRe: You Might Want to...memberS.P. Tiwari4 Jul '12 - 21:14 
a very good link. thanks for post here.
GeneralRe: You Might Want to... [modified]memberShivprasad koirala5 Jul '12 - 0:27 
Currently for the experiment my parameter values where same. So i think this is important but not relevant for this topic.
My book .NET interview questions with 500 mostly asked questions in .NET world .NET Interview questions and answers


modified 7 Jul '12 - 3:06.

GeneralRe: You Might Want to... [modified]memberPatrick Harris6 Jul '12 - 3:26 
Please forgive me as I poted after only making a cursory view of your article. When I find time, I will dig into what you've posted and take a look at your degradation scenarios to verify (out of curiosity) whether addressing parameter sniffing will solve issues you have found.
 
Side Note: In regards to parameter sniffing issues, I have found this to be a significant problem with stored procedures and have made it a habit to create local variables and assign them to passed in parameters. I'm not sure if Microsoft has addressed this problem with a service pack or new version of SQL Server, but I will continue to use this technique until further notice.
 
i.e.
 
CREATE PROCEDURE [dbo].[show_somedata]
-- Add the parameters for the stored procedure here
@pid int,
@pcode varchar(4)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
 
-- doing this to avoid 'Parameter Sniffing' or 'Bind Variable Peeking' issue
DECLARE @id int
DECLARE @code varchar(4)
SET @id = @pid
SET @code = @pcode
 
SELECT * FROM sometable WHERE id = @id AND code = @code
 
END
 
Regards,
Patrick Harris

modified 6 Jul '12 - 21:48.

GeneralMy vote of 4membermbsmbs3 Jul '12 - 8:38 
Perfect Man
GeneralI agree to your pointmemberJean Paul V.A3 Jul '12 - 7:22 
Stored Procedures are pre-compiled only upto version 6.5 (ie in year 2000)
msdn: http://msdn.microsoft.com/en-us/library/aa174792(v=sql.80).aspx
 
(This information is included in SQL Server Certification too)
 
But as Koirala said still 90% people believe it is faster and write more code on SP.
 
I can vote for stored procedure only on iteration blocks where SP can reduce the round trip network traffic.
 
Still SP is too difficult to debug/manage and using EF / ORM reduces the requirement for INSERT/UPDATE SQLS.. Less code more easier management..
Again SPs make the code less object oriented, not TFS friendly...I am stopping
 
Please do not offend.. Smile | :)
Jean.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 2 Oct 2012
Article Copyright 2012 by Shivprasad koirala
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid