C# 为什么代码在查询数据库时会耗尽CPU?

C# 为什么代码在查询数据库时会耗尽CPU?,c#,sql-server,performance,ado.net,C#,Sql Server,Performance,Ado.net,下面我的C代码检查SQL数据库,查看记录是否与ClientID和用户名匹配。如果找到超过15条或更多匹配的记录,Windows 2008服务器上的CPU峰值约为78%,而在执行下面的C代码时找到了15条记录。SQL Server 2008数据库和软件位于另一台服务器上,因此问题不在于SQL Server占用CPU。问题在于我的C软件正在执行下面的代码。在执行数据库查询并找到记录时,我可以看到我的软件可执行文件,其中包含的C代码低于78% 有人能告诉我,当发现15条或更多匹配记录时,我的代码是否有

下面我的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%的峰值

//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();
        }
    }
}

代码中没有表示性能问题的内容

SQL分析器显示了什么

无论是在查询计划方面,还是在所使用的服务器资源方面

编辑:为了更清楚地说明这一点:您有一个可能指示问题的度量。现在,您需要更深入地测量以了解这是否真的是一个问题,只有您可以这样做,其他人无权访问硬件。

更改此项:

SELECT * FROM Filelist
为此:

SELECT ClientID FROM Filelist
并检查性能。 我怀疑您的选择上有一个blob字段。
也不要选择*,在你的查询中写下你感兴趣的领域。

请考虑关于参数化查询的内容。

除此之外,我认为唯一的大问题可能出现在以下街区:

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
    }
}
所以试着缓存你的读卡器。读取一些局部变量中的数据,尽快释放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

如果要删除第一个查询,则可以将数据库访问次数从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
}

显然,没有什么是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())
    {
    }
}

我强烈建议您从JetBrains获得一份


至少,分析客户机代码将帮助您识别/消除CPU峰值的来源。

我建议使用建议的参数,但是,我看到了字符串列的类型与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];

为黑客做好准备:SQL注入的空间很大。或者,更好的方法是使用参数化查询。此代码在内部系统上运行,并且不会暴露于外部internet。首先,使用is会增加一次性对象的处理。然后,将所有数据带到客户端,然后检查它们是否有ClientID。为什么不从[ToAccountName]=@ToAccountName和ClientID=@ClientID的文件列表中选择*呢?另外:使用块清理资源,您也不需要这样做。您的Connection.Dispose正在复制使用块。@fraXis大多数安全漏洞都来自内部人员。使用参数化查询非常容易,而且安全。只要始终使用它们:默认为良好实践。此外,它们可以更快,服务器也可以缓存查询计划。我会在运行C代码的服务器和运行SQL server 2008的服务器上运行SQL Profiler吗,或者仅仅是运行SQL server 2008的服务器?对于查找如此少量的记录而言,78 CPU峰值会被视为性能问题吗?@fraXis 78%在具有匹配UI和内存的256核monster服务器上会是一个问题。在一个内存有限的单原子核上,结果没有缓存,这可能是正常的,甚至取决于monster。如果扫描100TB的数据库,78%也是正常的。数据库非常小。也许总共只有300张唱片。我想你是对的,如果我是弗雷克斯的话,我肯定会看这个。不幸的是,我们不知道do something块中发生了什么:-这段代码意味着您没有在C代码中执行字符串比较,并且您将在本地检索更少的行。这两个都不能解释神奇的数字“15”,但您修复的性能瓶颈越多,就越容易找到根本原因。@ElectricLlama:我完全支持应用程序服务器端计算,或者更好地说是业务逻辑,通常是这样。但不要惊讶于AppServer将需要越来越多的资源。通过仔细阅读,我发现这是他的问题!不是DB服务器CPU使用高峰,而是应用程序
数据库请求服务器!见他对问题的评论itself@Richard:OP不是这么说的。OP明确指出问题出在桌面上。