下面的我的C#代码检查SQL数据库以查看记录是否与ClientID和用户名匹配。如果找到匹配的匹配记录超过15个或更多,则Windows 2008服务器上的CPU峰值大约为78%,而下面的C#代码执行时找到15条记录。 SQL Server 2008数据库和软件位于另一台服务器上,因此问题不在于SQL Server加密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();
}
}
}
答案 0 :(得分: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
}
答案 1 :(得分:3)
改变这个:
SELECT * FROM Filelist
对此:
SELECT ClientID FROM Filelist
检查性能。
我怀疑你的选择上有一个blob字段。
另外,建议您不要使用select *
,在查询中写下您确切感兴趣的字段。
答案 2 :(得分:3)
没有什么看起来显然是CPU密集型的,但有一个问题确实很突出。
您正在运行查询以计算有多少记录
"SELECT Count(*) FROM Filelist WHERE [ToAccountName] = '" + output[0] + @"'"
然后,如果返回的值大于0,则表示您正在运行另一个查询来获取数据。
"SELECT * FROM Filelist WHERE [ToAccountName] = '" + output[0] + @"'"
这是多余的。摆脱第一个查询,只需使用第二个查询,检查读者是否有数据。您也可以摆脱HasRows调用,然后执行
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
}
}
答案 3 :(得分: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
答案 4 :(得分:0)
代码中没有任何内容表明存在性能问题。
SQL事件探查器显示什么?
(无论是查询计划还是使用的服务器资源。)
编辑:为了更清楚:您有一个可能表示问题的衡量标准。您现在需要更深入地测量以了解它是否确实存在问题,只有您可以执行此操作(没有其他人可以访问硬件)。
答案 5 :(得分:0)
我强烈建议您从JetBrains获得dotTrace的副本。
至少,分析客户端代码将帮助您识别/消除CPU峰值的来源。
答案 6 :(得分: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];