Dataset times out while query runs immediately - c#

I am running a query directly, it is trivial in nature:
SELECT * FROM [dbo].[vwUnloadedJobDetailsWithData] WHERE JobId = 36963
When I run this from Management studio the query doesn't even take a second. When I run it from within the table adapter it times out. I have fixed this multiple times, but the fix is ludicrous. If I delete the table adapter from my xsd file and recreate it the query time matches that of management studio for about two days, but I have to redeploy which is asinine.
Any insight into what could be causing this would be greatly appreciated. I've seen another question about this but the solution involving set arithabort on before the query had no effect for me.
Edit: It was asked that I show my code for calling the query. Now this happens when I go into my xsd file and just do preview data as well, but for sake of clarity, here it is:
using (TEAMSConnection connection = new TEAMSConnection())
{
connection.OpenConnection();
_JobDetailsDAO jobDetailDao= new _JobDetailsDAO(connection);
return jobDetailDao.GetUnloadedJobDetailsByJobId(jobId);
}
On disposal of connection the database connection is closed. using this line of code:
if (_DBConnection != null && _DBConnection.State == ConnectionState.Open)
_DBConnection.Close();
Edit2: I ran a trace and here are the set options that are being set
set quoted_identifier on
set arithabort off
set numeric_roundabort off
set ansi_warnings on
set ansi_padding on
set ansi_nulls on
set concat_null_yields_null on
set cursor_close_on_commit off
set implicit_transactions off
set language us_english
set dateformat mdy
set datefirst 7
set transaction isolation level read committed
I went and added that to the query that I generated in management studio and it still ran in less than a second. I even copied the query exactly as in the trace.
exec sp_executesql N'SELECT * FROM [dbo].[vwUnloadedJobDetailsWithData] WHERE JobID = #JobId',N'#JobId int',#JobId=36963
and it is still less than a second return time. I am so very confused.
Thanks,
Josh

the most likely scenarion why this would be happening is the difference in SET options between ssms and ado.net. that difference causes (re)building of execution plans that might not be optimal.

Alright, well I could not find any solution that would continue to allow me to use the dataset, so I went straight to using the SqlDataAdapter in code rather than using the auto generated TableAdapters.
According to the trace it performs the exact same query, but so far it works. It may not in two days, but for now it works it seems.

Just trying to think loudly:
Maybe there is a lock caused by another process/person? Is there anybody who updates the same row at the same time? Is there anybody who opens the table from Management studio or Query Analyzer with Open Table feature and plays with the filters?
Try looking for locks using sp_who2

Some thoughts:
What I'd call parameter sniffing for stored proc. Try the OPTION (RECOMPILE) hint, so your sent SQL looks like this:
exec sp_executesql
N'SELECT *
FROM [dbo].[vwUnloadedJobDetailsWithData]
WHERE JobID = #JobId
OPTION (RECOMPILE)',
N'#JobId int',
#JobId=36963
Explanation: When a query plan is produced and cached, it may be a bad, atypical value. Say JobID is usually very selective, but for that one execution it's not. When you run the query the next plan the cached plan is wrong for the next selective JobId. A plan will be recompiled for various reasons, but the value on recompilation matters.
Otherwise, what is the exact datatype of Jobid? If it's smallint, then the column will be converted to int in the parameterised query. When using a constant it will be smallint. Make sure the type is defined correctly: this matters in SQL code.

Related

Entity Framework - extremely long execution time for stored procedure

I'm following up on my question yesterday, Entity Framework 6 get complext return value from a stored procedure. My stored procedure now runs under entity framework. However, it times out after 3 minutes, the connection time out.
I run the stored procedure in my SQL Server Management Studio with the line (customer information omitted):
EXEC spGetDupWOs #ProjectName=N'...', #City=N'...', #State=N'LA', #ProposalNum=N'201703080740-001', #County=N'...', #Owner=N'...', #QuoteRecipients=N'...', #ProjectID=-1
It executes in less than a second. When Entity framwork executes it, it takes forever.
Using the SQL Server Profiler, I determined that Entity Framework is sending this line to the SQL server:
exec sp_executesql N'EXEC spGetDupWOs',N'#ProjectName nvarchar(19),#City nvarchar(6),#State nvarchar(2),#ProjectNum nvarchar(12),#County nvarchar(10),#Owner nvarchar(23),#QuoteRecipients nvarchar(23),#ProjectID bigint',#ProjectName=N'...',#City=N'Holden',#State=N'LA',#ProposalNum=N'201703080740-001',#County=N'Livingston',#Owner=N'...',#BID_RECIP=N'...',#ProjectID=-1
When I run this in SSMS, it takes forever to run.
Reading the similar questions it looks like the issue is Parameter Sniffing and a change in execution plan.
Here is my call to execute the stored procedure in my application:
List<DuplicateProposals> duplicateCheckResults =
db.Database.SqlQuery<DuplicateProposals>("spGetDupWOs",
spl.ToArray())
.ToList();
After reading a bunch of articles online, I'm even more confused. How can I change my call to resolve this?
The issue identified is parameter sniffing in SQL Server. There are multiple approaches to handle this, but the most optimal for your scenario depends on your real use case, utilization, etc.
Here are some options.
Recompile the stored procedure with every execution. This may become very heavy CPU utilization, and is typically overkill. I would NOT recommend this option unless you have a very good reason. To implement: Use
WITH RECOMPILE or the OPTION(RECOMPILE) hint at the end of your query.
Optimize for hint. This can be a workaround for the parameter sniffing, but may result in a subpar execution plan for all of your queries. Typically, not an optimal approach. To implement: Use OPTION(OPTIMIZE FOR UNKNOWN)
Copy parameter to a local variable. Was more common in older versions of SQL Server. To implement: Declare a local variable, then copy the value from your input parameter to your local variable. DECLARE #local_var1 char(1) = #InputParam1;
Turn off parameter sniffing at query level. This approach uses the QUERYTRACEON hint. This may be the most optimal approach for this case scenario. I would recommend to explore this option as a primary strategy. To implement: add OPTION(QUERYTRACEON 4136) to the end of your query.
Example:
SELECT * FROM dbo.MyTable T
WHERE T.Col1 = #Param1 and T.Col2 = #Param2
OPTION(QUERYTRACEON 4136)
I ended up having to convert the entire call into a single string that I passed to the SqlQuery function.
string sql = string.Format("exec spGetDupWOs #ProjectName=N'{0}',#City=N'{1}',#State=N'{2}',#ProjectNumber=N'{3}',#County=N'{4}',#Owner=N'{5}',#QuoteRecipients=N'{6}',#ProjectID={7}",
project.ProjectName,
project.City,
project.State,
project.ProjectNumber,
project.County,
project.Owner,
quoteRecipientsList,
"null");
Yes, I had to include the N prefix to the strings to make it work, I'm not sure why but it worked.
Thanks for all of the help everyone. I could not have solved this without your help.

Entity Framework Issue When running Stored Procedures

I have an issue with stored procedures and Entity Framework.
Let me explain what is happening... and what I have tried thus far.
I have a stored procedure, which does not do an awful lot
SELECT
COUNT(DISTINCT(EmailAddress)) AcceptedQuotes,
CONVERT (DATE,QuoteDate) QuoteDate
FROM
Quote Q
JOIN
Person P on Q.PersonPk = P.Pk
JOIN
Product Pr on Q.ProductPk = Pr.Pk
JOIN
Accepted A on Q.Pk = A.QuotePk
WHERE
QuoteDate between #startDate and #endDate
AND CompanyPk = #companyPk
AND FirstName != 'Test'
AND FirstName != 'test'
AND FirstName != 'EOH'
I want to execute this, and it works fine in SSMS and does not even take 1 second.
Now, I import this in to Entity Framework, it times out and I set the command timeout to 120...
Ok so what I have tried thus far and what I have tested.
If I use SqlCommand, SqlDataAdapter, DataTable way, with my own connection string, it executes as expected. When I use Entity Framework connection string in this scenario, it times out.
I altered my stored procedure to include "Recompile" option and also tried the SET ARITHABORT way, no luck, it times out when run through the EF.
Is this a bug in EF?
I have now just about decided to rewrite this using "old school" data access.
Also note that the EF executes fine with other stored procs, from the same database.
Any ideas or help would be greatly appreciated...
PS. I found this article, but no help either :(
http://www.sommarskog.se/query-plan-mysteries.html
This may be caused by Parameter Sniffing
When a stored procedure is compiled or recompiled, the parameter values passed for that invocation are "sniffed" and used for cardinality estimation. The net effect is that the plan is optimized as if those specific parameter values were used as literals in the query.
Using dummy variables that are not directly displayed on parameters also ensure execution plan stability without need to add recompile
hint, example below:
create procedure dbo.SearchProducts
#Keyword varchar(100) As Declare #Keyworddummy as varchar(100) Set #Keyworddummy = #Keyword select * from Products where Keyword like
#Keyworddummy
To prevent this and other similar situations, you can use the following query option:
OPTIMIZE FOR RECOMPILE
Disable auto-update statistics during the batch

Is "BEGIN TRAN" needed in order to get correct SCOPE_IDENTITY?

I'm using an SqlCommand like so:
command.CommandText = "INSERT INTO ... VALUES ...; SELECT SCOPE_IDENTITY();";
Is this enough, or do i need BEGIN TRAN etc.? (Mentioned here.)
I tried it first, of course, and it works fine. But will it work correctly even if there are two simultaneous inserts? (And I'm not sure how to test that.)
You don't need BEGIN TRAN. Scope_Identity() functions fine without it. Even if there are "simultaneous inserts". That is the whole point of the function--to return an answer for the current scope only.
Be aware that in less than SQL Server 2012, parallelism can break Scope_Identity(), so you must use the query hint WITH (MAXDOP 1) on your INSERT statement if you want it to work properly 100% of the time. You can read about this problem on Microsoft Connect. (It is theoretically fixed in Cumulative Update package 5 for SQL Server 2008 R2 Service Pack 1, but some people seem to think that may not be 100% true).
There is also the OUTPUT clause in SQL Server 2005 and up, which is another way to return data about your INSERT, either by sending a rowset to the client or by outputting to a table. Be aware that receiving the rowset does not actually prove the INSERT was properly committed... so you should probably use SET XACT_ABORT ON; in your stored procedure. here's an example of OUTPUT:
CREATE TABLE #AInsert(IDColumn);
INSERT dbo.TableA (OtherColumn) -- not the identity column
OUTPUT Inserted.IDColumn -- , Inserted.OtherColumn, Inserted.ColumnWithDefault
INTO #AInsert
SELECT 'abc';
-- Do something with #AInsert, which contains all the `IDColumn` values
-- that were inserted into the table. You can insert all columns, too,
-- as shown in the comments above
Not exactly the answer to your question, but if you are on SQL Server 2005 and above, consider using the OUTPUT clause, take a look this so answer for full sample, it's simple enough to implement
INSERT dbo.MyTable (col1, col2, col3)
OUTPUT INSERTED.idCol
VALUES ('a', 'b', 'c')
Scope_Identity and Begin Tran work independently, begin tran is used when you might want to rollback or commit a transaction at a given point within your query.

LINQ to SQL - Stored Procedure Return Type Error

On SQL 2005 I have a simple SP that selects rows from a table. The SP does not use temporary tables or return multiple result sets. In VS2010 I drag the SP from the Server Explorer to the DBML designer and the SP is added to the LINQ data context. Everything works okay. If I then script the table and SP on to another live SQL 2005 server I am getting the error "The return types for the following stored procedures could not be detected .. " Like I say, no temp tables or multiple result sets that would typically produce this error. Could there be something else on the server causing this?
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[spUsers]
AS
BEGIN
SET NOCOUNT ON;
SELECT top 100 * from Users
END
Make sure you have:
SET NOCOUNT ON;
as the first line in your SP after the 'BEGIN' statement.
If your SP does not have this, then it returns messages like
'10 Rows affected...'
Which Linq tries to interprete as part of the function result. Iv'e had it bite me loads of times!!
This is a known issue with Linq to SQL, and a frustrating one. It also seems to be somewhat unpredictable. The only way I have gotten around this, reliably, is by not having L2S call a stored procedure when I need it to return a result set. I have it call a table-valued UDF instead. L2S seems to have no problems with these, and I've never experienced any problems using them.
Okay, the reason it was failing on the live server is to do with privilages needed to access the meta-data on the DBMS. These are needed to create the return value data type from the SP. By elevating the SQL user account and then dragging the SP on onto the DBML designer .. bingo .. it works!
Use
create procedure Getxxxxxxx
#xxxxx uniqueidentifier
,#xxxxx uniqueidentifier
set fmtonly off
//you query
set fmtonly on

nvarchar(max) slowing stored procedure

From yesterday, i'm facing a problem:when i call a stored proc from c#,it lasts >5 in, but when i execute it directly from SSMS (in the server machine) its lasts less than 30 seconds.
I have searched in forums and went trough this great article http://www.sommarskog.se/query-plan-mysteries.html but no result.
The script contained in my proc is retrieving 10 columns among them a column called "article" of type nvarchar(max).
When i remove the article column from my Select ,my proc executes quickly.
To further my logic, i have created a new stored proc retrieving just Primary Key Column and nvarchar(max) column.
I'm reproducing the same behaviour.Here is my new proc=MyNewProc(lasts >5 min when called from c# and 0 Secondes in the server from SSMS)
CREATE PROCEDURE Student.GetStudents
AS
BEGIN
SET NOCOUNT ON
-----------------
SELECT StudentId,Article
FROM Students
WHERE Degree=1
END
MyNewProc returns just 2500 rows.
Is that normal? How can i improve that.
SELECT SUM(DATALENGTH(Article)) FROM Students WHERE Degree=1
the result is 13885838
You're probably transferring a lot of data over the network. That takes time.
Instead of returning article try returning LEFT(article, 50) to see if its an issue with the volume of data or not.
One thing to note is that SSMS will begin populating the results immediately while a C# application probably will not.
In SSMS, go to the following: Tools -> Options
Then go to Query Execution -> SQL Server -> Advanced
From here, look at what check boxes are checked and if there is something that is checked, SSMS will use this automatically when you execute a sproc from inside of it but when you execute it from C# (or whatever client you're using) it won't be used.
I had this same issue and found out that I needed to include the following line at the top of my sproc and it worked perfectly:
SET ARITHABORT ON;

Categories

Resources