Fill(DataTable) succeeds in testing, hangs in Production - c#

I have a console batch application which includes a process that uses SqlDataAdapter.Fill(DataTable) to perform a simple SELECT on a table.
private DataTable getMyTable(string conStr)
{
DataTable tb = new DataTable();
StringBuilder bSql = new StringBuilder();
bSql.AppendLine("SELECT * FROM MyDB.dbo.MyTable");
bSql.AppendLine("WHERE LEN(IdString) > 0");
try
{
string connStr = ConfigurationManager.ConnectionStrings[conStr].ConnectionString;
using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
using (SqlDataAdapter adpt = new SqlDataAdapter(bSql.ToString(), conn))
{
adpt.Fill(tb);
}
}
return tb;
}
catch (SqlException sx)
{
throw sx;
}
catch (Exception ex)
{
throw ex;
}
}
This method is executed synchronously, and was run successfully in several test environments over many months of testing -- both when started from the command-line or started under control of an AutoSys job.
When moved into production, however, the process hung up -- at the Fill method as nearly as we can tell. Worse, instead of timing out, it apparently started spawning new request threads, and after a couple hours, had consumed more than 5 GB of memory on the application server. This affected other active applications, making me very unpopular. There was no exception thrown.
The Connection String is about as plain-vanilla as they come.
"data source=SERVER\INSTANCE;initial catalog=MyDB;integrated security=True;"
Apologies if I use the wrong terms regarding what the SQL DBA reported below, but when we had a trace put on the SQL Server, it showed the Application ID (under which the AutoSys job was running) being accepted as a valid login. The server then appeared to process the SELECT query. However, it never returned a response. Instead, it went into an "awaiting command" status. The request thread appeared to remain open for a few minutes, then disappeared.
The DBA said there was no sign of a deadlock, but that he would need to monitor in real time to determine whether there was blocking.
This only occurs in the production environment; in test environments, the SQL Servers always responded in under a second.
The AutoSys Application ID is not a new one -- it's been used for several years with other SQL Servers and had no issues. The DBA even ran the SELECT query manually on the production SQL server logged in as that ID, and it responded normally.
We've been unable to reproduce the problem in any non-production environment, and hesitate to run it in production without a server admin standing by to kill the process. Our security requirements limit my access to view server logs and processes, and I usually have to engage another specialist to look at them for me.
We need to solve this problem sooner or later. The amount of data we're looking at is currently only a few rows, but will increase over the next few months. From what's happening, my best guess is that it involves communication and/or security between the application server and the SQL server.
Any additional ideas or items to investigate are welcome. Thanks everyone.

This may be tied to permissions. SQL Server does some odd things instead of giving a proper error message sometimes.
My suggestion, and this might improve performance anyway, is to write a stored procedure on the server side that executes the select, and call the stored procedure. This way, the DBA can ensure you have proper access to the stored procedure without allowing direct access to the table if for some reason that's being blocked, plus you should see a slight performance boost.

Though it may be caused by some strange permissions/ADO.NET issues as mentioned by #user1895086, I'd nonetheless would recommend to recheck a few things one more time:
Ensure that queries run manually by DBA and executed in your App are the same - either hardcode it or at least log just before running. It is better to be safe than sorry.
Try to select only few rows - it is always a good idea to not select the entire table if you can avoid it, and in our case SELECT TOP 1(or 100) query may not exhibit such problems. Perhaps there is just much more data than you think and ADO.Net just dutifully tries to load all those rows. Or perhaps not.
Try SqlDataReader to be sure that SqlDataAdapter does not cause any issues - yes, it uses the same DataAdapter internally, but we would at least exclude those additional operations from a list of suspects.
Try to get a hand on the dump with those 5 GB of memory - analyzing memory dumps is not a trivial task, but it won't be too difficult to understand what is eating those hefty chunks of memory. Because I somehow doubt that ADO.NET will just spawn a lot of additional objects for no reason.

Related

Why does Oledb Connection.Close() take far too long to execute?

During development of a desktop app to connect to a local database, I moved the database to a network location and now every time I call Connection.Close() the program hangs for 5-15 seconds. I would see this problem very infrequently when the database was stored on the local computer, but now that it's on the network, it hangs almost every time I attempt a Close(). The first call I make to the database I don't even query it, it's just a test connection that I open and close to make sure the user can connect, but it still hangs far too long.
I've seen this question asked before, but no one can offer a suggestion or solution to fix other than 'try using() {} to have c# clean it up.' This does not affect the Close() time in any way.
Is there an option in the connection string to address this issue? Does anyone know why this is happening?
The connection string I use is:
CONNECTION_STRING = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=\\NEWTORK\Shared\Database\Database.accdb; Persist Security Info=False;"
private void
Form_Login_Load(object sender, EventArgs e)
{
OleDbConnection Connection = new OleDbConnection();
Connection.ConnectionString = CONNECTION_STRING;
try
{
Console.Write("Connection Opening.....");
Connection.Open();
Console.WriteLine("Connection Opened");
Console.Write("Writing Status Text.....");
lbl_Status.Text = "Online";
Console.WriteLine("Written Status Text");
Console.Write("Connection Closing.....");
Connection.Close();
Console.WriteLine("Connection Closed");
}
catch (Exception Ex)
{
lbl_Status.Text = "Offline";
lbl_Status.ForeColor = System.Drawing.Color.FromArgb(255, 0, 0);
MessageBox.Show("Could not connect to Database");
}
}
In my output window, I see the opening messages and the writing status messages right away, but the app hangs just before the 'Console.Write("Connection Closing.....");' line. After 5-15 seconds, the close message appears in the window.
There are many connections in the app that do query the database and it seems to hang just before trying to close all of them as well. I do seems to notice that repeating the same query without closing the app sometimes results in quicker close times for the repeated close, but it always hangs during the first attempt for any query.
What ended up working for me:
When I was getting long lag times for the Connection.Close() method, I was using the Microsoft Access database engine 2016 (x64). For an unrelated reason, I needed to uninstall the 2016 engine and go with the 2010 (x86) version. Now my Connection.Close() times are averaging ~40 ms which is perfectly acceptable for my application.
If there are any pending transactions between the database and the program, then Close() will roll them back. It also has to request and drop it from the connection pool, which could take longer on a remote drive. Could this be your issue?
Here are the docs on the method.
To solve this, you could use a BackgroundWorker to execute it, like so:
var b = new BackgroundWorker();
b.DoWork += CloseDB;
b.RunWorkerCompleted += someMethodAfterClose;
b.RunWorkerAsync();
CloseDB:
public void CloseDB(object sender, DoWorkEventArgs e) {
someConnection.Close();
}
Often this can be the server settings. If the firewall + windows defender is active, then it scans all "file" accessing - the result is very slow opens, and of course close().
Try running the computer where the shared folder resides with firewall and windows defender turned off. I seen this often fix the large delays. Of course, using a socket based technology would eliminate this issue (eg: server based). However, you have what you have, and often it is not your code speed, but the "windows file" system, and that of network and anti-virus software that is the cause of this slowdown.
This might get flagged as "not an answer", but I have this problem as well, and no one seems to have found the real explanation, so instead of creating a redundant question, here are some of my symptoms:
Started happening much more often when the office updated to Windows 10 (from Windows 7).
Happens frequently but not always. Sometimes the OleDb connection close/dispose is very quick, sometimes it hangs ~10-15 s. The variation is seemingly random for any given connection attempt at any time, even with the same Access database, same machine, and same process.
Hanging can happen for databases located both locally and on network, though haven't tested if one is more frequent than the other.
Happens even if connection makes no changes or transactions (i.e. just SELECT queries).
Happens only with OleDb connections, i.e., a user opening and closing database via the Access interface is fine.
Update
In desperation, I tried the suggestion of closing the connection in a background thread, to avoid holding up the main thread during this process. But when I did that, whenever a subsequent connection was initiated later on, got this error:
Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt
Googling indicates this seems to happen with many people when dealing with Access database connections, but often for unknown reasons.
So I tried a different suggestion of changing conn string to include OLE DB Services=-1;. This appeared to fix issue at first. No expert on this, far as I can tell it basically avoids the hanging-on-close problem by leaving some of the connection's resources open behind the scenes for reuse, even after disposing the conn object. Fine with me...except eventually it appears to close those resources (probably some timeout), and then when a connection is later made, back to the inexplicable AccessViolationException above.
Potential Solution
From piecing together various web comments and my own experimentation:
OleDb does not play nice with multi-threading.
Closing the last open Access connection in an app, no matter what database, seems to trigger the unloading of some resources inside the OleDb library itself, hence this is a potentially time-consuming operation.
So what I did, add an empty Access database hidden inside my app, and on startup open an OleDb connection to it. I do NOT dispose the connection and maintain reference to the connection to keep it from closing on its own. That way, any disposing of subsequent connections never trigger the unloading of whatever resources OleDb is keeping around.
It's a hack but so far this appears to fix the original problem.
Of course the real answer is avoid Access databases!

SQL timeout on last connection

I have a weird issue. I have a C# application that makes multiple connections to SQL (7 in total). Everything had been working fine for a while and then all of the sudden, SQL times out on the last connection. That connection is pretty simple
public static void APP()
{
using (SqlConnection conn7 = new SqlConnection(ConfigurationManager.ConnectionStrings["Connect"].ConnectionString))
{
conn7.Open();
SqlCommand cmd7 = new SqlCommand("sp_proc", conn7);
cmd7.CommandType = System.Data.CommandType.StoredProcedure;
cmd7.ExecuteNonQuery();
conn7.Close();
}
}
My connection string looks like this.
add name="Connect" connectionString="Data Source=Server; Initial Catalog=DB; User ID=User; Password=password" providerName="System.Data.SqlClient"
I am doing a using on each one and I am closing each connection at the end of each class. Has anyone seen anything like this happen? Do I have too many connections?
I run each class in order from Main.
If it is timing out, there are 3 likely scenarios:
sp_proc is simply taking too long to run; you'll need to address the code
there is some kind of locking that is making it impossible to complete (perhaps an open transaction on a competing SPID that has touched the same data and taken conflicting locks)
there is some unrelated server load happening at the same time that is making it run too slow (this is unlikely to be the issue if it happens reliably)
I would recommend adding
cmd7.CommandTimeout = 6000
the time out is measured in seconds so put a time out that is acceptable for the users of the application,
I'd recommend this for all your SQL connections too just as a standard this way you should always have sufficient time to get the data.
one thing you might want to do is run a trace \ sql profile on the database that youre running against and also check for locking of some kind.
If this is timing out, I would think that there is a process that is being suspended or a lock of some kind somewhere

Disabling SQL Server's caching through .NET code

I am currently calling up several stored procedures in some .NET code, SqlConnection. I'd like to disable the caching done by SQL Server, so that I can measure performance periodically (I'm gonna be comparing it to another server that likely won't have any cached data either). Is this possible to do without modifying the sprocs?
This is the code that I am currently using:
using (SqlConnection connection = new SqlConnection(/* connection string goes here */)) {
SqlCommand command = new SqlCommand(procName, connection);
command.Parameters.AddRange(parameters);
command.CommandType = System.Data.CommandType.StoredProcedure;
connection.Open();
SqlDataReader r = command.ExecuteReader();
// todo: read data here
r.Close();
connection.Close();
}
First thing, by "cacheing" here I'm assuming you're referring to the Execution Plan Cache. Once SQL Server figures out the best order to execute your statements, it stores it for a while. This problem is commonly known as "Parameter Sniffing". This is what you clear when you run dbcc freeproccache. Unfortunately, that's an admin-privileged command and it affects all connections.
The root of the problem is that your SQL probably performs differently with a different set of parameters. SQL Server will only store the execution plan of the first execution it sees and the parameters associated with it. So if the arguments on first execution are good for the common case, your app will perform fine. But once in a while, the wrong arguments will get used on first execution and your entire application can perform poorly.
There are a number of ways to optimize your SQL statement to reduce the impact of this, but it's not completely avoidable.
Generate the SQL dynamically - You take the performance hit of generating a query plan on each execution, but this may be worth it if using the wrong execution plan causes your query to never return. I suggest this path, though it is more cumbersome. I found SET STATISTICS TIME ON and SQL Profiler helpful in reducing the plan generation time. The biggest improvement came from using 3-part naming (owner.schema.table) for the tables.
Specify a "good set" of initial parameters for your query with query hints.
SELECT Col1, Col2
FROM dbo.MySchema.MyTab
WHERE Col1=#Parameter
OPTION (OPTIMIZE FOR (#Parameter='value'));
This link describe the parameter sniffing problem fairly well. This was a bigger problem in SQL 2005. Later versions of SQL did a better job of avoiding this.

Unusual latency issue when using MySql from C#

I am a relative novice to MySql and I've run out of possible ideas so looking for a bit of help.
We recently started using MySql and we are seeing in multiple environments a consistent latency issue with calls to MySql. The latency is not present when running the queries using Workbench.
Although it is happening with many calls, I cut the code down to very simple calls like this for testing.
cmd.CommandText =
"SELECT 'test'";
cmd.CommandType = CommandType.Text;
Console.WriteLine("before execute:{0}",timer.ElapsedMilliseconds);
cmd.ExecuteNonQuery();
I even changed the call to NonQuery to make sure that as little as possible was being returned. Consistently every call is taking 200-300ms when I use our dev/qa servers. If I run it locally, runs in just a millisecond or two. I also tried multiple executes in a row without closing connection to eliminate connections and pools. I believe the bad performance is specifically when the command is being executed.
After a week of back and forth, this issue was isolated to our VIP. I am not a network person so apologies if I don't get this description quite correct.
The VIP apparently had a small packet size set for the network. This caused the select statement packets to become fragmented and adding the latency. We just made a change to our VIP and the problem has gone away.
Marking question answered.

Should I open and close db for each query?

I am using old school ADO.net with C# so there is a lot of this kind of code. Is it better to make one function per query and open and close db each time, or run multiple queries with the same connection obect? Below is just one query for example purpose only.
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["DBConnectMain"].ConnectionString))
{
// Add user to database, so they can't vote multiple times
string sql = " insert into PollRespondents (PollId, MemberId) values (#PollId, #MemberId)";
SqlCommand sqlCmd = new SqlCommand(sql, connection);
sqlCmd.Parameters.Add("#PollId", SqlDbType.Int);
sqlCmd.Parameters["#PollId"].Value = PollId;
sqlCmd.Parameters.Add("#MemberId", SqlDbType.Int);
sqlCmd.Parameters["#MemberId"].Value = Session["MemberId"];
try
{
connection.Open();
Int32 rowsAffected = (int)sqlCmd.ExecuteNonQuery();
}
catch (Exception ex)
{
//Console.WriteLine(ex.Message);
}
}
Well, you could measure; but as long as you are using the connections (so they are disposed even if you get an exception), and have pooling enabled (for SQL server it is enabled by default) it won't matter hugely; closing (or disposing) just returns the underlying connection to the pool. Both approaches work. Sorry, that doesn't help much ;p
Just don't keep an open connection while you do other lengthy non-db work. Close it and re-open it; you may actually get the same underlying connection back, but somebody else (another thread) might have made use of it while you weren't.
For most cases, opening and closing a connection per query is the way to go (as Chris Lively pointed out). However, There are some cases where you'll run into performance bottlenecks with this solution though.
For example, when dealing with very large volumes of relatively quick to execute queries that are dependent on previous results, I might suggest executing multiple queries in a single connection. You might encounter this when doing batch processing of data, or data massaging for reporting purposes.
Always be sure to use the 'using' wrapper to avoid mem leaks though, regardless of which pattern you follow.
If the methods are structured such that a single command is executed within a single method, then Yes: instantiate and dispose of the connection for each command.
If the methods are structured such that you have multiple commands executed in the same block of code, then the outer block needs to be the using clause for the connection.
ADO is very good about connection pooling so instantiating and disposing of the command object is going to be extremely fast and really won't impact performance.
As an example, we have a few pages that will execute update to 50 queries in order to compose the page. Because there is branching code to determine the queries to run, we have each of them wrapped with their own using (connection...) clauses.
We once ripped those out and grabbed one connection object and passed it to the individual methods. This had exactly zero performance improvement while complicating the hell out of the code with all the exception clauses every where to ensure the connection was properly disposed at the end. At the end of the test, we rolled back the code to how it was before. Much cleaner to know exactly what was going on and when a connection was being used.
Well, as always, it depends. If you have 5 database call to make within the same method call, you should probably use a single connection.
However, holding onto connection while nothing is happening isn't usually advised from a scalability standpoint.
ADO.NET is old school now? Wow, you just made me feel old. To me Rogue Wave ODBC using Borland C++ on Windows 3.1 is old school.
To answer, in general you want to understand how your data drivers work. Understand such concepts as connection pooling and learn to profile the transaction costs associate with connecting / disconnecting and executing queries. Then take that knowledge and apply it it your situation.

Categories