2

次のような単純なテキストログエントリをSQLテーブルに書き込んでいます。

private SqlConnection sqlcon;

// ...

try {
    sqlcon.Open();

    SqlCommand cmd = sqlcon.CreateCommand();
    cmd.CommandText = this.logString;

    cmd.ExecuteNonQuery();
} 
/* catch SqlException, InvalidOperationException, Exception */ 
/* finally sqlcon.Close() */

非同期処理はfalseに設定されているので、ログエントリは実行順にテーブルに表示されると思いました。ただし、2つ以上のログエントリが約5ミリ秒以内に発生する場合は、そうではありません。

したがって、私の推測では、ExecuteNonQueryは別のスレッドで実行され、どういうわけか別のイベントが混同されます。私はすでにBeginExecuteNonQueryとEndExecuteNonQueryで非同期処理を使用しようとしましたが、それは私のコードを台無しにし、とにかく実際には機能していません。

だから私の質問は:nonQueriesがトリガーされた順序で正確に実行されていることを確認する方法はありますか?

編集:多分それは重要です、私はそのようなタイムスタンプを使用しています

cmd.Parameters.Add("timestamp", SqlDbType.DateTime ).Value = System.DateTime.Now;
4

4 に答える 4

2

非同期?

確信が持てないたびに接続を開いたり閉じたりする場合は、呼び出すのと同じです(これは正確ではないことをご承知おきください)BeginExecuteNonQuery(MARS以前に使用されていた方法でした)。実際には、各要求は同期していますが、5ミリ秒間隔でログを記録すると、SQL Serverがその要求を処理する順序を確認できません(ここのDB担当者は、IDENTITY列の古い問題について考えます)。

タイムスタンプ

次に、解決策はTimeStamp列を使用し、その列に基づいて結果を並べ替えることです(書き込みの順序は重要ではありません)。これは完璧なソリューションです(他の回答で指摘されているように、データを格納するために正しいデータ型を使用することを忘れないでください)。

実際の時間を取得する方法は?DateTime.Now 関数を使用してクライアント側(例のように)で、またはSYSDATETIME(@PetrAbdulinによって示されるように)サーバー側でそれを行うことができます。高解像度が必要ない場合、これは完璧なソリューションです。

精度

どちらの機能もWindowsシステムタイマーに依存しており、その解像度は10ミリ秒を超えることはできません(したがって、本当に5ミリ秒の粒度が必要な場合は、それらを回避する必要があります)。

MSDNでは、DateTime.Nowの解像度は10ミリ秒で、SYSDATETIMEはGetSystemTimeAsFileTimeを呼び出し、FILETIME構造体の精度は100ミリ秒ですが、タイマー自体はその結果を達成するために付与されていません。条件によっては、1ミリ秒のティックが発生することもありますが、信頼性はまったくありません。StopWatchタイマーに関するドキュメントでは、次のように読むことができます。

Stopwatchクラスで使用されるタイマーは、システムのハードウェアとオペレーティングシステムによって異なります。ストップウォッチタイマーが高解像度パフォーマンスカウンターに基づいている場合、IsHighResolutionはtrueです。それ以外の場合、IsHighResolutionはfalseです。これは、ストップウォッチタイマーがシステムタイマーに基づいていることを示します。

どういう意味ですか?システムタイマーに高解像度が付与されることはありません(時間を格納するために使用される構造の精度と混同しないでください)。

問題になるかどうかはわかりませんが、ログを何に使用するかによって異なります。バックアップ中にあるフォルダから別のフォルダにコピーされたファイルのリストをログに記録する必要がある場合は、そのような精度は必要ない場合があります。ログが法的な目的で使用される可能性がある場合(はい、法的な価値はないはずです)、または微妙なスレッドの問題をデバッグするためにログが必要になります。

ソリューション

高解像度タイマーが必要な場合(および、Windowsでは、10ミリ秒未満のものを高解像度と見なすことができます)、パフォーマンスカウンターを処理する必要があります。タイミングについてのこの素晴らしい記事を見てください。もちろん、すべてのものは必要ありませんが、問題があります。

.NETでは、(プロパティのチェック)DateTime.Nowとともに使用できます。の精度を上げるためのの使用については、SOに関するこの良い投稿を読んでください。StopWatchIsHighResolutionStopWatchDateTime.Now

一般的なエラー

まず、時間を格納するために使用されるデータ型の精度とタイマーの解像度を混同しないでください。その値を低解像度のフィールドに保存する場合、タイマーがどれだけ正確であるかは問題ではありませんが、高解像度のフィールドを使用しても、粗いタイマーが高解像度のタイマーに変換されることはありません。

さらに、現地時間をTimeStampとして使用しないでください。夏時間のためにシステム時刻が変更されると、ログが混乱します。これについて考えます:

               00:00 02:00 02:01 03:00 02:00
ログ#1#2#3#4
システム時間-1

ログを読むと、1、2、4、3の順序になります。このため、ログには絶対に使用DateTime.NowないSYSDATETIMEでください。ログには、常にDateTime.UtcNowandSYSUTCDATETIME関数を使用する必要があります(さらに、のパフォーマンスはDateTime.UtcNow少しです)より良い)。

于 2012-04-11T10:17:26.303 に答える
1

SQL ServerSYSDATETIMEを使用してタイムスタンプを挿入するとどうなりますか?これは同期的だと思いますがExecuteNonQuery、タイムスタンプに問題がある可能性があります。

Windowsの時間解決に関する優れたドキュメントがあります。

于 2012-04-11T10:26:01.090 に答える
1

SQLServerの日時の精度は3ミリ秒です。順不同でリストされているエントリのタイムスタンプは同じですか?(ミリ秒が0、3、または7で終わる場合)。

datetime2データ型(SQL Server 2008から利用可能)などのより精度の高いフィールド、またはアイテムを正しく並べ替えるための増分カウンターが必要です。

于 2012-04-11T10:27:12.003 に答える
0

なぜトランザクションを使用しないのですか?データが重要な場合は、SqlTransactionを使用する必要があります。

なぜ注文が必要なのですか?あなたはあなたのテーブルにpkを持っていますか?それはどのように挿入されますか、またはタイムスタンプはあなたのpkですか?

ちなみに、接続をキャッシュしないでください。.netはあなたのためにそれをより良くやっています。このmsdnの例のように使用してください。

于 2012-04-11T10:31:26.247 に答える