虽然我认为这很可能是导致问题的数据量,而不是我们发送/解析它的方式(以及接收数据的设备是 98 磅的事实。weakling(运行 Windows 的旧手持设备) CE 使用 .NET 1.1)),我的任务是更改某些数据的 XML 处理以解析将代替它们的 CSV 文件。
“有问题的”数据是典型的 XML 票价:
<PlatypusItems>
<PlatypusID>DARINTULIP</PlatypusID>
<PlatypusItemID>010476</PlatypusItemID>
<ItemID>01820000468</ItemID>
<BillSize>15</BillSize>
</PlatypusItems>
<PlatypusItems>
<PlatypusID>DARINTULIP</PlatypusID>
<PlatypusItemID>011065</PlatypusItemID>
<ItemID>01820000478</ItemID>
<BillSize>15</BillSize>
</PlatypusItems>
<PlatypusItems>
<PlatypusID>DARINTULIP</PlatypusID>
<PlatypusItemID>015165</PlatypusItemID>
<ItemID>01820000481</ItemID>
<BillSize>15</BillSize>
</PlatypusItems>
<PlatypusItems>
<PlatypusID>DARINTULIP</PlatypusID>
<PlatypusItemID>010420</PlatypusItemID>
<ItemID>01820000907</ItemID>
<BillSize>24</BillSize>
</PlatypusItems>
(etc.)
在查看执行此操作的(遗留 - 我没有编写)代码时,我看到了一些看起来很奇怪的事情(至少对我来说),并且想知道它们是否可能,而不是数据大小或解析方法,成为问题的[至少一部分]。
例如,在下面的第二个实例中使用 var dSQL 有什么原因吗?它与 SqlCeCommand 的 CommandText 属性相同,但不使用参数。为了把它放在上下文中,我将展示一些代码:
if (File.Exists(filePathName)) // <-- filePathName contains the name of the XML file to be parsed
{
DataSet dset = new DataSet("DuckbillSetup");
dset.ReadXml(filePathName);
dSQL = "DELETE FROM Platypi";
try
{
dbconn.DBCommand(dSQL, true);
}
catch
{
//bla [elided/excised]
}
SqlCeConnection conn = dbconn.GetConnection();
if (conn != null && conn.State == ConnectionState.Closed)
{
conn.Open();
}
SqlCeCommand cmd = conn.CreateCommand();
cmd.CommandText = "INSERT INTO Platypi ( PlatypusID, PlatypusItemID, ItemID, BillSize) VALUES (?, ?, ?, ?)";
foreach (DataTable tab in dset.Tables)
{
if (tab.TableName.ToLower() == "Platypi".ToLower())
{
foreach (DataRow row in tab.Rows)
{
PlatypusItem PlatypusItm = new PlatypusItem();
if (!ret)
ret = true;
foreach (DataColumn column in tab.Columns)
{
if (column.ColumnName == "PlatypusID")
{
PlatypusItm.PlatypusID = (string) row[column];
}
else if (column.ColumnName == "PlatypusItemID")
{
if (!row.IsNull(column))
PlatypusItm.PlatypusItemID = (string) row[column];
else
PlatypusItm.PlatypusItemID = "";
}
else if (column.ColumnName == "ItemID")
{
if (!row.IsNull(column))
PlatypusItm.ItemID = (string) row[column];
else
PlatypusItm.ItemID = "";
}
else if (column.ColumnName == "BillSize")
{
if (!row.IsNull(column))
PlatypusItm.BillSize = Convert.ToInt32((string) row[column]);
else
PlatypusItm.BillSize = 0;
}
}
PlatypusItemList.List.Add(PlatypusItm);
dSQL = "INSERT INTO Platypi (PlatypusID, PlatypusItemID, ItemID, BillSize) VALUES (" + PlatypusItm.PlatypusID + ",'" +
PlatypusItm.PlatypusItemID + "','" + PlatypusItm.ItemID + "'," + PlatypusItm.BillSize + ")";
if (!First)
{
cmd.Parameters[0].Value = PlatypusItm.PlatypusID;
cmd.Parameters[1].Value = PlatypusItm.PlatypusItemID;
cmd.Parameters[2].Value = PlatypusItm.ItemID;
cmd.Parameters[3].Value = PlatypusItm.BillSize.ToString();
}
if (First)
{
cmd.Parameters.Add("@PlatypusID", PlatypusItm.PlatypusID);
cmd.Parameters.Add("@PlatypusItemID", PlatypusItm.PlatypusItemID);
cmd.Parameters.Add("@ItemID", PlatypusItm.ItemID);
cmd.Parameters.Add("@BillSize", PlatypusItm.BillSize);
cmd.Prepare();
First = false;
}
if (frmCentral.CancelFetchInvDataInProgress)
{
return false;
}
try
{
dbconn.DBCommand(cmd, dSQL, true); // <-- Why dSQL? Why not: dbconn.DBCommand(cmd, cmd.CommandText, true);
}
. . .
...我倾向于认为问题更可能是在命令中使用了 dSQL(所以问题不是 XML 的解析,而是插入到数据库中,这可能是“打嗝 [ough,up] ing” 每次它在 SQL 语句中遇到那些必须解开的类成员时,而不是让参数飞过)。如果XML 解析的性能比 CSV 解析低得多,有没有办法加快它,或者切换到 CSV 文件真的明智吗?
更新
我刚刚通过将 MessageBox.Show()s 放入代码中进行了测试(我必须这样做 - 长篇故事已经在这些地区多次哀叹),就在解析/读取 XML 文件之前和之后,并且只是在插入数据的 for 循环之前和之后。诚然,我的测试数据并不庞大,但在这两种情况下,“开始”和“完成”消息之间的时间几乎是瞬时的......很好奇一个人会慢下来(测试人员说一个人需要 10 分钟)网站加载,他推断另一个网站需要 30 分钟(没有等待它))。
更新 2
我不太清楚如何应用从这里摘录的以下代码http://msdn.microsoft.com/en-us/library/537kf788(v=vs.90).aspx(链接到 ErikEJ 的答案):
cmd.CommandText = "SELECT * FROM myTable";
SqlCeResultSet rs = cmd.ExecuteResultSet(ResultSetOptions.Updatable |
ResultSetOptions.Scrollable);
SqlCeUpdatableRecord rec = rs.CreateRecord();
// Insert 10 records
//
for (int i = 0; i < 10; i++)
{
rec.SetInt32(0, i);
rs.Insert(rec);
}
首先从表中读取所有记录真的有必要/明智吗?如果里面有无数的记录怎么办?还是实际上并没有这样做?
SetInt32() 是做什么的?看起来它可能假设该表有一个正在更新的 ID 列,但那不可能,因为通常那些会是 autoinc'd,所以......???
也许rec.SetInt32(0,i)只是一个占位符:
rec.MyFirstClassmember(bla);
rec.MySecondClassmember(Blee);
...etc.
但无论如何,“SqlCeResultSet”和“SqlCeUpdatableRecord”对我来说似乎都不可用 - 事实上,使用以下代码:
SqlCeResultSet rs = cmd.ExecuteResultSet(ResultSetOptions.Updatable | ResultSetOptions.Scrollable);
SqlCeUpdatableRecord rec = rs.CreateRecord();
...除了“res = cmd.”、“.Updatable |”、“.Scrollable”和“rec = rs”之外,VS2003 代码编辑器中的所有内容都是红色的。
没有可用的“解决”上下文菜单项;我确实有“使用 System.Data.SqlServerCe;” 在本单元中。
简而言之,这个应用程序的问题在于它像老式的迷幻屏幕保护程序一样在自身周围和之下编织。“意大利面条”这个词肯定会浮现在脑海中,而且很合适,但也许更好的词是“蛋壳”(想想 Humpty Dumpty)。这可能是一个很大的难题:“意大利面什么时候变成蛋壳?” 答案:“当写得不好的代码中断时。”
更新 3
在下面的评论中提供的链接(http://mobilesandbox.blogspot.dk/2009/02/sql-compact-insert-performance.html )中的项目代码中:
rs = cmd.ExecuteResultSet(ResultSetOptions.Updatable);
rec = rs.CreateRecord();
for(i = 0; i < m_nSampleSize; ++i)
{
rec.SetInt32(0, i);
rs.Insert(rec);
}
...似乎同一条记录(rec)被一遍又一遍地插入。我错了吗?rs 是否足够聪明,知道每次都递增到结果集中的下一条记录?如果是这样,为什么它不能只是一个“while not endOfResultSet”循环?