Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SqlDataAdapter.Fill method slow

Why would a stored procedure that returns a table with 9 columns, 89 rows using this code take 60 seconds to execute (.NET 1.1) when it takes < 1 second to run in SQL Server Management Studio? It's being run on the local machine so little/no network latency, fast dev machine

Dim command As SqlCommand = New SqlCommand(procName, CreateConnection()) command.CommandType = CommandType.StoredProcedure command.CommandTimeout = _commandTimeOut Try    Dim adapter As new SqlDataAdapter(command)    Dim i as Integer    For i=0 to parameters.Length-1       command.Parameters.Add(parameters(i))    Next    adapter.Fill(tableToFill)    adapter.Dispose() Finally    command.Dispose() End Try 

my paramter array is typed (for this SQL it's only a single parameter)

parameters(0) = New SqlParameter("@UserID", SqlDbType.BigInt, 0, ParameterDirection.Input, True, 19, 0, "", DataRowVersion.Current, userID) 

The Stored procedure is only a select statement like so:

ALTER PROC [dbo].[web_GetMyStuffFool]    (@UserID BIGINT) AS SELECT Col1, Col2, Col3, Col3, Col3, Col3, Col3, Col3, Col3 FROM [Table] 
like image 635
Steve Wright Avatar asked Oct 30 '08 15:10

Steve Wright


People also ask

Is SqlDataReader faster than SqlDataAdapter?

SqlDataReader will be faster than SQlDataAdapter because it works in a connected state which means the first result is returned from query as soon as its available ..

What does SqlDataAdapter fill do?

The Fill method of the DataAdapter is used to populate a DataSet with the results of the SelectCommand of the DataAdapter . Fill takes as its arguments a DataSet to be populated, and a DataTable object, or the name of the DataTable to be filled with the rows returned from the SelectCommand .

Does SqlDataAdapter always close the connection?

Yes, if you're opening it, you're responsible for closing it yourself.

Why do we use SqlDataAdapter?

SqlDataAdapter is used in conjunction with SqlConnection and SqlCommand to increase performance when connecting to a SQL Server database. If you are using SQL Server stored procedures to edit or delete data using a DataAdapter , make sure that you do not use SET NOCOUNT ON in the stored procedure definition.


2 Answers

First, make sure you are profiling the performance properly. For example, run the query twice from ADO.NET and see if the second time is much faster than the first time. This removes the overhead of waiting for the app to compile and the debugging infrastructure to ramp up.

Next, check the default settings in ADO.NET and SSMS. For example, if you run SET ARITHABORT OFF in SSMS, you might find that it now runs as slow as when using ADO.NET.

What I found once was that SET ARITHABORT OFF in SSMS caused the stored proc to be recompiled and/or different statistics to be used. And suddenly both SSMS and ADO.NET were reporting roughly the same execution time. Note that ARITHABORT is not itself the cause of the slowdown, it's that it causes a recompilation, and you are ending up with two different plans due to parameter sniffing. It is likely that parameter sniffing is the actual problem needing to be solved.

To check this, look at the execution plans for each run, specifically the sys.dm_exec_cached_plans table. They will probably be different.

Running 'sp_recompile' on a specific stored procedure will drop the associated execution plan from the cache, which then gives SQL Server a chance to create a possibly more appropriate plan at the next execution of the procedure.

Finally, you can try the "nuke it from orbit" approach of cleaning out the entire procedure cache and memory buffers using SSMS:

DBCC DROPCLEANBUFFERS DBCC FREEPROCCACHE 

Doing so before you test your query prevents usage of cached execution plans and previous results cache.

like image 129
HTTP 410 Avatar answered Oct 11 '22 15:10

HTTP 410


Here is what I ended up doing:

I executed the following SQL statement to rebuild the indexes on all tables in the database:

EXEC <databasename>..sp_MSforeachtable @command1='DBCC DBREINDEX (''*'')', @replacechar='*' -- Replace <databasename> with the name of your database 

If I wanted to see the same behavior in SSMS, I ran the proc like this:

SET ARITHABORT OFF EXEC [dbo].[web_GetMyStuffFool] @UserID=1 SET ARITHABORT ON 

Another way to bypass this is to add this to your code:

MyConnection.Execute "SET ARITHABORT ON" 
like image 38
Steve Wright Avatar answered Oct 11 '22 17:10

Steve Wright