Strange behavior in SQL Server 2012 - c#

I am currently trying to stabilize an asp.net 2.0 website.
I am about 95% sure that the main problem in the stability of the system is that the C# code is leaking SQL connections.
The accepted answer on this post describes exactly my problem:
Why is my SqlCommand returning a string when it should be an int?
That beign said, I am currently running this sql statement to pinpoint the possible problem:
SELECT S.spid, login_time, last_batch, status, hostname, program_name, cmd,
(
select text from sys.dm_exec_sql_text(S.sql_handle)
) as last_sql
FROM sys.sysprocesses S
where dbid > 0
and DB_NAME(dbid) = 'db'
and loginame = 'login'
order by last_batch asc
What I find weird is that the login used to connect to the DB from the website keeps returning last_sql as:
CREATE PROCEDURE name
-- Add the parameters for the stored procedure here
...
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
... Procedure code
The question is, why would a create procedure statement be run over and over?
Also, is it a bad practice to have 3-4 (not so active) website connecting to DB using the same connection string?

Related

Call to SQL Server stored procedure failing in certain cases

I am struggling to understand why a certain stored procedure has stopped working in a few of my databases, but not in others. I am hoping that someone can help me resolve this issue.
Introduction
I inherited an existing C# application that connects to a choice of SQL Server databases depending on the culture parameter supplied to the program. Example: Passing "en-CA" causes the program to connect to the database with English-Canada content. Passing "fr-CA" causes the program to connect to the database with French-Canada content. The databases are derived from a common root database. The databases are essentially identical except for the contents of many of the NVARCHAR fields. (This variety of databases is used solely during development for testing various cultures.)
Both databases use the following collation: SQL_Latin1_General_CP1_CI_AS
Issue
I am not sure when this issue started, but the current situation is that if I call a certain stored procedure from the fr-CA database, then it is not executed at all. (I will explain this in more detail.) No error code is returned to the program. the program acts as if no record was found.
However, if I call the same stored procedure from the en-CA database, then it functions as expected and a record is returned to the program.
Attempted Steps
If I run the stored procedure from SSMS, then it executes properly.
I have attempted copying the definition of the stored procedure from the database where it is executing properly to the database where it is not executing properly. This did not resolve the issue.
I did try debugging with the SQL Profiler. When I ran the stored procedure against both databases, I see an entry in the trace. I do not see any errors listed. I will admit that I am a newbie when it comes to using the Profiler.
When I say that the stored procedure is not being executed, I base this on the following test. I created a debug table with a couple of fields:
create table DEBUG
(
Id INTEGER,
Line NVARCHAR(100)
);
At the top of the stored procedure, in both databases, I inserted as the very first line the following statement:
INSERT INTO dbo.DEBUG VALUES (1, 'Top of Atms_Get_Tray_Infos');
When my code calls the stored procedure, I expect to see a line in the DEBUG table.
If I run the program against the en-CA database, I do see the expected line:
If I empty the DEBUG table and then run the program against the fr-CA database, the DEBUG table remains empty. This fact leads me to believe that the stored procedure is not being executed.
Database details
Here is the definition of the stored procedure with the debug line:
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[Atms_Get_Tray_Infos]
#TrayNo AS NVARCHAR(10)
AS
BEGIN
-- DEBUG
INSERT INTO dbo.DEBUG VALUES (1, 'Top of Atms_Get_Tray_Infos');
-- SET NOCOUNT ON added to prevent extra result sets from interfering with SELECT statements.
SET NOCOUNT ON;
BEGIN TRY
SELECT HTRAY.SEQ_HIST_PLATEAU AS TRAYNO,
HTRAY.DATE_EXPIRATION_DATE AS EXPIRY,
HTRAY.DATE_UTILISATION_DATE AS DATEUSED,
HTRAY.LADATE_LAVAGE AS WASHDATE,
HSTE.SEQ_CODE_QUAL_STERIL AS QLTYCODE,
HSTE.NO_CHARGE AS CHGNO,
HSTE.TEST_BIO_BON AS BIOTEST,
FRML.CODE AS FORMULACODE,
TRAY.NO_TYPE_PLATEAU AS TRAYCODE,
TRAY.DESCRIPTION_S,
TRAY.EstUrgent AS URGENT
FROM dbo.HIST_PLAT HTRAY
LEFT JOIN dbo.HIST_CHARG_STE HSTE ON HTRAY.LAST_SEQ_HIST_CHARGE_STERIL = HSTE.SEQ_HIST_CHARGE_STERIL
INNER JOIN dbo.PLATEAUX TRAY ON TRAY.SEQ_PLATEAU = HTRAY.NO_SEQ_PLATEAU
INNER JOIN dbo.FORMULE FRML ON HSTE.SEQ_FORMULE = FRML.SEQ_FORMULE
WHERE HTRAY.SEQ_HIST_PLATEAU = #TrayNo
END TRY
BEGIN CATCH
DECLARE #ErrorMessage NVARCHAR(4000);
DECLARE #ErrorSeverity INT;
DECLARE #ErrorState INT;
SELECT #ErrorMessage = ERROR_MESSAGE(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE();
RAISERROR (#ErrorMessage, #ErrorSeverity, #ErrorState);
END CATCH
END
I appreciate any bit of assistance that will lead me to a resolution of this issue. Thanks!
Paolo's comment, above, caused me to investigate the actual C# code that calls the stored procedure.
The code is convoluted for the sake of being convoluted, in my opinion.
There is a method is some class that handles all calls to stored procedures. I replaced that code with this basic code:
DataSet dataSet = new DataSet("ReturnDs");
using (var connection = new System.Data.SqlClient.SqlConnection(theConnectStg))
{
using (var command = new System.Data.SqlClient.SqlCommand(theStoreProcName, connection))
{
using (var dataAdapter = new System.Data.SqlClient.SqlDataAdapter(command))
{
command.CommandType = CommandType.StoredProcedure;
if (theParameterList != null)
{
foreach (String str1 in theParameterList.ToArray())
{
String parameterName = str1.Substring(0, str1.IndexOf(":"));
String str2 = str1.Substring(str1.IndexOf(":") + 1);
dataAdapter.SelectCommand.Parameters.Add(new SqlParameter(parameterName, SqlDbType.VarChar, 128));
dataAdapter.SelectCommand.Parameters[parameterName].Value = (object)str2;
}
}
dataAdapter.Fill(dataSet);
}
}
}
return dataSet;
To satisfy your curiosity, the theParameterList parameter is an array of parameters, each in the form "#variable:value". I'm not a fan, but I am stuck with the existing code for now.
So, why did the previous code fail for certain databases? I still do not know. I am curious, but I do not wish to spend any more time on this issue. My brain is tired.
Thanks for the clue, Paolo!

Getting a timeout error from a stored procedure in C#

I have this stored procedure to retrieve data from a database (dynamic query). I am calling this stored procedure from C# code, passing two parameters to this stored procedure:
ALTER PROCEDURE [dbo].[GetCompleteCPTDetails]
#Practice_Short_Name varchar(50),
#Uploaded_Date nvarchar(max)
AS
BEGIN
DECLARE #CPTtablename nvarchar(300)
DECLARE #vQuery NVARCHAR(max)
DECLARE #upldate nvarchar(100)
SET #upldate = #Uploaded_Date
SET #CPTtablename = 'ACER_CLAIMS_MASTER_DETAIL_Hist_' + #Practice_Short_Name
SET #vQuery = 'SELECT Practice_Short_Name, Service_Date_From, Carrier_Name,
Location_Description, Patient_Number, Patient_First_Name,
Patient_Last_Name, Voucher_Number, Procedure_Code, Service_Fees,
Service_Payments, Service_Adjustments, Acer_Status, Acer_Allowed_Amount
FROM ' +#CPTtablename+'
WHERE Uploaded_Date =''' + #upldate + '''
ORDER BY acer_status ASC, Service_Date_From DESC, Patient_First_Name ASC'
EXEC (#vQuery)
END
But when I am running this query I get a timeout error. If I assign value to my parameters in the stored procedure and run it from query windows then it is showing correct data.
Can anyone please explain to me why I get a timeout error if I am calling it from C#?
That is a pretty simple where and order by.
Unless that is just a massive table with no indexes that should be fast.
Is there an index on Uploaded_Date and is it not fragmented.
Also an index on the sort would help.
Are you loading everything into a DataTable?
If so try loading into DataReader.
Try a top 1 and remove the order by.
If that does not return then you have connection issue as no way that query should time out.
The other thing to try is with (no lock) to see if it is a lock problem.
Why is #Uploaded_Date nvarchar(max)?
Is that a date or not?
There can be many solutions to this problem, as problem areas can be different in each case.
But most common:
Check & increase sqlcommand timeout in your application
Try calling this SP asynchronously
Also i would like to know, your application on the same machine where DB resides?

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.

Stored Procedure Much Slower in .NET SqlCommand than in SSMS

I have a stored procedure that is executing an INSERT statement that we are seeing significant delays when executing. When running it from our C# .NET application to insert 30 records in a row, it's taking roughly 4 seconds total to complete (only counting the tame it takes to run the SqlCommand.ExecuteNonQuery() method). However, calling the same exact stored procedure from within SQL Server Management Studio the same number of times only takes about 0.4 seconds. I can't figure out what's different between the 2 setups that would make such a difference of 10x speed.
I have tried all of the following with no noticeable change in speed:
Creating the stored procedure "WITH RECOMPILE"
Checking all of the "SET" values that are configured within SSMS and C#. The only difference one was SET ARITHABORT, which was ON in SSMS and OFF when called from the .NET application. Adding "SET ARITHABORT ON" to the start of the stored procedure made no difference, though.
Removed all default values from the sproc parameters
The code used to call the stored procedure from the .NET application is:
using (SqlConnection newConn = new SqlConnection(connectionString))
{
using (SqlCommand uCmd = new SqlCommand("sproc_name", newConn))
{
uCmd.CommandType = CommandType.StoredProcedure;
uCmd.Connection.Open();
//About 15 parameters added using:
uCmd.Parameters.AddWithValue("#ParamName", value);
...
//One output parameter
SqlParameter paramOUT = new SqlParameter("#OutPutKey", SqlDbType.UniqueIdentifier);
paramOUT.Direction = ParameterDirection.Output;
uCmd.Parameters.Add(paramOUT);
uCmd.ExecuteNonQuery();
uCmd.Connection.Close();
}
}
The stored procedure itself is just a list of set commands (SET ANSI_NULLS ON, SET QUOTED_IDENTIFIER ON, SET ARITHABORT ON), a list of non-defaulted parameters, and the setting of the output variable that will be the new uniqueidentifier that will be inserted as the primary key in the table, followed by the INSERT statement itself.
The application is build on .NET 4 and the SQL server is MS SQL Server 2005.
Here is an example of the insert stored procedure it's calling:
alter procedure InsertStuff
#Field1 uniqueidentifier,
#Field2 datetime,
...
#CreateDate datetime,
#PrimaryKEY uniqueidentifier OUTPUT
AS
declare #newCreateDate datetime
set #newCreateDate=getDate()
set #PrimaryKEY = NEWID()
INSERT INTO [dbo].[Table]
(
Field1,
Field2,
...
CreateDate,
PrimaryKEY
)
VALUES
(
#Field1,
#Field2,
...
#newCreateDate,
#PrimaryKEY
)
Likely the issue is that every execute command call does a network hop, where as ssms will send all 30 commands to the server at once in a batch. I believe by default SSMS will send all 30 statements as a single batch, but if you've changed other settings that may impact things as well.
Also, make sure youre not opening and closing the connection each time. While connection pools may make that a non issue, I wouldn't leave it to chance.

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

Categories

Resources