MySQL .Net connection pool connection.Open() very slow - c#

Version 6.4.4:
Using the most basic implementation of MySqlConnection, the following code takes 2-5 seconds per connection when preloading the connection pool to reach the "Min Pool Size" configured in my connection string.
Any ideas why it is taking so long, how to fix, or workarounds?
Connection String:
<add name="users" connectionString="server=192.168.1.2;User Id=dbuser;password=dbpassword;database=users;Pooling=true;Min Pool Size=10;Max Pool Size=50;Persist Security Info=True;" />
Code
private static void MySqlConnectionTester()
{
string connectionString = ConfigurationManager.ConnectionStrings["users"].ConnectionString;
using (var connection = new MySqlConnection(connectionString))
{
using (var command = connection.CreateCommand())
{
command.CommandText = "select * from users;";
try
{
connection.Open(); // This line hangs until "Min Pool Size" is reached.
using (var reader = command.ExecuteReader())
{
while(reader.Read())
{
// Read results
}
}
}
catch(Exception ex)
{
// Log exception
}
finally
{
connection.Close();
}
}
}
}

At MySQL's homepage they write that you should avoid creating, opening and closing the connection object youself, instead you should use the helper class which should work better with connectionpooling.
I have not tested it, but was something I just read :)

The issue was also present on our side with MySql Connector .Net 6.6.5. The MySql Connector .Net 6.8.3 is solving this issue.
Fabrice

Related

C# code is unable to connect to Azure SQL database

I am trying to connect to a sample database I have created in Azure using C# (.NET Core 3.1)
I have enabled my IP address within Azure's Firewall rules.
I am able to use VS2019's SQL Server Object Explorer to connect and view the database within with no problems.
However, when I run a simple C# app on the same PC to execute a query to count the number of records in a table, it throws the following exception at the point where the connection is opened (conn.Open());
A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 0 - The requested address is not valid in its context.)
The C# code;
using System;
using System.Data.SqlClient;
namespace AzureSql2
{
class Program
{
static void Main(string[] args)
{
string connStr = " Server=tcp:beaconsqlsql.database.windows.net,1433;Initial Catalog=MRP2;Persist Security Info=False;User ID=beaconadmin;Password=********;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;";
Console.WriteLine("Building connection");
try
{
using (var conn = new SqlConnection(connStr))
{
Console.WriteLine("Creating command");
using (var command = conn.CreateCommand())
{
command.CommandText = "SELECT COUNT(*) FROM [dbo].[Table]";
Console.WriteLine("Opening connection");
conn.Open();
Console.WriteLine("Reading database");
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine("Record count: {0}", reader.GetInt32(0));
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
}
Console.WriteLine("Press Enter to exit");
Console.ReadLine();
}
}
}
I've tried temporarily turning off the firewall on my PC, but that made no difference.
The fact that SQL Server Object Explorer can connect but the C# code cannot makes it sound like there's a problem with the C# code, but I can't see any differences between it and the samples I've looked at.
I created one Azure SQL database and allowed my client IP like below :-
I created one .Net Console application and ran your code, I replaced
using System.Data.SqlClient
with
using Microsoft.Data.SqlClient
You can use any of the above packages.
Copied connection string from Azure Portal > Azure SQL server > Connection string refer below :-
C# Code:-
using System;
using System.Linq.Expressions;
using Microsoft.Data.SqlClient;
namespace AzureSql2
{
class Program
{
static void Main(string[] args)
{
string connStr = "Server=tcp:sqlservername.database.windows.net,1433;Initial Catalog=sqldbname;Persist Security Info=False;User ID=username;Password=password;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;";
Console.WriteLine("Building connection");
try
{
using (var conn = new SqlConnection(connStr))
{
Console.WriteLine("Creating command");
using (var command = conn.CreateCommand())
{
command.CommandText = "SELECT * FROM Products";
Console.WriteLine("Opening connection");
conn.Open();
Console.WriteLine("Reading database");
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine("Record count: {0}", reader.GetInt32(0));
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
}
Console.WriteLine("Press Enter to exit");
Console.ReadLine();
}
}
}
Output :-
I tried to run the code with the connection string format you mentioned in the comments :-
Data Source=azuresqlservername.database.windows.net;Initial Catalog=databasename;User ID=siliconuser;Password=password;Connect Timeout=30;Encrypt=True;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False
And I was able to run the same code above and got the desired output:-
When I tried to change the Azure SQL server name in the connection string, I got the same error code as yours, refer below :-
Verify if your connection string has any syntax missing and validate it from Azure Portal.
I ended up taking a copy of the project home and running it on my home PC, and it worked correctly and reliably (after telling Azure to allow that IP address as well)
It turned out the answer was embarrassingly obvious - in addition to the standard Windows 10 firewall, my work PC is running another virus protection/firewall software, and that also needed to be told to allow the app thru.
Definitely one to remember for next time... Although I am kind of intrigued that on two occasions (once mentioned above, once afterwards) out of a few hundred attempts the app did manage to get thru and connect.
Thank you everyone for your answers and help.

SqlCeConnection is way slower than SqlConnection

In my C# app I can switch between Online SQL-Server connection and local SQLCE (sdf file) connection. Both DBs are the same in structure and indexes.
But using the local SDF file through SqlCeConnection is so much slower - 20 times slower when doing a lot of calls.
Example:
using (DbConnection connection = new SqlCeConnection(ConnectionString))
{
connection.Open();
using (DbCommand cmd = GetSqlCommand("select * from t", connection))
{
try
{
var reader = cmd.ExecuteReader();
while (reader.Read())
{
...
}
reader.Close();
}
catch (Exception e) { }
}
}
What is going on here - can I optimize that?
Keep a single connection open and unused for the lifetime of your app, SQL Compact does not have connection pooling.
In addition, opening a SqlCeConnection can be slow because of:
The database file has been created on another platform
The ACL (Access Control List) on the RSA folder is corrupt
Invalid Internet Proxy configuration
More info here: http://erikej.blogspot.dk/2013/08/faq-why-is-opening-my-sql-server.html

Connection to SQL Server throws exception

I have a task where I need to write a simple application to process some data from SQL Server. The process is working with dummy data, but I just can't connect to the server to get the valid data.
I have a code like this:
string ConnectionString = #"Server=----;Database=----;User ID=----;Password=*******";
string field1, field2;
try
{
using (SqlConnection Connection = new SqlConnection(ConnectionString))
{
Connection.Open();
using (IDbCommand dbcmd = Connection.CreateCommand())
{
string sql = "SELECT * from [---].[dbo].[Components]";
dbcmd.CommandText = sql;
using (IDataReader reader = dbcmd.ExecuteReader())
{
while (reader.Read())
{
field1 = (string)reader["field1"];
field2 = (string)reader["field2"];
}
}
}
}
Console.WriteLine("Success");
}
catch (Exception e)
{
Console.WriteLine("Failure");
Console.WriteLine(e.Message);
}
My problem is, that if I run this code in a simple C# application, it works, no problem, but when I try to use it in the Xamarin application, the Connection.Open() throws an exception with the message:
server does not exist or connection refused
And here it is my problem, I don't really know why this happenes, when I run it as an app. The problem shows up even in android emulator, which theoretically uses the same network as the c# application which works.
Do I need to change options in the app, or the problems is at the server side?
I know that it's not the best idea to connect directly, but the app will be used internally on a secured network, so that this shouldn't be the problem.
Android emulator does not set correct DNS network parameters, so your application is not able to resolve the domain name of your SQL server.
So in your connection string try setting the IP address of SQL server instead of domain name.
string ConnectionString = #"Server=192.168.XXX.XXX;Database=MyDatabase;User ID=MyUser;Password=MyPassword";

How to disable connection pool?

Connection string that my app is using to connect to DB is the following:
private const string oradb = "Data Source=(DESCRIPTION=(ADDRESS_LIST="
+ "(ADDRESS=(PROTOCOL=TCP)(HOST=host.name)(PORT=1521)))"
+ "(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=service.name)));"
+ "User Id=myusername;Password=mypass;";
In all DB access points of my app I am using the following pattern:
OracleConnection conn = new OracleConnection(oradb);
try
{
Console.WriteLine("Opening DB Connection...");
conn.Open();
string queryString = string.Format(#"SELECT ...");
using (OracleCommand command = new OracleCommand(queryString, conn))
{
using (OracleDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
...
}
}
}
}
catch (Exception e)
{
Console.WriteLine("Exception occured during DB access: {0}", e.Message);
dbr.Error = e.Message;
}
finally
{
Console.WriteLine("Closing DB connection");
conn.Close();
conn.Dispose();
}
For sure I am properly handling exceptions and in try/catch/finally closing AND disposing connection object. However, often I am receiving oracle service message that I am holding oracle sessions. Moreover, if I just leave my app open and next day try to make operation, I am getting ora-12537 network session end of file exception first time, then second attempt is going through. After some reading it looks like I have to disable connection pool. If this is the right way to solve, how to disable pool? If not, then what other thing can be wrong?
You could add Pooling=False in the connection string, but this means a new connection is created each time.
+ "User Id=myusername;Password=mypass;Pooling=False;";
Take a look at this article, it might help with your issue. Also, take a look at this website page, specifically the Using Connection Pooling section

Working example with ReliableSqlConnection and Azure

I have done everything i read on the internet, tutorials, but nothing seem to work!
https://www.google.com/search?q=reliablesqlconnection+azure
http://geekswithblogs.net/ScottKlein/archive/2012/01/27/understanding-sql-azure-throttling-and-implementing-retry-logic.aspx
i already install all the hand on lab:
http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=6932
The NuGets
PM> Install-Package EnterpriseLibrary.WindowsAzure.TransientFaultHandling
PM> Install-Package CommonServiceLocator
All the config I found to solve specific problems (just to mention one).
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="RetryPolicyConfiguration" type="Microsoft.Practices.EnterpriseLibrary.WindowsAzure.TransientFaultHandling.Configuration.RetryPolicyConfigurationSettings, ... />
<section name="typeRegistrationProvidersConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.TypeRegistrationProvidersConfigurationSection, Microsoft.Practices.EnterpriseLibrary.Common... />
</configSections>
<RetryPolicyConfiguration defaultRetryStrategy="Fixed Interval Retry Strategy">
<incremental name="Incremental Retry Strategy" />
<fixedInterval name="Fixed Interval Retry Strategy" />
<exponentialBackoff name="Exponential Backoff Retry Strategy" />
</RetryPolicyConfiguration>
<typeRegistrationProvidersConfiguration>
<add sectionName="RetryPolicyConfiguration" name="RetryPolicyConfiguration" />
</typeRegistrationProvidersConfiguration>
</configuration>
I cant get it work! I keep getting errors like
Could not load file or assembly 'Microsoft.Practices.ServiceLocation,
OR
The type RetryManager cannot be constructed. You must configure the container to supply this value
OR
Activation error occured while trying to get instance of type RetryManager, key "
OR it keep looking for *.cs files when debugging!
And more and more!!
Is someone there! with a simple azure ReliableSqlConnection sample! that i can download and run?
Please! Preferable using the latest dlls?
Thanks.
This is one of my simple testing code in a new WinForm solution
I have tried many combinations! like
ReliableSqlconnection with ExecuteReader or
SqlConnection with ExecuteReaderWithRetry or
ReliableSqlconnection with ExecuteReaderWithRetry
I just cant get it work! using SqlConnection with ExecuteReader, works perfect.! but is not reliable connection! so i will keep getting connection errors.
using (var cnn = new ReliableSqlConnection(connString))
{
cnn.Open();
using (var cmd = cnn.CreateCommand())
{
cmd.CommandText = "SELECT * FROM MyTable";
using (var rdr = cmd.ExecuteReaderWithRetry())
{
if (rdr.Read())
{
Console.Write(rdr.GetString(1));
}
}
}
}
Enterprise library 6 is all about the retry logic! No more ReliableSqlConnection.
This same logic will work for all azure storage services:
SQL Azure, Windows Azure Storage, Windows Azure Caching, or the Windows Azure Service Bus
You can even use it for all retry needs using your own retry logic class with the Interface ITransientErrorDetectionStrategy
So here is a working example (Console, WinForm, Website, WebMethod):
1.- Installing the NuGet (V. 6.0)
PM> Install-Package EnterpriseLibrary.TransientFaultHandling.WindowsAzure.Storage
2.- WebConfig:
<connectionStrings>
<add name="MyConnectionString" connectionString="Server=tcp:********.database.windows.net,1433;Database=DATABASENAME;User ID=*********;Password=********;Trusted_Connection=False;Encrypt=True;"/>
</connectionStrings>
3.- Using
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling;
4.- De example class
public class ReliableAzureConnection
{
string ConnectionString;
RetryPolicy RetryPolicy;
/// <summary>
/// Initialize the retryPolicy
/// Load the connection string from App.config
/// </summary>
public ReliableAzureConnection()
{
ConnectionString = ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
//This means, 3 retries, first error, wait 0.5 secs and the next errors, increment 1 second the waiting
Incremental RetryStrategy = new Incremental(3, TimeSpan.FromMilliseconds(500), TimeSpan.FromSeconds(1));
// You can use one of the built-in detection strategies for
//SQL Azure, Windows Azure Storage, Windows Azure Caching, or the Windows Azure Service Bus.
//You can also define detection strategies for any other services that your application uses.
RetryPolicy = new RetryPolicy<StorageTransientErrorDetectionStrategy>(RetryStrategy);
}
public DataTable GetTable(string commandText)
{
DataTable DataTable = null;
DataTable TempDataTable = null;
try
{
TempDataTable = new DataTable();
//This is the function that will retry,
//dont try to make your retry logic your self!
//there are so many error codes. Not all can retry
RetryPolicy.ExecuteAction(() =>
{
// Here you can add any logic!
//1.-Fill DataSet, NonQueries, ExecuteScalar
using (SqlConnection SqlConnection = new SqlConnection(ConnectionString))
{
SqlConnection.Open();
using (SqlCommand SqlCommand = new SqlCommand(commandText, SqlConnection))
{
TempDataTable.Load(SqlCommand.ExecuteReader());
}
}
DataTable = TempDataTable;
TempDataTable = null;
});
}
catch (SqlException ex)
{
//You can manage you own errors, for example bad queries or bad connections.
Debug.WriteLine(ex.Message);
throw;
}
finally
{
if (TempDataTable != null) TempDataTable.Dispose();
}
return DataTable;
}
//Example using ExecuteAction<TResult>
public DataTable GetTableUsingTResult(string commandText)
{
return RetryPolicy.ExecuteAction<DataTable>(() =>
{
DataTable DataTable = new DataTable();
using (SqlConnection SqlConnection = new SqlConnection(ConnectionString))
{
SqlConnection.Open();
using (SqlCommand SqlCommand = new SqlCommand(commandText, SqlConnection))
{
DataTable.Load(SqlCommand.ExecuteReader());
}
}
return DataTable;
});
}
}
5.- Call
ReliableAzureConnection ReliableAzureConnection = new ReliableAzureConnection();
DataTable MyTable = ReliableAzureConnection.GetTable("SELECT * FROM YourTable");
Debug.WriteLine(MyTable.Rows.Count);
I hope it help someone there. thanks.
As of .NET 4.6.1 the SqlConnection class now has retrying built in.
Troubleshoot, diagnose, and prevent SQL connection errors and transient errors for SQL Database
.NET SqlConnection parameters for connection retry
If your client program connects to to Azure SQL Database by using the .NET Framework class System.Data.SqlClient.SqlConnection, you should use .NET 4.6.1 or later (or .NET Core) so you can leverage its connection retry feature. Details of the feature are here.
When you build the connection string for your SqlConnection object, you should coordinate the values among the following parameters:
ConnectRetryCount (Default is 1. Range is 0 through 255.)
ConnectRetryInterval (Default is 1 second. Range is 1 through 60.)
Connection Timeout (Default is 15 seconds. Range is 0 through 2147483647)
Specifically, your chosen values should make the following equality true:
Connection Timeout = ConnectRetryCount * ConnectionRetryInterval
For example, if the count = 3, and interval = 10 seconds, a timeout of only 29 seconds would not quite give the system enough time for its 3rd and final retry at connecting: 29 < 3 * 10.
ReliableSqlConnection is technically part of EL 6 but it is outdated and is not appropriate for modern applications which care about scalability because that class, as well as all other Sql specific extension methods in the EL 6, doesn't support async operations, so, I believe the only good solution is to use generic retry EL 6 logic async methods to wrap async methods from ADO.NET.

Categories

Resources