C#中遍历DbReader/DataSet实现数据库表转Base64编码XML的高效方案
优化方案
核心瓶颈定位
你当前的性能问题完全不是遍历列的迭代操作导致的,最大的性能损耗来自两个点:
- 直接用
string类型的+=做大量拼接:C#中string是不可变类型,每次+=操作都会在堆中重新生成一个包含全部内容的新字符串,数据量稍大就会产生大量内存碎片和GC开销,性能呈指数级下降 - 用
try-catch捕获异常来处理空值:异常捕获的开销远大于正常的空值判断,属于完全不必要的性能浪费
遍历所有列是必然操作(你需要输出所有列的节点),不存在能跳过遍历的写法,你感知到的迭代开销都是上述两个问题放大的假象。当前方案不需要为每张表创建实体,完全适配任意表结构,灵活性可以满足需求。
优先级最高的优化:替换字符串拼接为StringBuilder
直接修改你原有DataReader版本的代码,改完性能至少提升10~100倍:
// 初始化StringBuilder,预先分配一定容量减少扩容开销,可根据平均表大小调整初始值 StringBuilder sb = new StringBuilder(1024 * 1024); OdbcCommand DbCommand = DbConnection.CreateCommand(); DbCommand.CommandText = "SELECT * FROM " + dbTable; OdbcDataReader DbReader = DbCommand.ExecuteReader(); int fCount = DbReader.FieldCount; string[] colnames = new string[fCount]; sb.Append('<').Append(dbTable).Append(">\n"); for (int i = 0; i < fCount; i++) { colnames[i] = DbReader.GetName(i); } while (DbReader.Read()) { sb.Append("\t<export_row>\n"); for (int i = 0; i < fCount; i++) { string col = ""; // 替换try-catch为原生IsDBNull判断,消除异常捕获开销 if (!DbReader.IsDBNull(i)) { col = DbReader.GetString(i); } if (col.Length > 0 || i == 0) { sb.Append("\t\t<") .Append(colnames[i]) .Append(">") .Append(Base64Encode(col)) .Append("</") .Append(colnames[i]) .Append(">\n"); } } sb.Append("\t</export_row>\n"); } sb.Append("</").Append(dbTable).Append(">\n"); // 最终输出只需要一次ToString() string output = sb.ToString();
进阶优化:使用XmlWriter直接输出到流
如果表数据量非常大,不需要把整个XML存在内存中,可以用XmlWriter直接写入文件/网络流,内存占用会降到极低,同时XML格式更规范:
// 示例直接输出到本地文件 using (XmlWriter writer = XmlWriter.Create($"输出路径/{dbTable}.xml", new XmlWriterSettings() { Indent = true, IndentChars = "\t" })) { writer.WriteStartElement(dbTable); OdbcCommand DbCommand = DbConnection.CreateCommand(); DbCommand.CommandText = "SELECT * FROM " + dbTable; using (OdbcDataReader DbReader = DbCommand.ExecuteReader()) { int fCount = DbReader.FieldCount; string[] colnames = new string[fCount]; for (int i = 0; i < fCount; i++) { colnames[i] = DbReader.GetName(i); } while (DbReader.Read()) { writer.WriteStartElement("export_row"); for (int i = 0; i < fCount; i++) { string col = ""; if (!DbReader.IsDBNull(i)) { col = DbReader.GetString(i); } if (col.Length > 0 || i == 0) { writer.WriteElementString(colnames[i], Base64Encode(col)); } } writer.WriteEndElement(); } } writer.WriteEndElement(); }
内容的提问来源于stack exchange,提问作者Edwin Dijk
相关产品推荐
相关产品推荐

