为什么 NpgsqlDataReader 从 V3 开始变慢了?

问题描述 投票:0回答:1

我正忙着将使用 Postgres 数据库 v9 的旧系统升级到 v14, 我需要在 C# .NetFramework 4.6.1 应用程序上将 Npgsql 库从当前版本 2.2.7 更新到 4.1.12。

在我的测试中,我注意到,如果我使用 Npgsql v3 或更高版本,则使用 NpgsqlDataReader 执行函数并将响应读取到数组中的命令需要花费 10 倍的时间。

代码看起来遵循 while (dbReader.Read()) 循环: 当连接到 Postgres v9 数据库时,运行 Npgsql v2.2.7 需要 10 秒才能运行完 20000 行。 当连接到 Postgres v9 或 v14 数据库时,运行 Npgsql v3 或更高版本需要 140 秒才能运行 20000 行(数据库没有区别)。

using Npgsql;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;

namespace UpgradeV2.Sample
{
    internal class SampleRequest
    {

        private static string connectionstring = "server=myhostname;port=5432;database=mydatabase;user id=myuser;password=mypassword;enlist=true;pooling=false;minpoolsize=1;maxpoolsize=100;timeout=1024;commandtimeout=3000;";

        public static IEnumerable<DataClass> GetData(long id)
        {
            var parameters = new Dictionary<string, object>
            {
                {"i_id", (int)id}             
            };
            using (NpgsqlConnection _npgsqlConnection = new NpgsqlConnection(connectionstring))
            {
                var command = new NpgsqlCommand
                {
                    CommandType = CommandType.StoredProcedure,
                    Connection = _npgsqlConnection,
                    CommandText = "public.function_returning_lots_of_data"
                };

                foreach (var parameter in parameters)
                {                  
                        command.Parameters.Add(new NpgsqlParameter { ParameterName = parameter.Key, Value = parameter.Value });
                }
             
                using (var dbReader = command.ExecuteReader())
                {                   
                    var dataList = new Collection<DataClass>();

                    // to complete this while loop with npgsql v2 takes 10 seconds
                    // to complete this while loop with npgsql v3-v6 takes 140 seconds
                    while (dbReader.Read())
                    {

                        if (dbReader["id"] == DBNull.Value)
                        {
                            continue;
                        }

                        DataClass item = new DataClass()
                        {
                            id = dbReader.GetFieldValue<int>("id"),
                            //And about 20 other Fields read using GetFieldValue
                        };

                        dataList.Add(item);
                    }
                    return dataList;
                }
            }
        }
    }
}

我尝试了 Npgsql 库的不同较新版本,从版本 3 开始,所有这些都会导致相同的问题。 我尝试将连接字符串更新为“读取缓冲区大小”的更高值,但没有任何改进 我尝试使用 ExecuteAsync 和 ReadAsync 方法,但几乎没有效果。

c# npgsql
1个回答
0
投票

我知道这不是最佳解决方案,但它显着提高了将结果读入数组的速度,所以我希望这可以帮助某人,直到找到更优雅的解决方案。

为此,我创建一个数据表,并使用 load 方法将整个结果读入数据表,然后创建一个 DataTableReader 来代替 NpgsqlDataReader。

使用这个 dbReader.Read() 循环将在 5 秒内完成 20000 条记录(在我的例子中是这样)。下面的代码将花费大约 10 秒来填充数据表并创建适配器。 它仍然不如 Npgsql v2.2.7 库那么快,但比 140 秒的加载时间要好得多。

DataTable dataTable = new DataTable();
dataTable.Load(command.ExecuteReader());
return dataTable.CreateDataReader();

请注意: 这是我的具体问题的解决方案,我知道应该重构问题中的原始代码,以针对更现代的方法进行优化,但是,这只是最终将退役的大型系统遗留系统的一小部分,在这种情况下这种情况发生在数百个类+文件中。 因此,针对性能问题的快速通用修复是我现阶段唯一的选择。

© www.soinside.com 2019 - 2024. All rights reserved.