2

SqlConnectionを使用しているアプリケーションに関するいくつかの統計、具体的には、サーバーに物理的にログインするために費やした時間について取得したいと思います。

単純なアプローチは次のようになります。

using (SqlConnection connection = ...)
{
    Stopwatch loginTimer = Stopwatch.StartNew();
    connection.Open()
    loginTimer.Stop();
}

ひねりは、私も接続プールを使用していて、それをオフにしたくないということです。その結果、ほとんどの呼び出し.Open()が実際にはプールから既存の開いている物理接続を取得しているだけなので、メトリックが歪んでいます。そのため、次のように表示されます。

00:00:01.39
00:00:00.02
00:00:00.02
00:00:00.02
...

アプリケーションは十分な接続を使用し、SqlAzureを対象としているため、物理ログインが十分な頻度で発生することを期待しています。

試す前に接続をテストしてみました:

if (sqlConnection.State != ConnectionState.Open)
{
    // Time and call .Open()
}

残念ながら、論理SqlConnectionは物理接続の状態を反映していないため、ifブロックは常に実行されます。

独自の接続プールを作成して、そこから引き出して実行することは可能ですが、閉じることはできません。したがって、論理接続の状態を介して物理接続の実際の状態を追跡できますが、本当にこれをしないことを好みます。

4

2 に答える 2

1

おそらく、ClientConnectionIdプロパティを使用してSQL接続を追跡できます。新しい物理接続が作成されるたびに再生成され、接続がプールから返されるときに保持されます。ただし、.net4.5以降でのみ使用できます。

もう1つの可能性は、物理時間を測定するためだけに、一部の接続についてのみ接続プールをスキップし、他の接続についてはプールを維持することです。

たとえば、静的カウンターを作成して、増分を続けることができます。10で割り切れるすべての値について、Pooling ='false'を接続文字列に追加して、プールへの追加をスキップできます。これにより、新しい接続が開かれ、物理的な時間を測定できます。

于 2013-03-22T20:54:20.953 に答える
0

アレクサンダーの答えを具体的なコードで拡張します。

すべての接続にプーリングを使用するという制約の中で、物理ログインごとに生成された値を追跡することで、サーバー/データベースに物理的にログインするのに費やされた時間を測定できます。以下は、今回測定・報告するサンプルの拡張方法です。これを使用するには、 の呼び出しを に変更します。ログインが発生した場合は結果が true になり、それ以外の場合は false になります。SqlConnection.ClientConnectionIdSqlClientSqlConnection.Open()SqlConnection.Login(out openTime)

internal static class SqlConnectionExtension
{
    private static readonly PropertyInfo _clientConnectionIdPropertyInfo = typeof(SqlConnection).GetProperty("ClientConnectionId");
    private static readonly HashSet<Guid> _clientConnectionIds = new HashSet<Guid>();

    /// <summary>
    /// Method that calls <see cref="SqlConnection.Open()"/>, measuring the time it takes.
    /// </summary>
    /// <param name="sqlConnection">The <see cref="SqlConnection"/> to open.</param>
    /// <param name="openTime">The total time that the call to <see cref="SqlConnection.Open()"/> took.</param>
    /// <returns>True if a login took place; false if a connection was returned from a connection pool.</returns>
    public static bool Login(this SqlConnection sqlConnection, out TimeSpan openTime)
    {
        Stopwatch loginTimer = Stopwatch.StartNew();
        sqlConnection.Open();
        loginTimer.Stop();

        openTime = loginTimer.Elapsed;

    #if NET_4_0_3
        Guid clientConnectionId = sqlConnection.ClientConnectionId;
    #else
        Guid clientConnectionId = Guid.Empty;
        if (_clientConnectionIdPropertyInfo != null)
        {
            clientConnectionId = (Guid)_clientConnectionIdPropertyInfo.GetValue(sqlConnection, null);
        }
    #endif
        if (clientConnectionId != Guid.Empty && !_clientConnectionIds.Contains(clientConnectionId))
        {
            lock (_clientConnectionIds)
            {
                if (_clientConnectionIds.Add(clientConnectionId))
                {
                    return true;
                }
            }
        }
        return false;
    }
}

私自身の環境では、まだ VS2010 を使用しており、すべてのクライアントが 4.0.3 マルチターゲット パックを持っているわけではないため、この#if NET_4_0_3セクションを参照してください。

于 2013-04-03T01:07:20.770 に答える