2

以下の私のC#コードは、SQLデータベースをチェックして、レコードがClientIDとユーザー名に一致するかどうかを確認します。一致するレコードが15個以上見つかった場合、Windows 2008サーバーのCPUは約78%でピークに達しますが、以下のC#コードの実行中に15個のレコードが見つかります。SQL Server 2008のデータベースとソフトウェアは別のサーバーにあるため、SQLServerがCPUをスパイクすることで問題が発生することはありません。問題は、以下のコードを実行している私のC#ソフトウェアにあります。データベースクエリが実行され、レコードが検出されている間、以下のC#コードを含むソフトウェア実行可能ファイルが78%に急上昇していることがわかります。

15個以上の一致するレコードが見つかったときにCPUが急上昇する原因となっているコードに問題があるかどうか、誰かに教えてもらえますか?また、コードを最適化する方法を教えてください。

更新:10個のレコードが見つかった場合、CPUは2〜3パーセントで急上昇します。15以上のレコードが見つかった場合にのみ、CPUが78%で2〜3秒間スパイクします。

//ClientID[0] will contain a ClientID of 10 characters
//output[0] will contain a User Name
char[] trimChars = { ' ' };
using (var connection = new SqlConnection(string.Format(GlobalClass.SQLConnectionString, "History")))
{
    connection.Open();
    using (var command = new SqlCommand())
    {
        command.CommandText = string.Format(@"SELECT Count(*) FROM Filelist WHERE [ToAccountName] = '" + output[0] + @"'");
        command.Connection = connection;
        var rows = (int) command.ExecuteScalar();
        if (rows >= 0)
        {
            command.CommandText = string.Format(@"SELECT * FROM Filelist WHERE [ToAccountName] = '" + output[0] + @"'");
            using (SqlDataReader reader = command.ExecuteReader())
            {
                if (reader.HasRows)
                {
                    while (reader.Read())
                    {
                        //Make sure ClientID does NOT exist in the ClientID field
                        if (reader["ClientID"].ToString().TrimEnd(trimChars).IndexOf(ClientID[0]) !=
                            -1)
                        {
                            //If we are here, then do something
                        }
                    }
                }
                reader.Close();
                reader.Dispose();
            }
        }
        // Close the connection
        if (connection != null)
        {
            connection.Close();
        }
    }
}
4

7 に答える 7

4

最初のクエリを削除する場合は、データベースアクセスの数を2から1に減らすことができます。これは必要ありません。

using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = connection.CreateCommand())
{
    command.CommandText = "SELECT ClientID FROM dbo.Filelist WHERE ToAccountName = @param"; // note single column in select clause
    command.Parameters.AddWithValue("@param", output[0]); // note parameterized query

    connection.Open();
    using (SqlDataReader reader = command.ExecuteReader())
    {  
        while (reader.Read()) // reader.HasRow is doubtfully necessary
        {
            // logic goes here
            // but it's better to perform it on data layer too

            // or return all clients first, then perform client-side logic
            yield return reader.GetString(0);
        }
    } // note that using block calls Dispose()/Close() automatically
}
于 2012-11-17T17:13:59.297 に答える
3

明らかにCPUを集中的に使用しているように見えるものはありませんが、1つの問題が際立っています。

クエリを実行して、レコードの数をカウントしています

"SELECT Count(*) FROM Filelist WHERE [ToAccountName] = '" + output[0] + @"'"

次に、0より大きい値が返された場合は、別のクエリを実行してデータを取得しています。

"SELECT * FROM Filelist WHERE [ToAccountName] = '" + output[0] + @"'"

これは冗長です。最初のクエリを削除し、2番目のクエリを使用して、リーダーにデータがあるかどうかを確認します。HasRows呼び出しを削除して、実行することもできます。

using (SqlDataReader reader = command.ExecuteReader())
{
    while (reader.Read())
    {
    }
}
于 2012-11-17T17:23:42.507 に答える
3

これを変える:

SELECT * FROM Filelist

これに:

SELECT ClientID FROM Filelist

そして、パフォーマンスを確認します。選択範囲にblobフィールドがあると思われます。またselect *、お勧めしません。クエリに正確に関心のあるフィールドを入力してください。

于 2012-11-17T17:11:17.940 に答える
1

パラメータ化されたクエリについてすでに述べたことを考慮してください。

それ以外に、次のブロックで唯一の大きな問題が発生する可能性があると思います。

while (reader.Read())
{
    //Make sure ClientID does NOT exist in the ClientID field
    if (reader["ClientID"].ToString().TrimEnd(trimChars).IndexOf(ClientID[0]) != -1)
    {
        //If we are here, then do something
    }
}

したがって、reader.Read()データをローカル変数にキャッシュして、SQLリソースをできるだけ早く解放してみてください。そうすれば、取得したデータを処理できます。例えば:

List<string> myRows = new List<string>();
while (reader.Read())
{
   myRows.Add(reader["ClientID"].ToString();
}
/// quit the using clause
/// now elaborate what you got in myRows
于 2012-11-17T17:12:51.593 に答える
0

JetBrainsからdotTraceのコピーを入手することを強くお勧めします。

少なくとも、クライアントコードのプロファイリングは、CPUスパイクの原因を特定/排除するのに役立ちます。

于 2012-11-17T17:25:53.023 に答える
0

コードには、パフォーマンスの問題を示すものは何もありません。

SQLプロファイラーは何を示していますか?

(クエリプランと使用されるサーバーリソースの両方の観点から。)

編集:これを明確にするために:問題を示す可能性のある測定値が1つあります。これが本当に問題であるかどうかを理解するには、より深く測定する必要があります。これを実行できるのは自分だけです(他の誰もハードウェアにアクセスできません)。

于 2012-11-17T17:05:10.653 に答える
0

提案されているようにパラメーターを使用することをお勧めしますが、文字列列のタイプがC#文字列と一致しない場合にパフォーマンスの問題が発生します。このような場合は、タイプを明示的に指定することをお勧めします。

このような:

command.CommandText = "SELECT ClientID FROM dbo.Filelist WHERE ToAccountName = @accountName"; 
command.Parameters.Add("@accountName", SqlDbType.NVarChar, 16, output[0]);

またはこれ:

SqlParameter param = command.Parameters.Add(
    "@accountName", SqlDbType.NVarChar);
param.Size = 16; //optional
param.Value = output[0];
于 2012-11-17T18:03:25.273 に答える