問題を引き起こしているのはデータの量であり、データを送信/解析する方法ではない可能性が高いと思います (そして、データを受信するデバイスが 98 ポンドの弱いもの (Windows を実行している古いハンドヘルド デバイス) .NET 1.1)) を使用する CE では、一部のデータの 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.)
これを行う (レガシー - 私は書いていない) コードを調べると、(少なくとも私には) 奇妙に見えることがいくつかあり、データ サイズや解析方法論ではなく、そうなる可能性があるのではないかと考えています。問題の[少なくとも一部である]。
たとえば、次の 2 番目のインスタンスで var dSQL が使用されている理由はありますか? SqlCeCommand の CommandText プロパティと同じですが、params を使用しません。コンテキストに入れるために、かなりのコードを示します。
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 の解析ではなく、データベースへの挿入であり、"hicc[ough,up]フライスルーするパラメーターを持つのではなく、解明しなければならない SQL ステートメント内のクラス メンバーに直面するたびに)。XML 解析が CSV 解析よりもはるかにパフォーマンスが低い場合、それを高速化する方法はありますか、または CSV ファイルに切り替えることは本当に賢明ですか?
アップデート
XMLファイルの解析/読み取りの直前と直後に、 MessageBox.Show()s をコードに挿入してテストしました(そのようにする必要があります-これらの領域ではすでに長い話が何度もありました)。データを挿入する for ループの前後。確かに、私のテストデータは膨大ではありませんが、どちらの場合も、「開始」メッセージと「終了」メッセージの間の時間は実質的に瞬時でした...クロールまで速度が低下することに興味があります(テスターは、1つに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 列があると想定しているように見えますが、通常は自動インクリメントされるため、そうではありません。
おそらく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();
...VS2003 コード エディターでは、"res = cmd."、".Updatable |"、".Scrollable"、および "rec = rs." を除くすべてが赤です。
使用可能な「解決」コンテキスト メニュー項目はありません。「using System.Data.SqlServerCe;」があります。このユニットで。
一言で言えば、このアプリの問題点は、昔ながらのサイケデリックなスクリーン セーバーのように、自分自身の周りや下に織り込まれていることです。「スパゲッティ」という言葉は間違いなく頭に浮かびますが、おそらく「卵の殻」という言葉の方が適しているでしょう (ハンプティ・ダンプティを考えてください)。「スパゲッティが卵の殻に変わるのはいつ?」回答: 「不適切に記述されたコードが壊れた場合。」
更新 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」ループではないのでしょうか?