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   
GeneralMy vote of 5memberTapasU8 Apr '13 - 19:13 
Hi Shiv Sir,
This is one of the best videos from you. Super explanation.
I have one question:
Suppose I have to execute one select from my .Net application then my view is definitely I will not go ahead and wrap that statement around some Procedure. I will keep it inline only. Any views on this?
QuestionVote 5membernarenderkumardhull4 Apr '13 - 19:09 
hello sir
 
many thanks for your post !
i am one of biggest fan of yours.. Good post i learn a lot from post as well comments.
please update with post.
 
offcourse you are respectable by reading your posts and books many juniors creaked interview.
plese keep posting.
 
Your reply for my commant can make my day Smile | :)
GeneralMy vote of 5membernarenderkumardhull4 Apr '13 - 19:09 
hello Shiv sir
 
many thanks for your post !
i am one of biggest fan of yours.. Good post i learn a lot from post as well comments.
please update with post.
 
offcourse you are respectable by reading your posts and books many juniors creaked interview.
plese keep posting.
 
Your reply for my commant can make my day Smile | :)
GeneralMy vote of 4memberVijaySai Panchadi28 Feb '13 - 1:17 
I like the way he explained about it.
GeneralMy vote of 4memberkimberly wind21 Feb '13 - 17:41 
new thing
GeneralMy vote of 5memberVarun Sareen22 Oct '12 - 2:26 
Gives a solid clarification on inline queries execution and Stored Procedures
QuestionSP are outdatedmemberThornik11 Oct '12 - 1:45 
Long-long time ago they were invented to create some kind of ugly apps on server side (when "clients" were just a simple programs and there was only two layers). Novadays SP is not needed at all, since Application Server solves everything - from abstraction of tables from classes till security. In other words, everything you counted as "benefits of SP". Moreover: throwing away SP you REALLY can have everything in central place: changing in business logic will touch only your C#/Java/Ruby code, no necessary to login to database and jump on procedures/triggers. Moreover: knowing and using one general purpose language you don't need to study sh*t like PL/SQL, T-SQL, etc. - just SQL as an ugly brother to make queries.
Anyway my score is 3 since you gave good hint related perfomance: SP are the same fast as queries, who need all those SP?...
AnswerRe: SP are outdatedmembereghetto11 Oct '12 - 21:14 
Relax buddy. Try to do mass data (big data) operations in C# or Ruby - then you know what SPs or SQL are good for. "It's the economy big data, stupid"
GeneralStored Procedures can Increase performancemembert4teacher8 Oct '12 - 4:21 
Dear You wrote a good article but in this way I made an experiment which increase performance and reduce load 80 percent mean which procedure was taking 10 sec that return record in 2 sec.
Example of my experiment
 
Create procedure sp_abc
@v1 varchar(50) ,
@v2 varchar(50)
as
Begin
Decclare @vuse1 varchar(50)
Decalare @vuse2 varchar(50)
set @vuse1=@v1
set @vuse2=@v2
 
select * from tblname where colunmname1=@v1
end
BugSQL InjectionmemberRichard Deeming8 Oct '12 - 4:00 
How can you write a query like your first example:
"Select * from Users where UserName='" + UserName + "' and Password='" + Password + "'"
without mentioning SQL Injection?! Unsure | :~



"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer


GeneralMy vote of 3membermerlin9813 Oct '12 - 6:27 
I've been a SQL Server DBA for over 10 years, and a .NET developer for nearly as long. Stored procs do have many performance improvements, especially as you start using newer technologies like LINQ and Entity Framework. Other commenters have already laid out very good reasons and proofs of why sprocs are "usually" faster, so I won't repeat them, here. Suffice it to say, in 90% of real world scenarios, sprocs are faster.
SuggestionDo not use the prefix “sp_” in the stored procedure name, link attached for you ref.memberURVISH_SUTHAR2 Oct '12 - 20:45 
http://blog.sqlauthority.com/2010/02/16/sql-server-stored-procedure-optimization-tips-best-practices/
GeneralRe: Do not use the prefix “sp_” in the stored procedure name, link attached for you ref.memberVarun Sareen22 Oct '12 - 2:28 
Yes very true.
 
We should not use sp_ for stored procedures instead we should rely on using usp_
 
Regards
 
Varun Sareen
Varun Sareen (Dot Net Developer)

QuestionArticle has nothing to do with the real performance issues.memberziggyfish2 Oct '12 - 20:29 
When I first read the title I thought it, surely this depends on the RDBMS (and it does). For example SQL Server does things completely different to the way Oracle does things. However since this only refers to SQL Server I can understand some of your reasoning.
 
However you haven't actually discussed the reason why I believe stored procedures are quicker.
 
You didn't look at the parse time taken, or the time it took to send that query to the server. Although the cache is hit, you still have the time it takes to parse the SQL query by the SQL server and sending it to the SQL server.
 
For example say you have a query that is 100 lines long (which is where your going to actually notice the difference), there is a considerable amount of time that SQL server has to take and verify that there is no syntax errors and compile it to send it to the query optimizer. In a Stored Proc this is only done once where as for inline SQL its done every time you run that statement. Now mr SQL Server may after looking at the SQL say this is the same as a previous SQL statement, and grab the query plan out of the cache. However it still needs to verify that the syntax of the statement is correct.
 
Some RDBMS systems, like MySQL do a simple text comparison to whats in the cache (for example "SELECT * FROM Customer" is a different query to "Select * From Customer"), so the parser can ignore this step. As this text comparison is generally O(n), there is some a performance effect however we are talking about cycles here not seconds.
 
Another problem with your logic, is the time it takes to send the SQL statement to the SQL server if it is physically hosted somewhere else. In fact as the Ping time increases you would see a noticeable difference in performance.
GeneralMy vote of 5memberMihai MOGA8 Aug '12 - 5:44 
This is a great inspiring article. I am pretty much pleased with your good work. You put really very helpful information. Keep it up once again.
GeneralVery GoodmemberOmar Gamil7 Aug '12 - 1:13 
You've cleared a misconception that has been irritating me for years.
 
Good job
5 from me Wink | ;)
GeneralA comment on "Maintenance ease"membersapatag6 Aug '12 - 23:43 
If you have one exe, and hundreds of databases at your customers, than maintainig stored procedures is an other storySmile | :)
Useful article, thank you!
GeneralRe: A comment on "Maintenance ease"memberMarco Rinaldi29 Jan '13 - 0:49 
In my opinion in IT the right answer is always: "like medicine, it depends on circumstances and scope"
Ing. Rinaldi Marco

AnswerYou can not reach a conclusion with partial tests.memberAgileWare3 Aug '12 - 5:08 
Their tests were useful to show that there is in all occasions that the stored procedure is faster, However it showed the cases it is better to use stored procedure, for example (Sub select).
 
See in:
http://www.blackwasp.co.uk/SpeedTestSqlSproc_2.aspx

You can not reach a conclusion with partial tests.
:|
GeneralRe: You can not reach a conclusion with partial tests.memberAgileWare2 Jan '13 - 5:12 
Correct?
GeneralMy vote of 5membersagar viradiya22 Jul '12 - 7:47 
i read your article in quetpond and here, i love it?
bcoz of questpond i cracked my interview ,thank you
GeneralMy vote of 5memberVMAtm19 Jul '12 - 0:57 
Nice position. But I think you could write much about
General-membersosingus17 Jul '12 - 2:44 
I'd suggest you see what Jasmine2501 wrote, in every other case this article has no diagnostic value.
 
Also, you might consider showing off on more complex query.
GeneralMy vote of 5memberromull16 Jul '12 - 19:49 
Good article. It's very strange that people does not know the basis and their comments give evidence to that fact.
GeneralMy vote of 3 [modified]memberJasmine250116 Jul '12 - 11:21 
Please do this test again without using the * in your query. The * causes behavioral differences from properly written queries and is known to affect performance. Please give more emphasis to the fact that stored procedures have many other advantages and are still generally preferred over ad-hoc SQL statements. People will use this article to argue with managers, and they will be wrong. So, please make a bigger point out of the benefits of stored procedures (security, DRY, etc).
 
Oh also, another thing I'd like to see you do is to reinstall the database between tests. Since your SQL statements are identical, there's a possibility that one is faster because you ran the other one first. Over time, with repeated queries against the same table, SQL Server gets faster as it generates statistics and creates indexes to improve query plans. If you're hammering on the Users table looking up users all day, SQL Server will be able to optimize ANY attempt to do that, regardless of the source of the query. So, if you ran your inline SQL after running the proc 1000 times, I would expect it to be faster because SQL Server has been able to optimize the table for that specific type of lookup.
 
These are my suggestions for a more valid test:
1. Remove the * from your queries
2. Get a different row each time (you're always grabbing the same row)
3. Run the tests against different physical databases (so that performing one test doesn't affect the outcome of the other)
4. Return some useful data (such as User ID that was found) and consume it on the client side.
5. Try the other two kinds of operations, updating and deleting.
6. Run two load tests at the same time - one using procs and one using SQL - see which users "get through" more quickly when the server is stressed.
 
(Your conclusion is probably correct, but I don't think the test actually proves it).

modified 16 Jul '12 - 17:45.

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

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