Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用protobuf的流式压缩IDataReader_C#_Tcp_Compression_Protobuf Net_Idatareader - Fatal编程技术网

C# 使用protobuf的流式压缩IDataReader

C# 使用protobuf的流式压缩IDataReader,c#,tcp,compression,protobuf-net,idatareader,C#,Tcp,Compression,Protobuf Net,Idatareader,在将数据拉入和推送到sql时,我们需要大大减少后端服务使用的带宽。SqlClient使用的TDS流相当臃肿。多年来,人们在从sql中提取数据时要求使用压缩选项,但微软并没有添加它 我想看看是否有人想到了处理这件事的最佳方法。以下是我到目前为止所做的尝试: 我修改为在套接字层添加压缩和解压缩。因为有效负载是SSL加密的,所以没有多大区别 接下来,我将IDataReader转换为Protobuf库,并在中找到TCP框架,试图创建一个客户机-服务器代理,通过将IDataReader转换为Protobu

在将数据拉入和推送到sql时,我们需要大大减少后端服务使用的带宽。SqlClient使用的TDS流相当臃肿。多年来,人们在从sql中提取数据时要求使用压缩选项,但微软并没有添加它

我想看看是否有人想到了处理这件事的最佳方法。以下是我到目前为止所做的尝试:

  • 我修改为在套接字层添加压缩和解压缩。因为有效负载是SSL加密的,所以没有多大区别

  • 接下来,我将IDataReader转换为Protobuf库,并在中找到TCP框架,试图创建一个客户机-服务器代理,通过将IDataReader转换为Protobuf,然后压缩此流,并在另一端执行相反的操作,在线路上传输IDataReader

  • 我在这里得到了一个概念证明,与普通TDS流相比,网络上的原始字节减少了84%到98%。缺点是WatsonTcp希望您在分配流时传入内容长度。但在创建整个protobuf流之前,无法知道这一点。我们有时一下子就转移了数百场演出,所以那是行不通的

    我不知道protobuf net数据是如何在grpc上传输的,即使可以,我担心IAsyncEnumerable中记录的粒度特性可能会减慢大型传输

    毫无疑问,我可以坐下来编写一个完全定制的原始套接字压缩protobuf over TCP流媒体实现,客户端的表面积接近SqlCommand,我只知道这是出了名的难以实现


    有节省时间的主意吗?如果不是,也许我会用它做一个开源项目

    这里有一个模式,您可以使用它来获取一个大型查询并将其作为一系列批传输,其中每个批都是一个压缩的二进制序列化数据表。在传输和反序列化之后,SqlBulk Copy可以直接使用每个数据表。相同的模式可以用于其他格式,但在传递到SqlBulkCopy之前需要额外的转换器

    using System.Data.SqlClient;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Data;
    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;
    
    namespace BatchingDataReader
    {
        class BatchingDataReader : IDataReader
        {
            private int batchSize;
            private IDataReader rdr;
            private int rowsRead;
            private bool atEnd;
            private int batchesRead;
    
            public BatchingDataReader(IDataReader rdr, int batchSize)
            {
                this.batchSize = batchSize;
                this.rdr = rdr;
            }
    
            public object this[int i] => rdr[i];
    
            public object this[string name] => rdr[name];
    
            public int Depth => rdr.Depth;
    
            public bool IsClosed => rdr.IsClosed;
    
            public int RecordsAffected => rdr.RecordsAffected;
    
            public int FieldCount => rdr.FieldCount;
    
            public void Close()
            {
                if (!atEnd)
                    return;
                rdr.Close();
            }
    
            public void Dispose()
            {
                if (!atEnd)
                    return;
    
                rdr.Dispose();
            }
    
            public bool GetBoolean(int i)
            {
                return rdr.GetBoolean(i);
            }
    
            public byte GetByte(int i)
            {
                return rdr.GetByte(i);
            }
    
            public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
            {
                return rdr.GetBytes(i, fieldOffset, buffer, bufferoffset, length);
            }
    
            public char GetChar(int i)
            {
                return rdr.GetChar(i);
            }
    
            public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
            {
                return rdr.GetChars(i, fieldoffset, buffer, bufferoffset, length);
            }
    
            public IDataReader GetData(int i)
            {
                return rdr.GetData(i);
            }
    
            public string GetDataTypeName(int i)
            {
                return rdr.GetDataTypeName(i);
            }
    
            public DateTime GetDateTime(int i)
            {
                return rdr.GetDateTime(i);
            }
    
            public decimal GetDecimal(int i)
            {
                return rdr.GetDecimal(i);
            }
    
            public double GetDouble(int i)
            {
                return rdr.GetDouble(i);
            }
    
            public Type GetFieldType(int i)
            {
                return rdr.GetFieldType(i);
            }
    
            public float GetFloat(int i)
            {
                return rdr.GetFloat(i);
            }
    
            public Guid GetGuid(int i)
            {
                return rdr.GetGuid(i);
            }
    
            public short GetInt16(int i)
            {
                return rdr.GetInt16(i);
            }
    
            public int GetInt32(int i)
            {
                return rdr.GetInt32(i);
            }
    
            public long GetInt64(int i)
            {
                return rdr.GetInt64(i);
            }
    
            public string GetName(int i)
            {
                return rdr.GetName(i);
            }
    
            public int GetOrdinal(string name)
            {
                return rdr.GetOrdinal(name);
            }
    
            public DataTable GetSchemaTable()
            {
                return rdr.GetSchemaTable();
            }
    
            public string GetString(int i)
            {
                return rdr.GetString(i);
            }
    
            public object GetValue(int i)
            {
                return rdr.GetValue(i);
            }
    
            public int GetValues(object[] values)
            {
                return rdr.GetValues(values);
            }
    
            public bool IsDBNull(int i)
            {
                return rdr.IsDBNull(i);
            }
    
            public bool NextResult()
            {
                if (!atEnd)
                {
                    batchesRead += 1;
                    rowsRead = 0;
                    return true;
                }
    
                if (IsClosed)
                    return false;
    
                return rdr.NextResult();
            }
    
            public bool Read()
            {
                if (rowsRead >= batchSize)
                    return false;
                rowsRead += 1;
    
                atEnd = !rdr.Read();
                return !atEnd;
    
            }
    
            public static IEnumerable<DataTable> Read(SqlDataReader r, int batchSize)
            {
                var rdr = new BatchingDataReader(r, batchSize);
                do
                {
                    var dt = new DataTable();
                    dt.TableName = "table";
                    dt.Load(rdr);
                    yield return dt;
                } while (rdr.NextResult());
            }
        }
        class Program
        {
    
            static void Main(string[] args)
            {
                var constr = "server=localhost;database=master;integrated security=true";
                var outfile = "c:\\temp\\out.bin";
    
                if (File.Exists(outfile))
                    File.Delete(outfile);
    
                using (var con = new SqlConnection(constr))
                {
                    //322,162,200  TDS raw
                    //235,355,311  binary uncompressed out.bin
                    // 52,755,181  binary GZ Fastest
                    // 43,061,121  binary GZ optimal
                    // 65,282,624  XML GZ fastest
                    // 41,892,056  binary GZ optimal 100,000 row batches
    
                    con.Open();
    
                    var bin = new BinaryFormatter();
    
                    var cmd = new SqlCommand("select top (1000000) * from sys.messages m, sys.objects o", con);
                    using (SqlDataReader rdr = cmd.ExecuteReader())
                    using (var destFile = File.OpenWrite(outfile))
                    using (var zipStream = new System.IO.Compression.GZipStream(destFile,System.IO.Compression.CompressionLevel.Optimal))
                    {
                        foreach (var dt in BatchingDataReader.Read(rdr, 10000))
                        {
                            Console.WriteLine(dt.Rows.Count);
    
                            dt.RemotingFormat = SerializationFormat.Binary;
                            bin.Serialize(zipStream, dt);
                        }
                    }
                }
            }
        }
    
    }
    
    使用System.Data.SqlClient;
    使用制度;
    使用系统集合;
    使用System.Collections.Generic;
    使用系统数据;
    使用System.IO;
    使用System.Runtime.Serialization.Formatters.Binary;
    命名空间BatchingDataReader
    {
    类BatchingDataReader:IDataReader
    {
    私有整数批量大小;
    私人IDataReader rdr;
    私人住宅区;
    私人住宅区;
    私有int-batchesRead;
    公共BatchingDataReader(IDataReader rdr,int batchSize)
    {
    this.batchSize=batchSize;
    this.rdr=rdr;
    }
    公共对象this[int i]=>rdr[i];
    公共对象此[字符串名称]=>rdr[名称];
    public int Depth=>rdr.Depth;
    public bool IsClosed=>rdr.IsClosed;
    public int recordsafected=>rdr.recordsafected;
    public int FieldCount=>rdr.FieldCount;
    公众假期结束()
    {
    如果(!atEnd)
    返回;
    rdr.Close();
    }
    公共空间处置()
    {
    如果(!atEnd)
    返回;
    Dispose();
    }
    公共bool GetBoolean(int i)
    {
    返回rdr.GetBoolean(i);
    }
    公共字节GetByte(int i)
    {
    返回rdr.GetByte(i);
    }
    公共长GetBytes(int i,long fieldOffset,byte[]buffer,int bufferoffset,int length)
    {
    返回rdr.GetBytes(i,fieldOffset,buffer,bufferoffset,length);
    }
    公共字符GetChar(int i)
    {
    返回rdr.GetChar(i);
    }
    公共长GetChars(int i,long fieldoffset,char[]buffer,int bufferoffset,int length)
    {
    返回rdr.GetChars(i,fieldoffset,buffer,bufferoffset,length);
    }
    公共IDataReader获取数据(int i)
    {
    返回rdr.GetData(i);
    }
    公共字符串GetDataTypeName(int i)
    {
    返回rdr.GetDataTypeName(i);
    }
    公共日期时间GetDateTime(int i)
    {
    返回rdr.GetDateTime(i);
    }
    公共十进制GetDecimal(int i)
    {
    返回rdr.GetDecimal(i);
    }
    公共双精度GetDouble(int i)
    {
    返回rdr.GetDouble(i);
    }
    公共类型GetFieldType(int i)
    {
    返回rdr.GetFieldType(i);
    }
    公共浮点GetFloat(int i)
    {
    返回rdr.GetFloat(i);
    }
    公共Guid GetGuid(int i)
    {
    返回rdr.GetGuid(i);
    }
    公共短消息GetInt16(int i)
    {
    返回rdr.GetInt16(i);
    }
    公共整数GetInt32(整数i)
    {
    返回rdr.GetInt32(i);
    }
    公共长GetInt64(int i)
    {
    返回rdr.GetInt64(i);
    }
    公共字符串GetName(int i)
    {
    返回rdr.GetName(i);
    }
    public int GetOrdinal(字符串名称)
    {
    返回rdr.GetOrdinal(名称);
    }
    公共数据表GetSchemaTable()
    {
    返回rdr.GetSchemaTable();
    }
    公共字符串GetString(int i)
    {
    返回rdr.GetString(i);
    }
    公共对象GetValue(int i)
    {
    返回rdr.GetValue(i);
    }
    public int GetValues(对象[]值)
    {
    返回rdr.GetValues(值);
    }
    公共布尔IsDBNull(int i)
    {
    返回rdr.IsDBNull(i);
    }
    公共bool NextResult()
    {
    如果(!atEnd)
    {
    batchesRead+=1;
    rowsRead=0;
    返回true;
    }
    如果(已关闭)
    返回false;
    返回rdr。下一个
    
    with csv as (
        select n = row_number() over (order by (select null)),
            line = convert(nvarchar(max), concat(
                message_id, ',', language_id, ',', severity, ',',
                is_event_logged, ',', '"' + replace([text], '"', '""') + '"'))
        from sys.messages)
    
    select compress(string_agg(line, char(13)) within group (order by n))
    from csv group by n / 1000