Stored Procedure returning duplicate results where as firing the sql it runs directly doesn't - sql

We have got a stored procedure in SQL Server 2005 with a complicated bit of single select query. Recently in one environment, we noticed that for a small subset of the results returned by the stored proc, there were duplicate records. When we ran the sql query directly, we got the correct set of records without any duplicates. The stored procedure uses a lot of views and joins (inner join/left join). One theory I have is that somehow the stored procedure is using some cached execution plans as we have modified some views recently, but I don't have enough SQL expertise to be sure of that. Does any one have any idea?
Thanks for your help,
Ashish

Different results might be caused by different connection settings (e.g. ansi_nulls, arith_abort etc.).

Run sp_recompile on the stored procedure to clear the procedure cache for that stored procedure.
To clear the entire procedure cache execute
DBCC FREEPROCCACHE
Here's an example of recompiling if you want to put it in a re-usable script:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/****** Object: Maintenance - StoredProcedure [Sample].[SampleSearch] Script Date: 07/28/2011 14:15:15 ******/
IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = 'Sample' AND ROUTINE_NAME = 'Sampleearch'))
BEGIN
PRINT 'Marking procedure [Sample].[SampleSearch] for recompile'
EXEC sp_recompile 'Sample.SampleSearch'
PRINT 'Finished marking procedure [Sample].[SampleSearch] for recompile'
END
GO
However, if the query is returning different results, maybe turn on SQL tracing or debug the call from the code to ensure the same in and out parameters are being used in both cases.

Related

Loop Through All SSMS Databases without Recreating Stored Procedure

Background Information:
In Python, I might write something like this if I want to apply the same logic to different values in a list.
database_list = ["db_1", "db_2", "db_3"]
for x in range(0,len(database_list),1):
print("the database name is " + database_list[x])
What I am trying to do:
What I am trying to do in SSMS, is pull a list of DB objects for each database. I created a stored procedure to pull exactly what I want, but I have to run it against each database, so 10 databases mean running it 10 times.
My goal is to do this with a T-SQL query instead of Python.
I tried doing something like this:
exec sp_MSforeachdb 'USE ?; EXEC [dbo].[my_stored_procedure]';
The problem with this is, [dbo].[my_stored_procedure] has to exist in every database I want to do this in.
How can I create the stored procedure in 1 database, but execute it for all databases or a list of databases that I choose?
I know what you are trying to do and if it's what I think (you seem reluctant to actually say!) you can do the following:
In the master database, create your procedure. Normally you wouldn't do this, but in this case you must prefix it sp_
use master
go
create procedure sp_testproc as
select top 10 * from sys.tables
go
Now if you run this, it will return tables from the master database.
If you switch context to another database and exec master.dbo.sp_testproc, it will still return tables from the master database.
In master, run
sys.sp_MS_marksystemobject sp_testproc
Now switch context to a different database and exec master.dbo.sp_testproc
It will return tables from the database you are using.
Try creating your sproc in master and naming it with an sp_ prefix:
USE master
GO
CREATE PROCEDURE sp_sproc_name
AS
BEGIN
...
END
GO
-- You *may* need to mark it as a system object
EXEC sys.sp_MS_marksystemobject sp_sprocname
See: https://nickstips.wordpress.com/2010/10/18/sql-making-a-stored-procedure-available-to-all-databases/
It should then be available in all dbs
Create the stored procedure in the Master database with the sp_ prefix, and use dynamic SQL in the stored procedure so it resolves object names relative to the current database, rather than the database which contains the stored procedure.
EG
use master
go
CREATE OR ALTER PROCEDURE [dbo].[sp_getobjects]
AS
exec ('
select *
from [sys].[objects]
where is_ms_shipped = 0
order by type, name
')
go
use AdventureWorks2017
exec sp_getobjects
#LunchBox - it's your single stored procedure (that you create in one database) that is actually going to need to contain the "exec sp_MSforeach ...." command, and instead of the command to be executed being "EXEC ", it will need to be the actual SQL that you were going to put into the stored proc.
Eg. (inside your single stored procedure)
EXEC sp_MSforeachdb 'USE ?; SELECT * FROM <table>; UPDATE <another table> SET ...';
Think of the stored procedure (that you put into one database) as being no different than your Python code file - if you had actually wanted to achieve the same thing in Python, you would have either needed to create the stored proc in each database, or build the SQL statement string in Python and execute it against each database.
I understand what you thought you might be able to achieve with SQL, but stored procedures really don't work the way you were expecting. Even when you're in the context of a different database, but you run EXEC <different_db>.stored_proc, that stored proc ends up running in the context of the database in which it exists (not your context database).
Now, the only one issue you may come up against is that the standard sp_MSforeachdb stored proc has a limit of 2000 characters for the command that can be executed (although, it does have multiple "command" parameters, this may not be practical if you were planning on running a very large code block, perhaps with variables that carry all the way through). If this is something that might impact what you're intending to do, you could do a search online for "sp_MSforeachdb alternatives" - there seem to be a handful that people have created where the command parameter can contain a larger string.

Should we end stored procedures with the GO statement?

Should we end stored procedures with GO statement, if so what are the advantages of using GO?
CREATE PROCEDURE uspGetAddress #City nvarchar(30)
AS
SELECT *
FROM AdventureWorks.Person.Address
WHERE City = #City
GO
The statement go, per the documentation
Signals the end of a batch of Transact-SQL statements to the SQL Server utilities.
...
GO is not a Transact-SQL statement; it is a command recognized by the sqlcmd and osql
utilities and SQL Server Management Studio Code editor.
SQL Server utilities interpret GO as a signal that they should send the current batch
of Transact-SQL statements to an instance of SQL Server. The current batch of statements
is composed of all statements entered since the last GO, or since the start of the
ad-hoc session or script if this is the first GO.
A Transact-SQL statement cannot occupy the same line as a GO command. However, the line
can contain comments.
Users must follow the rules for batches. For example, any execution of a stored procedure
after the first statement in a batch must include the EXECUTE keyword. The scope of
local (user-defined) variables is limited to a batch, and cannot be referenced after a
GO command.
A stored procedure definition, per the documentation for create procedure, comes with restrictions. it must be the first (and only) statement in the batch:
The CREATE PROCEDURE statement cannot be combined with other Transact-SQL statements in
a single batch.
That means the body of stored procedure ends with the batch. Adding GO in your source file is good practice. Especially since it's common to do things prior to and following the creation of a stored procedure. You'll often see source files that look something like this:
if (object_id('dbo.foobar') is not null ) drop procedure dbo.foobar
GO
-- dbo.foobar --------------------------------------------
--
-- This stored procedure does amazing and wonderful things
----------------------------------------------------------
create procedure dbo.foobar
as
...
{a sequence of amazing and wonderful SQL statements}
...
return 0
GO
grant execute on dbo.foobar to some_schema
GO
And the value for GO is adjustable in Sql Server Management Studio's options. If you'd like to use something like jump instead of go, you can (bearing in mind that you're almost certainly going to give yourself grief in doing so.).
No, you should end your procedure with RETURN.
CREATE PROCEDURE uspGetAddress #City nvarchar(30)
AS
SELECT *
FROM AdventureWorks.Person.Address
WHERE City = #City
RETURN
The GO is really meant to separate commands in a sql script.
Just wanted to point out that without a GO at the end of your stored procedure, any T-SQL after the supposed end of the procedure body will still be included in the body of the proc.
For example
CREATE PROCEDURE Foo
BEGIN
SELECT * FROM dbo.Bar;
END
DROP TABLE dbo.Bar;
In this example, running EXEC dbo.Foo will end up dropping the table even though it is after the END. To avoid that, you need to place a GO after the END.
I prefer to surround the body of the stored procedure with begin and end statements:
CREATE PROCEDURE uspGetAddress (
#City nvarchar(30)
) AS
BEGIN
SELECT *
FROM AdventureWorks.Person.Address
WHERE City = #City;
END;
GO is a not a T-SQL command. It is understood by the tools that run scripts. As the documentation describes:
GO is not a Transact-SQL statement; it is a command recognized by the
sqlcmd and osql utilities and SQL Server Management Studio Code
editor.
SQL Server utilities interpret GO as a signal that they should send
the current batch of Transact-SQL statements to an instance of SQL
Server. The current batch of statements is composed of all statements
entered since the last GO, or since the start of the ad hoc session or
script if this is the first GO.
By the way, in your case, a user-defined table function might be more appropriate than a stored procedure.

SQL Server performance fast only when refresh the stored procedure

I can run a stored procedure multiple times and it wont hit it's cache: (1665ms is duration column)
But if I then alter the stored procedure changing nothing: (240ms is duration column)
Problem: how to get the stored procedure to always be fast (on the second and next calls)
With some digging I found that when I called the SP initially (after a reboot) with a NULL applicationID
exec [dbo].[usp_Tab32] #responsibleReviewerID=1135,#applicationID=NULL,#environment=1,#userUIStatus=0,#roleID=NULL
then with a more confined query:
exec [dbo].[usp_Tab32] #responsibleReviewerID=1135,#applicationID=1406,#environment=1,#userUIStatus=0,#roleID=NULL
This would be slow.
However if I hit the more confined query first, then both would be fast.
To clear down the database plan cache:
DECLARE #dbId INTEGER
SELECT #dbId = dbid FROM master.dbo.sysdatabases WHERE name = ‘myDatabase’
DBCC FLUSHPROCINDB (#dbId)
More detail here
All against SQL2012 Developer edition.
Create your stored procedure with RECOMPILE and recompile at Runtime
CREATE PROCEDURE yourprodecurename
WITH RECOMPILE
AS
--your code here
GO
then call it in this way:
EXEC yourprodecurename WITH RECOMPILE
This should give you the experience you want, because, when a procedure is compiled for the first time or recompiled, the procedures query plan is optimized for the current state of the database.
So this can improve the procedure’s processing performance.

What are the downsides of creating SQL Server stored procedures in the following manner?

We check in all our database objects into source control as rerunnable scripts (views, functions, triggers & stored procedures etc...)
When it comes time to deploy, we need to ensure that all the scripts are re-runnable & repeatable so that a stored procedure is be created/updated to the latest version.
Are there any downsides to creating the scripts in the following manner.
IF NOT EXISTS
(
SELECT *
FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_SCHEMA = 'dbo'
AND ROUTINE_NAME = 'MyStoredProcedure'
)
BEGIN
EXEC ('CREATE PROCEDURE [dbo].[MyStoredProcedure] AS SELECT 1')
-- ALSO DO ANY INITIAL GRANT PRIVILEGE SCRIPTING HERE
END
GO
ALTER PROCEDURE [dbo].[MyStoredProcedure] (
#param1 INT,
#param2 NVARCHAR(50) = 'Default String'
)
AS
BEGIN
-- DO SOMETHING WITH #param1 AND #param2
SELECT 1;
END
GO
Essentially the script checks to see if the object exists in the relevant system view, and if it doesn't exist, some dynamic sql creates it as a stub to get around CREATE PROCEDURE/GO statement issues not being allowed in conditional blocks. Then it applies the actual functionality of the script through an ALTER.
So the benefits are obvious to me, I'm just wondering are there any downsides to doing this... other than the slight overhead of writing slightly more verbose scripts.
10 year SQL Server developer/architect here, and I can't think of any downsides other than the (relatively slight) upfront cost of creating the script that will do this.
If you are concerned that a plan compiled as trivial at the time of creation is not recompiled when the procedure is ALTERed, you could add an explicit call to SP_RECOMPILE for each, but I have never had this this problem with SQL Server (I have had it with DB2) and so I think that is excessive caution.
This is an interesting and I think useful approach.

add SQL Server index but how to recompile only affected stored procedures?

I need to add an index to a table, and I want to recompile only/all the stored procedures that make reference to this table. Is there any quick and easy way?
EDIT:
from SQL Server 2005 Books Online, Recompiling Stored Procedures:
As a database is changed by such actions as adding indexes or changing data in indexed columns, the original query plans used to access its tables should be optimized again by recompiling them. This optimization happens automatically the first time a stored procedure is run after Microsoft SQL Server 2005 is restarted. It also occurs if an underlying table used by the stored procedure changes. But if a new index is added from which the stored procedure might benefit, optimization does not happen until the next time the stored procedure is run after Microsoft SQL Server is restarted. In this situation, it can be useful to force the stored procedure to recompile the next time it executes
Another reason to force a stored procedure to recompile is to counteract, when necessary, the "parameter sniffing" behavior of stored procedure compilation. When SQL Server executes stored procedures, any parameter values used by the procedure when it compiles are included as part of generating the query plan. If these values represent the typical ones with which the procedure is called subsequently, then the stored procedure benefits from the query plan each time it compiles and executes. If not, performance may suffer
You can exceute sp_recompile and supply the table name you've just indexed. all procs that depend on that table will be flushed from the stored proc cache, and be "compiled" the next time they are executed
See this from the msdn docs:
sp_recompile (Transact-SQL)
They are generally recompiled automatically. I guess I don't know if this is guaranteed, but it has been what I have observed - if you change (e.g. add an index) the objects referenced by the sproc then it recompiles.
create table mytable (i int identity)
insert mytable default values
go 100
create proc sp1 as select * from mytable where i = 17
go
exec sp1
If you look at the plan for this execution, it shows a table scan as expected.
create index mytablei on mytable(i)
exec sp1
The plan has changed to an index seek.
EDIT: ok I came up with a query that appears to work - this gives you all sproc names that have a reference to a given table in the plan cache. You can concatenate the sproc name with the sp_recompile syntax to generate a bunch of sp_recompile statements you can then execute.
;WITH XMLNAMESPACES (default 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
,TableRefs (SProcName, ReferencedTableName) as
(
select
object_name(qp.objectid) as SProcName,
objNodes.objNode.value('#Database', 'sysname') + '.' + objNodes.objNode.value('#Schema', 'sysname') + '.' + objNodes.objNode.value('#Table', 'sysname') as ReferencedTableName
from sys.dm_exec_cached_plans cp
outer apply sys.dm_exec_sql_text(cp.plan_handle) st
outer apply sys.dm_exec_query_plan(cp.plan_handle) as qp
outer apply qp.query_plan.nodes('//Object[#Table]') as objNodes(objNode)
where cp.cacheobjtype = 'Compiled Plan'
and cp.objtype = 'Proc'
)
select
*
from TableRefs
where SProcName is not null
and isnull(ReferencedTableName,'') = '[db].[schema].[table]'
I believe that the stored procedures that would potentially benefit from the presence of the index in question will automatically have a new query plan generated, provided the auto generate statistics option has been enabled.
See the section entitled Recompiling Execution Plans for details of what eventualities cause an automatic recompilation.
http://technet.microsoft.com/en-us/library/ms181055(SQL.90).aspx