Professional Documents
Culture Documents
Keep in mind that just because you use a stored procedure does not mean that it
will run fast. The code you use within your stored procedure must be well designed
for both speed and reuse. [6.5, 7.0, 2000, 2005] Update 6-6-2005
*****
One of the biggest advantages of using stored procedures over not using stored
procedures is the ability to significantly reduce network traffic. And the more
network traffic that can be reduced, the better the overall performance of your SQL
Server-based applications.
Here are some examples how stored procedures reduce network traffic:
The goal should be to limit network traffic from the client to SQL Server to simple
RPCs, and limit the traffic from SQL Server to the client as finished results. [6.5,
7.0, 2000] Updated 12-6-2005
*****
To help identify performance problems with stored procedures, use the SQL
Server's Profiler Create Trace Wizard to run the "Profile the Performance of a
Stored Procedure" trace to provide you with the data you need to identify poorly
performing stored procedures. [7.0] Updated 12-6-2005
*****
By default, every time a stored procedure is executed, a message is sent from
the server to the client indicating the number of rows that were affected by the
stored procedure. Rarely is this information useful to the client. By turning off
this default behavior, you can reduce network traffic between the server and the
client, helping to boost overall performance of your server and applications.
There are two main ways to turn this feature off. You can also turn this feature off
using a server trace setting, but it is unnecessary as there are easier ways, as
described here.
To turn this feature off on at the stored procedure level, you can include the
statement:
SET NOCOUNT ON
at the beginning of each stored procedure you write. This statement should be
included in every stored procedure you write.
If you want this feature turned off for your entire server, you can do this by running
these statements at your server:
SP_CONFIGURE 'user options', 512
RECONFIGURE
You may or may not want to do this for your entire server, as it affects every
transaction on your server. For example, some application programs need the count
information, otherwise they will not work. If this is the case, you don't want to turn
this option for the entire server, but just for the stored procedures you write.
Most commonly, the first statement is used as it is more flexible, and only affects
those stored procedures you write. [6.5, 7.0, 2000] Updated 12-6-2005
*****
Keep Transact-SQL transactions as short as possible within a stored
procedure. This helps to reduce the number of locks, helping to speed up the
overall performance of your SQL Server application.
Two ways to help reduce the length of a transaction are to: 1) break up the entire
job into smaller steps (or multiple stored procedures) so each step can be
committed as soon as possible; and 2) take advantage of SQL Server statement
batches, which acts to reduce the number of round-trips between the client and
server. [6.5, 7.0, 2000, 2005] Updated 6-6-2005
*****
When a stored procedure is first executed (and it does not have the WITH
RECOMPILE option), it is optimized and a query plan is compiled and cached in
SQL Server's buffer. If the same stored procedure is called again from the same
connection, it will used the cached query plan instead of creating a new one, often
saving time and boosting performance. This may or may not be what you want.
If the query in the stored procedure is exactly the same each time, and the query
plan is the same each time, then this is a good thing. But if the query within the
stored procedure is dynamic (for example, the WHERE clauses changes from one
execution of the stored procedure to the next), then this may not be a good thing, as
the query may not be optimized when it is run, and the performance of the query
can suffer greatly. This can happen because changes in the query plan may occur,
and if you run an incorrect cached query plan for what is essentially a new query, it
may not be appropriate and it may cause performance to suffer greatly.
If you know that your query's query plan will vary each time it is run from a stored
procedure, you will want to add the WITH RECOMPILE option when you create
the stored procedure. This will force the stored procedure to be re-compiled each
time it is run, ensuring the query is optimized with the correct query plan each time
it is run. Yes, this will circumvent the reuse of cached query plans, hurting
performance a little, but it is more desirable than reusing incorrect query plans.
[6.5, 7.0, 2000] Updated 12-6-2005
*****
Many stored procedures have the option to accept multiple parameters. This in and
of itself is not a bad thing. But what can often cause problems is if the parameters
are optional, and the number of parameters varies greatly each time the stored
procedure runs. There are two ways to handle this problem, the slow performance
way and fast performance way.
If you want to save your development time, but don't care about your application's
performance, you can write your stored procedure generically so that it doesn't care
how many parameters it gets. The problem with this method is that you may end up
unnecessarily joining tables that don't need to be joined based on the parameters
submitted for any single execution of the stored procedure.
Another, much better performing way, although it will take you more time to code,
is to include IF...ELSE logic in your stored procedure, and create separate queries
for each possible combination of parameters that are to be submitted to the stored
procedure. This way, you can be sure you query is as efficient as possible each time
it runs. [6.5, 7.0, 2000] Updated 12-6-2005
*****
Here's another way to handle the problem of not knowing what parameters
your stored procedure might face. In fact, it will probably perform faster than the
tip listed above.
Although the above tip is a good starting point, it's not complete. The problem are
the query plans, the pre-compilation of stored procedures, that SQL Server does for
you. As you know, one of the biggest reasons to use stored procedures instead of
ad-hoc queries is the performance gained by using them. The problem that arises
with the above tip is that SQL Server will only generate a query-plan for the path
taken through your stored procedure when you first call it, not all possible paths.
Let me illustrate this with an example. Consider the following procedure (precompilation doesn't really have a huge effect on the queries used here, but these are
just for illustration purposes):
CREATE PROCEDURE dbo.spTest (@query bit) AS
IF @query = 0
SELECT * FROM authors
ELSE
SELECT * FROM publishers
GO
Suppose I make my first call to this procedure with the @query parameter set to 0.
The query-plan that SQL Server will generate will be optimized for the first query
("SELECT * FROM authors"), because the path followed on the first call will
result in that query being executed.
Now, if I next call the stored procedure with @query set to 1, the query plan that
SQL Server has in memory will not be of any use in executing the second query,
since the query-plan is optimized for the authors table, not the publishers table.
Result: SQL Server will have to compile a new query plan, the one needed for the
second query. If I next call the procedure with @query set to 0 again, the whole
path will have to be followed from the start again, since only one query-plan will
be kept in memory for each stored procedure. This will result in sub-optimal
performance.
As it happens I have a solution, one that I've used a lot with success. It involves the
creation of what I like to call a 'delegator'. Consider again spTest. I propose to
rewrite it like this:
CREATE PROCEDURE dbo.spTestDelegator (@query bit) AS
IF @query = 0
EXEC spTestFromAuthors
ELSE
EXEC spTestFromPublishers
GO
CREATE PROCEDURE dbo.spTestFromAuthors AS
SELECT * FROM authors
GO
If you are creating a stored procedure to run in a database other than the
Master database, don't use the prefix "sp_" in its name. This special prefix is
reserved for system stored procedures. Although using this prefix will not prevent a
user defined stored procedure from working, what it can do is to slow down its
execution ever so slightly.
The reason for this is that by default, any stored procedure executed by SQL Server
that begins with the prefix "sp_", is first attempted to be resolved in the Master
database. Since it is not there, time is wasted looking for the stored procedure.
If SQL Server cannot find the stored procedure in the Master database, then it next
tries to resolve the stored procedure name as if the owner of the object is "dbo".
Assuming the stored procedure is in the current database, it will then execute. To
avoid this unnecessary delay, don't name any of your stored procedures with the
prefix "sp_". [6.5, 7.0, 2000] Updated 6-12-2006
*****
Before you are done with your stored procedure code, review it for any unused
code that you may have forgotten to remove while you were making changes, and
remove it. Unused code just adds unnecessary bloat to your stored procedures,
although it will not negatively affect performance of the stored procedure. [6.5, 7.0,
2000] Updated 6-12-2006
*****
For best performance, all objects that are called within the same stored
procedure should all be owned by the same object owner, preferably dbo, and
should also be referred to in the format of object_owner.object_name.
If the object owner's are not specified for objects, then SQL Server must perform
name resolution on the objects, which causes a performance hit.
And if objects referred to in the stored procedure have different owners, SQL
Server must check object permissions before it can access any object in the
database, which adds unnecessary overhead. Ideally, the owner of the stored
procedure should own all of the objects referred to in the stored procedure.
In addition, SQL Server cannot reuse a stored procedure "in-memory plan" over if
the object owner is not used consistently. If a stored procedure is sometime referred
to with its object owner's name, and sometimes it is not, then SQL Server must reexecute the stored procedure, which also hinders performance. [7.0, 2000, 2005]
Updated 6-6-2005
*****
When you need to execute a string of Transact-SQL, you should use the
sp_executesql stored procedure instead of the EXECUTE statement.
Sp_executesql offers two major advantages over EXECUTE. First, it supports
parameter substitution, which gives your more options when creating your code.
Second, it creates query execution plans that are more likely to be reused by SQL
Server, which in turn reduces overhead on the server, boosting performance.
Sp_executesql executes a string of Transact-SQL in its own self-contained batch.
When it is run, SQL Server compiles the code in the string into an execution plan
that is separate from the batch that contained the sp_executesql and its string.
Learn more about how to use sp_executesql in the SQL Server Books Online. [7.0,
2000] Updated 6-12-2006
*****
Here are three potential problems you want to look out for when writing stored
procedures.
Unnecessary Stored Procedure Recompilations Due to Row Modifications and
Automated Statistics Update
If your database has the "Auto Update Statistics" database option turned on, SQL
Server will periodically automatically update the index statistics. On a busy
database, this could happen many times each hour. Normally, this is a good thing
because the Query Optimizer needs current index statistics if it is to make good
query plan decisions. One side effect of this is that this also causes any stored
procedures that reference these tables to be recompiled. Again, this is normal, as
you don't want a stored procedure to be running an outdated query plan. But again,
sometimes stored procedures recompile more than they have to. Here are some
suggestions on how to reduce some of the unnecessary recompilations:
*****
Avoid nesting stored procedures, although it is perfectly legal to do so. Nesting
not only makes debugging more difficult, it makes it much more difficult to
identify and resolve performance-related problems. [6.5, 7.0, 2000] Updated 0403-2006
*****
If you use input parameters in your stored procedures, you should validate all
of them at the beginning of your stored procedure. This way, if there is a
validation problem and the client applications needs to be notified of the problem,
it happens before any stored procedure processing takes place, preventing wasted
effort and boosting performance. [6.5, 7.0, 2000] Updated 6-12-2006
*****
When calling a stored procedure from your application, it is important that
you call it using its fully qualified name. Such as:
exec database_name.dbo.myProcedure
instead of:
exec myProcedure
Why? There are a couple of reasons, one of which relates to performance. First,
using fully qualified names helps to eliminate any potential confusion about which
stored procedure you want to run, helping to prevent bugs and other potential
problems.
But more importantly, doing so allows SQL Server to access the stored procedures
execution plan more directly, and in turn, speeding up the performance of the
stored procedure. Yes, the performance boost is very small, but if your server is
running tens of thousands or more stored procedures every hour, these little time
savings can add up. [7.0, 2000] Updated 6-12-2006
*****
If a stored procedure needs to return only a single value, and not a recordset,
consider returning the single value as an output statement. While output
statements are generally used for error-checking, they can actually be used for any
reason you like. Returning a single value as at output statement is faster than
returning a single value as part of a recordset. [6.5, 7.0, 2000] Updated 6-12-2006
*****
One way to help ensure that stored procedures are reused from execution to
execution of the same stored procedure is to ensure that any SET options, database
options, or SQL Server configuration options don't change from execution to
execution of the same stored procedure. If they do, then SQL Server may consider
these same stored procedures to be different, and not be able to reuse the current
query plan stored in cache.
Some examples of this include when you change the language used by the stored
procedure (using SET) and if you change the Dateformat (using SET). [7.0, 2000]
Updated 6-12-2006
*****
If you find that a particular stored procedure recompiles every time it
executes, and you have determined that there is nothing you can do about the
recompiles, and if that stored procedure is very large, consider the following
option. Try to determine what part or parts of the stored procedure is causing the
recompiles. Once you have done this, break out this troublesome code into its own
stored procedure, and then call this stored procedure from the main stored
procedure. The advantage of this is that is it takes much less time to recompile a
smaller stored procedure than a larger stored procedure. [7.0, 2000] Updated 6-122006