SQL Stored Procedure execution time difference - sql-server

I have strange issue in my win-form application where I am calling a stored procedure and it takes about 6 seconds to execute.
(This stored procedure accepts several parameters including one output parameter)
From application level I used :
Dim dt1 = DateTime.Now
cmd.ExecuteNonQuery()
MessageBox.Show(DateTime.Now.Subtract(dt1).Seconds)
This is about 5-6 seconds
I have tried running the same stored procedure with same parameters on sql-server and it takes no time to execute:
declare #val decimal
exec mysp 'value1','value2','value3','value4',#val out
select #val
I am not sure what the issue is or where to start.

The issue with difference between calling SP directly and from .NET code, maybe due to parameter sniffing. SQL Server maybe caching execution plan that is not optimal for the parameters you're passing from code.
To avoid this try adding WITH RECOMPILE to your SP definition, e.g.
CREATE PROCEDURE MySP (
... parameters...
) WITH RECOMPILE
AS
BEGIN
...

It could be an issue if your stored procedure expects say nvarchar and you use a varchar. SQL server will accept the parameters but will be forced to do a conversion. Do you have more specifics?

Related

Execute SQL Task output parameter vs ResultSet

We have parameter direction as output in parameter binding and at the same time we do have result binding. So if we are having output variable or return type variable which will be available at output, so why do we need Result binding then.
ResultSets and output parameters are not the same, each one of them has it own use:
ResultSets are used to store a result of a Select query: It can be a one or more columns and it can be a single row or a full result set. ResultSets are retrieved as ADO RecordSets and can be stored within variables. In general a RecordSet can be consumed on time.
Output Parameters are used to store some values that can be set any part of the SQL command (not necessary at the end). Parameters have the same concept of a SQL stored procedure parameters. The value can be used several times.
You can have an Execute SQL Task with output parameters and a ResultSet.
Additional Information
SQL Server Performance ResultSet vs Output Parameter vs Return Value
Result Sets in the Execute SQL Task
Map Result Sets to Variables in an Execute SQL Task
Parameters and Return Codes in the Execute SQL Task
Update 1 # 2019-16-08
You can use the output parameter as input parameter in another stored procedure but you have to execute it in a separate Execute SQL Task.
If you need to execute both stored procedures within one Execute SQL Task, then you can use SQL variables as mentioned in the example below:
DECLARE #output VARCHAR(50)
EXEC proc1 #output OUTPUT
EXEC proc2 #output
Update 2 # 2019-19-09
Recently I published a detailed article about this topic on SQL Shack, you can check it on:
Execute SQL Tasks in SSIS: Output Parameters Vs Result Sets

Execute stored procedure that has parameters with sp_executesql

I have a simple stored procedure that has parameter
CREATE Procedure GetSupplierForTesting
(#SupplierId INT)
AS
SELECT SuppLabel
FROM Supplier
WHERE Supplier.SupplierId = #SupplierId
I am able to call it with the exec command inside another stored procedure like this
exec GetSupplierForTesting #SupplierId = 10
I came across an article that explains how sp_executesql is faster than exec. My problem is that I don't know how to call a stored procedure that has parameters with sp_executesql. I have tried this code
DECLARE #SupplierId INT = 10;
EXEC sp_executesql N'GetSupplierForTesting', N'#SupplierId INT', #SupplierId
but I am getting an error:
Procedure or function 'GetSupplierForTesting' expects parameter '#SupplierId', which was not supplied
The syntax you would need would be
DECLARE #SupplierId INT = 10;
EXEC sys.sp_executesql N'GetSupplierForTesting #SupplierId=#SupplierId',
N'#SupplierId INT',
#SupplierId=#SupplierId
But don't do this. It is utterly pointless. There is no magic performance increase to be expected from using sp_executesql to basically wrap the same exec statement and execute it at a different scope.
Just use
exec dbo.GetSupplierForTesting #SupplierId = 10
1
Performance issue is based on assumption that when you are using non-parametrized ad-hoc query, it (the string representing this query) will be different every time - because specific argument values are parts of query text.
Whilst parametrized query keeps it's body unchanged because in place of where ... and title="asdf" you have where ... and title = #title. Only contents of variable #title change. But query text persists and sql server realizes that there is no need to recompile it.
Non-parametrized query will be recompiled every time you change values used in it.
2
You are getting exception because your script does not pass any arguments to the stored proc.
Your script is: 'GetSupplierForTesting' - that's it.
By passing arguments to sp_executesql you are passing them to the scipt. Not to the sp used in script, but to the script itself. E.g.:
exec sp_executesql N'print #val', N'#val int', #val = 1
this script does utilize variable #val. Your - does not. It just contains name of the proc. So your script corrected should look like
exec sp_executesql
N'exec GetSupplierForTesting #Supplier = #Supplier_id_value',
N'#Supplier_id_value int',
#Supplier_id_value = 10
script contains code calling your sp and this code passes argument to sp with value taken from #Supplier_id_value variable
#Supplier_id_value is declared as int for internals of this script
value of 10 is passed to the argument of the script
3
Performance issue you are talking about is about ad-hocs, not SPs.
Another face of this issue is parameter sniffing problem. Sometimes with specific param values your script or SP should use another execution plan, different from the plan it used for previously passed param values.
Every time recompiled ("slowly executed") ad-hoc would be (re)compiled for sure and probably would get better execution plan while SP or parametrized query would probably not be recompiled and would use worse, less optimal execution plan and would finally perform much slower than "slow because of recompilation" ad-hoc query.
There are no "write this - and it will work slowly", "write that - and it will hurtle like a rocket" rules in sql. It all depends on many factors. Sometimes one would probably need specifically ad-hocs, sometimes - should avoid them totally.

TVF is much slower when using parameterized query

I am trying to run an inline TVF as a raw parameterized SQL query.
When I run the following query in SSMS, it takes 2-3 seconds
select * from dbo.history('2/1/15','1/1/15','1/31/15',2,2021,default)
I was able to capture the following query through SQL profiler (parameterized, as generated by Entity framework) and run it in SSMS.
exec sp_executesql N'select * from dbo.history(#First,#DatedStart,#DatedEnd,#Number,#Year,default)',N'#First date,#DatedStart date,#DatedEnd date,#Maturity int,#Number decimal(10,5)',#First='2015-02-01',#DatedStart='2015-01-01',#DatedEnd='2015-01-31',#Year=2021,#Number=2
Running the above query in SSMS takes 1:08 which is around 30x longer than the non parameterized version.
I have tried adding option(recompile) to the end of the parameterized query, but it did absolutely nothing as far as performance. This is clearly an indexing issue to me, but I have no idea how to resolve it.
When looking at the execution plan, it appears that the parameterized version mostly gets mostly hung up on an Eager Spool (46%) and then a Clustered Index scan (30%) which are not present in the execution plan without parameters.
Perhaps there is something I am missing, can someone please point me in the right direction as to how I can get this parameterized query to work properly?
EDIT: Parameterized query execution plan, non-parameterized plan
Maybe it's a parameter sniffing problem.
Try modifying your function so that the parameters are set to local variables, and use the local vars in your SQL instead of the parameters.
So your function would have this structure
CREATE FUNCTION history(
#First Date,
#DatedStart Date,
#DatedEnd Date,
#Maturity int,
#Number decimal(10,5))
RETURNS #table TABLE (
--tabledef
)
AS
BEGIN
Declare #FirstVar Date = #First
Declare #DatedStartVar Date = #DatedStart
Declare #DatedEndVar Date = #DatedEnd
Declare #MaturityVar int = #Maturity
Declare #NumberVar decimal(10,5) = #Number
--SQL Statement which uses the local 'Var' variables and not the parameters
RETURN;
END
;
I've had similar probs in the past where this has been the culprit, and mapping to local variables stops SQL Server from coming up with a dud execution plan.

Calling a stored procedure via EF6 where the Stored Procedure calls another procedure for the result

I'm trying to introduce Entity Framework 6 to a legacy system that depends entirely on stored procedures.
I've got a stored procedure that builds a query which is then passed it to a second query that handles all of the paging requirements. The problem is that when I add the stored procedure to the model, the framework is detecting the return type as being 2 columns (varchar(4000) & varchar(100)) instead of the actual dataset that is returned when the query is executed.
When I try to run the code, firstly the Just-In-Time debugger crashes with some unhandled win32 exception in w3wp.exe.
Then when I cancel debugging I see the error message
The data reader is incompatible with the specified 'TFS_DevModel.spi_QualSearch_Result'. A member of the type, 'provider_code', does not have a corresponding column in the data reader with the same name.
The stored procedure is as follows:
declare #SQL varchar(5000),
#SearchCriteria varchar(1000)
-- build the sorting expression
-- various checks to append criteria based on input parameters
SELECT #SQL = 'select column1, column2, etc from tables ' +
#SearchCriteria
execute PagingProc #SQL, #sort_expression, [paging parameters]
I have tried to define a complex type to suit the data actually returned by the paging procedure, but I get the same error.
Does anyone know if what I'm trying to do is possible? Or should I look into refactoring the stored procedures?
Try attaching w3wp.exe to the IIS process (Tools > Attach to Process > Scroll down to w3wp.exe, select the correct IIS app pool and click attach). This seems to work for us.

Coding stored procedure for search screen with multiple, optional criteria

I've got a search screen on which the user can specify any combination of first name, last name, semester, or course. I'm not sure how to optimally code the SQL Server 2005 stored procedure to handle these potentially optional parameters. What's the most efficient way? Separate procedures for each combination? Taking the items in as nullable parms and building dynamic SQL?
I'd set each parameter to optional (default value being null)
and then handle it in the WHERE....
FirstName=ISNULL(#FirstName,FirstName)
AND
LastName=ISNULL(#LastName,LastName)
AND
SemesterID=ISNULL(#SemesterID,SemesterID)
That'll handle only first name, only last name, all three, etc., etc.
It's also a lot more pretty/manageable/robust than building the SQL string dynamically and executing that.
The best solution is to utilize sp_execute_sql. For example:
--BEGIN SQL
declare #sql nvarchar(4000)
set #sql =
'select * from weblogs.dbo.vwlogs
where Log_time between #BeginDate and #EndDate'
+ case when #UserName is null then '' else 'and client_user = #UserName' end
sp_execute_sql
#sql
, #params = '#UserName varchar(50)'
, #UserName = #UserName
--END SQL
As muerte mentioned, this will have a performance benefit versus exec()'ing a similar statement.
I would do it with sp_executesql because the plan will be cached just for the first pattern, or the first set of conditions.
Take a look at this TechNet article:
sp_executesql can be used instead of stored procedures to execute a Transact-SQL statement many times when the change in parameter values to the statement is the only variation. Because the Transact-SQL statement itself remains constant and only the parameter values change, the SQL Server query optimizer is likely to reuse the execution plan it generates for the first execution.
Was just posting the same concept as Kevin Fairchild, that is how we typically handle it.
You could do dynamic sql in your code to create the statement as required but if so you need to watch for sql injection.
As muerte points out, the plan will be cached for the first set of parameters. This can lead to bad performance when its run each subsequent time using alternate parameters. To resolve that use the WITH RECOMPILE option on the procedure.

Resources