【问题标题】:How do I improve performance of DataSet.ReadXml if I'm using a schema?如果我使用架构,如何提高 DataSet.ReadXml 的性能?
【发布时间】:2010-09-23 08:53:15
【问题描述】:

我有一个 ADO 数据集,我通过 ReadXml 从它的 XML 文件加载。数据和架构位于不同的文件中。

现在,加载这个 DataSet 需要将近 13 秒。如果我不读取 DataSet 的架构并让 ReadXml 推断架构,我可以将其缩短到 700 毫秒,但生成的 DataSet 不包含任何约束。

我试过这样做:

Console.WriteLine("Reading dataset with external schema.");
ds.ReadXmlSchema(xsdPath);
Console.WriteLine("Reading the schema took {0} milliseconds.", sw.ElapsedMilliseconds);
foreach (DataTable dt in ds.Tables)
{
   dt.BeginLoadData();
}
ds.ReadXml(xmlPath);
Console.WriteLine("ReadXml completed after {0} milliseconds.", sw.ElapsedMilliseconds);
foreach (DataTable dt in ds.Tables)
{
   dt.EndLoadData();
}
Console.WriteLine("Process complete at {0} milliseconds.", sw.ElapsedMilliseconds);

当我这样做时,读取架构需要 27 毫秒,读取数据集需要 12000 多毫秒。这是报告的时间之前我在所有 DataTables 上调用 EndLoadData。

这不是一个庞大的数据量 - 大约 1.5mb,没有嵌套关系,所有表都包含两到三列 6-30 个字符。如果我预先阅读架构,我唯一能想到的不同之处在于架构包含所有唯一约束。但是 BeginLoadData 应该关闭约束(以及更改通知等)。所以这不应该在这里适用。 (是的,我尝试将 EnforceConstraints 设置为 false。)

我读过很多关于人们通过先读取架构而不是让对象推断架构来改进 DataSet 加载时间的报告。在我的例子中,推断架构比显式提供架构快约 20 倍。

这让我有点疯狂。这个 DataSet 的模式是由元信息生成的,我很想编写一个方法来以编程方式创建它,并使用 XmlReader 对其进行反序列化。但我宁愿不这样做。

我错过了什么?我还能做些什么来提高这里的速度?

【问题讨论】:

    标签: c# performance ado.net dataset readxml


    【解决方案1】:

    我将尝试为您提供将数据存储在纯文本文件和 xml 文件中的性能比较。

    第一个函数创建两个文件:一个包含 1000000 条纯文本记录的文件和一个包含 1000000 条(相同数据)记录的 xml 文件。首先,您必须注意文件大小的差异:~64MB(纯文本)与~102MB(xml文件)。

    void create_files()
        {
            //create text file with data
            StreamWriter sr = new StreamWriter("plain_text.txt");
    
            for(int i=0;i<1000000;i++)
            {
                sr.WriteLine(i.ToString() + "<SEP>" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbb" + i.ToString());
            }
    
            sr.Flush();
            sr.Close();
    
            //create xml file with data
            DataSet ds = new DataSet("DS1");
    
            DataTable dt = new DataTable("T1");
    
            DataColumn c1 = new DataColumn("c1", typeof(int));
            DataColumn c2 = new DataColumn("c2", typeof(string));
    
            dt.Columns.Add(c1);
            dt.Columns.Add(c2);
    
            ds.Tables.Add(dt);
    
            DataRow dr;
    
            for(int j=0; j< 1000000; j++)
            {
                dr = dt.NewRow();
                dr[0]=j;
                dr[1] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbb" + j.ToString();
                dt.Rows.Add(dr);
            }
    
            ds.WriteXml("xml_text.xml");
    
        }
    

    第二个函数读取这两个文件:首先它将纯文本读取到字典中(只是为了模拟使用它的真实世界),然后读取 XML 文件。这两个步骤都以毫秒为单位(并将结果写入控制台):

    开始将文本文件读入内存
    文本文件在 7628 毫秒内加载到内存中
    开始将 XML 文件读入内存
    XML 文件在 21018 毫秒内加载到内存中

    void read_files()
        {
    
            //timers
            Stopwatch stw = new Stopwatch();
            long milliseconds;
    
            //read text file in a dictionary
    
            Debug.WriteLine("Start read Text file into memory");
    
            stw.Start();
            milliseconds = 0;
    
            StreamReader sr = new StreamReader("plain_text.txt");
            Dictionary<int, string> dict = new Dictionary<int, string>(1000000);
            string line;
            string[] sep = new string[]{"<SEP>"};
            string [] arValues;
            while (sr.EndOfStream!=true) 
            {
                line = sr.ReadLine();
                arValues = line.Split(sep,StringSplitOptions.None);
                dict.Add(Convert.ToInt32(arValues[0]),arValues[1]);
            }
    
            stw.Stop();
            milliseconds = stw.ElapsedMilliseconds;
    
            Debug.WriteLine("Text file loaded into memory in " + milliseconds.ToString() + " milliseconds" );
    
    
    
            //create xml structure
            DataSet ds = new DataSet("DS1");
    
            DataTable dt = new DataTable("T1");
    
            DataColumn c1 = new DataColumn("c1", typeof(int));
            DataColumn c2 = new DataColumn("c2", typeof(string));
    
            dt.Columns.Add(c1);
            dt.Columns.Add(c2);
    
            ds.Tables.Add(dt);
    
            //read xml file
    
            Debug.WriteLine("Start read XML file into memory");
    
            stw.Restart();
            milliseconds = 0;
    
            ds.ReadXml("xml_text.xml");
    
            stw.Stop();
            milliseconds = stw.ElapsedMilliseconds;
    
            Debug.WriteLine("XML file loaded into memory in " + milliseconds.ToString() + " milliseconds");
    
        }
    

    结论:XML文件大小几乎是文本文件大小的两倍,加载速度比文本文件慢三倍。

    XML 处理比纯文本更方便(因为抽象级别),但它更消耗 CPU/磁盘。

    因此,如果您有小文件并且从性能的角度来看是可以接受的,那么 XML 数据集就可以了。但是,如果您需要性能,我不知道 XML 数据集(使用任何可用的方法)是否比纯文本文件更快。基本上,它从第一个原因开始:XML 文件更大,因为它有更多标签。

    【讨论】:

    • XML 解析只是我所描述的时间的一小部分。 XmlReader 可以在半秒内遍历我存储的 DataSet。你提出的建议可能会将那半秒缩短到几乎没有。但是另外 12.5 秒 不是 由 XML 解析引起的呢?
    【解决方案2】:

    确切地说,这不是一个答案(尽管它总比没有好,这是我到目前为止所得到的),但是在解决这个问题很长时间之后,我发现当我的程序不在 Visual Studio 中运行时它完全不存在.

    我之前没有提到过,这使这更加神秘的是,当我将一个不同的(但相当大的)XML 文档加载到 DataSet 中时,程序运行得很好。我现在想知道我的一个数据集是否附加了某种元信息,Visual Studio 在运行时检查而另一个没有。我不知道。

    【讨论】:

      【解决方案3】:

      另一个要尝试的方法是读取没有架构的数据集,然后将Merge 读取到启用了约束的类型化数据集。这样一来,它在构建用于强制约束的索引时就拥有所有手头的数据——也许它会更有效?

      来自MSDN

      通常调用 Merge 方法 在一系列程序结束时 涉及验证更改, 核对错误,更新数据 源与更改,最后 刷新现有数据集

      【讨论】:

        猜你喜欢
        • 2013-11-16
        • 1970-01-01
        • 2012-02-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-15
        相关资源
        最近更新 更多