web-dev-qa-db-ja.com

現在、すべての接続で「タイムアウトの期限が切れています」

SQL Serverに接続するアプリケーションがあります。現在私は得ています、

Timeout expired.  The timeout period elapsed prior to obtaining a connection from the pool.  This may have occurred because all pooled connections were in use and max pool size was reached.

私が走ったとき

SELECT 
    DB_NAME(dbid) as DBName, 
    COUNT(dbid) as NumberOfConnections,
    loginame as LoginName
FROM
    sys.sysprocesses
WHERE 
     DB_NAME(dbid) ='MyDb'
GROUP BY 
    dbid, loginame 

DBName  NumberOfConnections LoginName
MyDb    10                     sa                                                                                                                              
MyDb    109                   MyUser

すべてのプロセスのステータスはsleepingで、cmsはAWAITING COMMAND

これが私のコードです、

private async Task<object> ExecuteAsync<T>(ExecutionType executionType, CommandType commandType, string commandText, IsolationLevel isolationLevel, SqlParameter[] parameters, Func<IDataReader, T> callback = null)
{
    var stopwatch = new Stopwatch();
    stopwatch.Start();
    using (var connection = new SqlConnection(_settings.DatabaseConnectionString))
    {
        using (var command = new SqlCommand(commandText, connection) {CommandType = commandType})
        {
            command.Parameters.AddRange(parameters);
            await connection.OpenAsync().ConfigureAwait(false);
            command.CommandTimeout = _settings.CommandTimeout;
            var transaction = connection.BeginTransaction(isolationLevel);
            command.Transaction = transaction;
            try
            {
                object result;
                switch (executionType)
                {
                    case ExecutionType.Reader:
                        var reader = await command.ExecuteReaderAsync().ConfigureAwait(false);
                        using (reader)
                        {
                            var list = new List<T>();
                            while (reader.Read())
                            {
                                if (callback != null)
                                {
                                    var item = callback(reader);
                                    if (item != null)
                                    {
                                        list.Add(item);
                                    }
                                }
                            }
                            result = list;
                        }
                        break;
                    case ExecutionType.NonQuery:
                        result = await command.ExecuteNonQueryAsync().ConfigureAwait(false);
                        break;
                    default:
                        result = await command.ExecuteScalarAsync().ConfigureAwait(false);
                        break;
                }
                transaction.Commit();
                stopwatch.Stop();
                var elapsed = stopwatch.Elapsed;
                if (elapsed.Seconds > 2)
                {
                    _logger.Log(string.Format("{0} took {1} time", command.CommandText, elapsed));// only log if it tooks more than 2 seconds
                }
                return result;
            }
            catch (Exception exception)
            {
                _logger.Log(exception);
                transaction.Rollback();
                throw;
            }
        }
    }
}
4
user960567

SqlConnectionオブジェクトを適切に閉じたり破棄したりしていないアプリケーションがあるようです。デフォルトでは、 SqlConnectionの最大プールサイズは1 です。

ここでの修正は、アプリケーションと連携して、特定の接続プールで接続がまだ「アクティブ」であるため、接続がクリーンアップされていない理由を見つけることです。使用するプール内の非アクティブな接続。

接続を解放して「非アクティブ」としてマークするには、アプリケーションがSqlConnection.Close()またはSqlConnection.Dispose()を呼び出す必要があります。

広範なブログ投稿(SQL Server DBAの接続プーリング))を接続プーリングについて書きました 何が表示されているのか、およびプログラムによる問題の修正について説明します。

8
Thomas Stringer

代わりに、大量のレコードを処理している場合、実際には誤解を招くエラーが発生する可能性があります。 PCのすべてのポートを使い果たした可能性があります。Sysinternals TCPView を実行してこれを確認できます。

何千もの TIME_WAIT が表示される場合、これは考えられる原因です。

本質的に、アプリケーションがデータベースへの接続を閉じた後(using (var connection = new SqlConnection(_settings.DatabaseConnectionString))の終わり)、TCPは、使用中のポートが解放される前に約4分間待機します再び使用されます。

これを実行するには、メモリから約16,000回の実行を4分未満で処理する必要があります(OSのバージョンと、そのPCで実行している他のものによって異なります)。

5