トップ回答者
BackgroundWorker内のSqlCommandでタイムアウト

質問
-
環境:VisualStudio 2005 .Net C# + SqlServer 2000
お世話になります。
数百万件のテーブルが5つあり、これらを読み込んである処理をするのに
1テーブル当たり数十分かかります。
そこで、時間短縮のために、BackgroundWorkerを5つ用意して(接続も5つ)、
同時にテーブルを読み込もうとしたところ、4つのBackgroundWorkerでタイムアウトが発生しました。
何がいけないのかアドバイスをいただけないでしょうか。
-----
SqlConnection[] sql_conn = new SqlConnection[4 + 1];
//sql_conn[0]~[5]すべてオープンする処理
NpgsqlConnection[] pg_conn = new NpgsqlConnection[4 + 1];
//pg_conn[0]~[5]すべてオープンする処理
BackgroundWorker[] bgw = new BackgroundWorker[4 + 1];
//
// 優先テーブル待ち合わせ
//
bgw[0].RunWorkerAsync(new DoWorkParam(sql_conn[0], pg_conn[0],100));
while (bgw[0].IsBusy)
{
Thread.Sleep(100);
Application.DoEvents();
}//
// BigTables 待ち合わせ
//
for (int i = 1; i <= 4; i++)
{
bgw[i].RunWorkerAsync(new DoWorkParam(sql_conn[i], pg_conn[i], 900+i));
}
bool bBusy = true;
while (bBusy)
{
Thread.Sleep(100);
Application.DoEvents();bBusy = false;
for (int i = 1; i <= 4; i++)
{
bBusy = bBusy || bgw[i].IsBusy;
}
}-----
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{// このメソッドへのパラメータ
DoWorkParam bgWorkerArg = (DoWorkParam)e.Argument;try
{
table = this.MainList.Rows[idx]["テーブル名"].ToString();//テーブル単位でトランザクション
trn = bgWorkerArg.pg_conn.BeginTransaction();try
{
// 件数取得
using (SqlCommand cmdCount = new SqlCommand(string.Format("SELECT COUNT(*) FROM {0}", table), bgWorkerArg.sql_conn))
{
this.MainList.Rows[idx]["件数"] = Convert.ToInt64(cmdCount.ExecuteScalar());
}
}
catch (Exception ex)
{
//ロールバック
if (trn != null)
{
trn.Rollback();
trn.Dispose();
trn = null;
}ret = false;
continue;
}try
{
using (SqlCommand cmd = bgWorkerArg.sql_conn.CreateCommand())
{
cmd.CommandText = string.Format("SELECT * FROM {0}", table);
using (SqlDataReader sqlrd = cmd.ExecuteReader())
{while (sqlrd.Read())
{//いろいろ処理が続く
---
public class DoWorkParam
{public SqlConnection sql_conn;
public NpgsqlConnection pg_conn;
public int group;
public DoWorkParam()
{}
public DoWorkParam(SqlConnection sql_conn, NpgsqlConnection pg_conn, int group)
{
this.sql_conn = sql_conn;
this.pg_conn = pg_conn;
this.group = group;
}
}---
回答
-
ただし、処理速度が遅いため(バッチなのでシビアではないのですが)改良しようとしています。「ある処理」と記載しましたが、SQLServerのデータを読み込んでPosgtreSQLにデータコピーしたいのです。
こういった処理には SSIS が向いているように思いますが、それはさておき。
そこで、時間短縮のために、BackgroundWorkerを5つ用意して(接続も5つ)、
同時にテーブルを読み込もうとしたところ、4つのBackgroundWorkerでタイムアウトが発生しました。
DB サーバーやクライアント PC のリソース(CPU とかメモリとかネットワークとか)は十分なのでしょうか。
BackgroundWorker を同時に走らせると重たい処理がいっぺんに動くことになるので、ひとつの Command の処理時間は長くなります。
コマンドの実行時間が長くなるのであれば、CommandTimeout を適切な時間に調整することも選択肢かと。
(SqlCommand のタイムアウトなのでデッドロックを真っ先に疑うところですが、テスト プログラムでその可能性はないことを確認してますよね。)
すべての返信
-
佐祐理さん、前回は「分割してFill?・・・」の件でお世話になりました。
アドバイスをいただき、DbCommand+DbDataReaderで対処することで
OutofMemoryExceptionが回避できました。その節はありがとうございます。
ただし、処理速度が遅いため(バッチなのでシビアではないのですが)改良しようとしています。
「ある処理」と記載しましたが、SQLServerのデータを読み込んでPosgtreSQLにデータコピーしたいのです。
ストアドで実現可能でしょうか?
また、実際の実現方法とは別に、タイムアウトが発生する理由も知っておきたいです。
小さいテーブルを5つ用意し、BackgroundWorkerを5つ用意して
同様のテストプログラムを作った場合はうまく動作しました。
原因がお分かりになりましたら教えてください。
-
ただし、処理速度が遅いため(バッチなのでシビアではないのですが)改良しようとしています。「ある処理」と記載しましたが、SQLServerのデータを読み込んでPosgtreSQLにデータコピーしたいのです。
こういった処理には SSIS が向いているように思いますが、それはさておき。
そこで、時間短縮のために、BackgroundWorkerを5つ用意して(接続も5つ)、
同時にテーブルを読み込もうとしたところ、4つのBackgroundWorkerでタイムアウトが発生しました。
DB サーバーやクライアント PC のリソース(CPU とかメモリとかネットワークとか)は十分なのでしょうか。
BackgroundWorker を同時に走らせると重たい処理がいっぺんに動くことになるので、ひとつの Command の処理時間は長くなります。
コマンドの実行時間が長くなるのであれば、CommandTimeout を適切な時間に調整することも選択肢かと。
(SqlCommand のタイムアウトなのでデッドロックを真っ先に疑うところですが、テスト プログラムでその可能性はないことを確認してますよね。)