You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Npgsql v3及以上版本中NpgsqlDataReader读取速度大幅变慢?

Npgsql v3+版本读取数据性能骤降的排查与解决

将PostgreSQL v9升级至v14时,同步把.NET Framework 4.6.1项目的Npgsql从2.2.7升级到4.1.12,发现执行存储过程并通过NpgsqlDataReader读取20000行数据时,v3+版本耗时是v2.2.7的10倍(v2.2.7需10秒,v3+需140秒,连接PostgreSQL v9或v14耗时无差异)。已尝试调整连接字符串Read Buffer Size、使用ExecuteAsync/ReadAsync方法,均无明显改善。相关代码如下:

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;
                }
            }
        }
    }
}

解决方案

  • 替换GetFieldValue<T>为批量读取
    Npgsql v3+对GetFieldValue<T>的类型检查逻辑做了调整,频繁调用单字段读取会累积大量开销。改用GetValues一次性读取整行数据,再映射到实体:

    while (dbReader.Read())
    {
        var idOrdinal = dbReader.GetOrdinal("id");
        if (dbReader.IsDBNull(idOrdinal))
            continue;
    
        var values = new object[dbReader.FieldCount];
        dbReader.GetValues(values);
    
        DataClass item = new DataClass()
        {
            id = (int)values[idOrdinal],
            // 其他字段通过对应索引取值转换
        };
        dataList.Add(item);
    }
    

    也可以使用Dapper等ORM工具自动映射实体,进一步减少手动读取的性能损耗。

  • 开启二进制格式传输
    Npgsql v2.2.7默认启用二进制格式传输数据,而v3+默认关闭。在连接字符串中添加UseBinaryFormat=true,大幅降低数据序列化与反序列化的开销:

    server=myhostname;port=5432;database=mydatabase;user id=myuser;password=mypassword;enlist=true;pooling=false;minpoolsize=1;maxpoolsize=100;timeout=1024;commandtimeout=3000;UseBinaryFormat=true;
    
  • 明确指定参数类型
    手动创建NpgsqlParameter时,显式设置NpgsqlDbType可以避免Npgsql自动推断类型的额外开销:

    command.Parameters.Add(new NpgsqlParameter 
    { 
        ParameterName = parameter.Key, 
        Value = parameter.Value,
        NpgsqlDbType = NpgsqlDbType.Integer
    });
    
  • 启用连接池
    当前连接字符串设置pooling=false,每次请求都新建连接会带来显著开销。建议改为pooling=true,并根据业务调整minpoolsize和maxpoolsize,减少连接建立的耗时。

  • 升级Npgsql版本
    Npgsql 4.1.12存在部分性能缺陷,建议升级到4.1.x系列的最新补丁版本(如4.1.16),或兼容.NET Framework 4.6.1的5.x/6.x版本,新版本修复了多个性能相关问题。

内容的提问来源于stack exchange,提问作者Code Ninja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 12:05:07