从数据库减少 CPU 远程 select 上的负载

Reducing CPU Load on a remote select from a database

我正在远程 select 从自定义生产数据库中获取结果,标准是从 C# 应用程序大约三分钟。

每次执行 select 命令时,我使用的服务器 PC CPU 都会上升到 50% 左右。但可以肯定的是,负载应该在我连接的数据库上吗?

为什么 C# 应用程序会飙升至 50%,直到检索数据进行读取?

一些背景

这是我正在使用的一些代码。

OdbcConnection remoteConn = new OdbcConnection(ConfigurationManager.ConnectionStrings["remoteConnectionString"].ToString());

            remoteConn.Open();

            OdbcCommand remoteCommand = new OdbcCommand();
            remoteCommand.Connection = remoteConn;

            using (remoteConn)
            {
                string localSql = "";
                string remoteSql = "select * from tracking where last_update > 212316247440000000"; // Julian No = 2015-07-12 11:24:00

                remoteCommand.CommandText = remoteSql;

                OdbcDataReader remoteReader;

                remoteReader = remoteCommand.ExecuteReader();

                while (remoteReader.Read())
                {


                    for (int i = 0; i < 68; i++)
                    {
                        localSql += ",'" + remoteReader[i].ToString() + "'";
                    }

                }

            }

我 运行 对应用程序进行了性能和诊断测试,得到了这个结果。

如果有的话,我怎样才能减少这种 CPU 负荷甚至完全根除它。这完全不同寻常,我不知道该怎么做。

谢谢

难道是解析结果?您是否正在使用某种自动将结果集解析为域对象的数据层?那可能会非常 CPU 激烈..

感谢您提供信息,丹。这是我的想法...

我认为您的应用消耗如此多的主要原因 CPU 是因为您使用的驱动程序。

由于您要连接到 SQL 服务器数据库,因此您应该使用 SQL 服务器驱动程序,它知道如何优化客户端和服务器之间的数据传输。

要使用适当的驱动程序,请确保使用 SqlConnectionSqlCommand

这将允许 SQL 服务器在您查询数据 reader.

时将结果 流式传输 到您的客户端

其次,不要在DbCommand对象上使用ExecuteReader()方法。 SQL 服务器驱动程序独有的众多精彩功能之一是 ExecuteReaderAsync() 方法。

由于此命令是 IO 绑定操作(不是计算绑定),因此无需阻塞调用线程。当结果返回时,它们将到达 IO 完成线程。

这里是您的代码在更改后的样子的代码示例。

using (var remoteConn = new SqlConnection(ConfigurationManager.ConnectionStrings["remoteConnectionString"].ToString()))
{
    remoteConn.Open();
    using (var remoteCommand = new SqlCommand())
    {
        remoteCommand.Connection = remoteConn;
        string localSql = "";
        string remoteSql = "select * from tracking where last_update > 212316247440000000"; // Julian No = 2015-07-12 11:24:00

        remoteCommand.CommandText = remoteSql;
        var remoteReader = await remoteCommand.ExecuteReaderAsync();
        while (remoteReader.Read())
        {
            for (int i = 0; i < 68; i++)
            {
                localSql += ",'" + remoteReader[i].ToString() + "'";
            }
        }
    }
}

我假设 select 命令是 运行 来自另一台计算机而不是托管 SQL 数据库的计算机。

说实话有点莫名其妙。我唯一想到的是传递和处理元数据可能需要时间。您是否尝试过将查询更改为 return 只说一条数据?

例如:

select top 1 last_update from tracking where last_update > 212316247440000000
select count (*) from tracking where last_update > 212316247440000000

这将阐明问题是否是由数据+元数据引起的。

您的 IO Bound 操作的最佳方式是使用 Task,因为它不需要更改现有代码:

var task = Task.Factory.StartNew(() => {
    //your code or @Randy code with little change here:
    using (var remoteConn = new SqlConnection(ConfigurationManager.ConnectionStrings["remoteConnectionString"].ToString()))
    {
        remoteConn.Open();
        using (var remoteCommand = new SqlCommand())
        {
            remoteCommand.Connection = remoteConn;
            string localSql = "";
            string remoteSql = "select * from tracking where last_update > 212316247440000000"; // Julian No = 2015-07-12 11:24:00

            remoteCommand.CommandText = remoteSql;
            var remoteReader = remoteCommand.ExecuteReader();
            while (remoteReader.Read())
            {
                for (int i = 0; i < 68; i++)
                {
                    localSql += ",'" + remoteReader[i].ToString() + "'";
                }
            }
        }
    }
});
//use can use 'task.wait();' to waiting for complete the task.