如果我使用模式,如何提高DataSet.ReadXml的性能?
-
08-07-2019 - |
题
我有一个ADO DataSet,我通过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);
当我这样做时,读取模式需要27ms,读取DataSet需要12000+毫秒。这就是之前报告的时间我在所有DataTable上调用EndLoadData。
这不是一个庞大的数据量 - 大约1.5mb,没有嵌套关系,并且所有表包含两到三列6-30个字符。如果我事先阅读架构,那么我唯一能想到的就是架构包含了所有独特的约束。但是BeginLoadData应该关闭约束(以及更改通知等)。所以这不适用于此。 (是的,我尝试过将EnforceConstraints设置为false。)
我已经阅读了很多关于人们通过首先读取模式而不是让对象推断模式来改善DataSet的加载时间的报告。在我的例子中,推断模式使得进程比明确提供模式快20倍。
这让我有点疯狂。这个DataSet的模式是从元信息生成的,我很想编写一个以编程方式创建它的方法,并使用XmlReader对其进行解除分类。但我更不愿意。
我错过了什么?我还能做些什么来提高速度呢?
解决方案 2
这不是一个答案,确切地说(虽然它比没有更好,这是我到目前为止所得到的),但经过长时间的努力解决这个问题,我发现当我的程序没有在Visual Studio中运行时它完全不存在。
之前我没有提到的,这使得这更加神秘,是当我将不同的(但相当大的)XML文档加载到DataSet中时,程序执行得很好。我现在想知道我的一个DataSet是否有某种形式的元信息附加到Visual Studio在运行时检查而另一个没有。我不知道。
其他提示
我将尝试在文本普通文件和xml文件中存储数据之间进行性能比较。
第一个函数创建两个文件:一个文件包含1000000个纯文本记录,另一个文件包含1000000个(相同数据)的xml记录。首先你必须注意文件大小的差异:~64MB(纯文本)vs~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文件更大,因为它有更多标签。
尝试的另一个方面是在没有架构的情况下读取数据集,然后 < strong> 合并 将其添加到已启用约束的类型化数据集中。这样它就拥有了所有的数据,因为它构建了用于强制执行约束的索引 - 也许它会更有效率?
来自 MSDN :
通常调用Merge方法 在一系列程序结束时 涉及验证更改, 协调错误,更新数据 来源与变化,最后 刷新现有的DataSet
。