質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Q&A

解決済

3回答

2410閲覧

C# 分割してcommitを発行させるにはどうしたらいいでしょうか。

kumakumatan

総合スコア213

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

0グッド

0クリップ

投稿2022/07/04 05:30

編集2022/07/05 17:41

C# で10万件のデータを一括インサートをする際、アプリのメモリが落ちてしまい、
インサートできないでいます。これを分割して(5千件毎に)Insertしてcommitを発行させる方法をご教授いただきたく
思います。

C#

1List<string> listA = new List<string>(); 2//10万件追加 3listA.Add(xxxx); 4 5StringBuilder strSql = new StringBuilder(); 6OracleConnection objConn; 7OracleCommand objCmd; 8OracleTransaction objTran = null; 9 10objTran = objConn.BeginTransaction(); //トランザクション開始 11 12strSql.AppendLine("INSERT INTO TABLE1"); 13strSql.AppendLine(" ("); 14strSql.AppendLine(" TEST1"); 15strSql.AppendLine(" ) "); 16strSql.AppendLine("VALUES ("); 17strSql.AppendLine(" :A"); 18strSql.AppendLine(" ) "); 19 20objCmd = new OracleCommand(); 21{ 22 objCmd.Connection = objConn; 23 objCmd.BindByName = true; 24 objCmd.ArrayBindCount = listA.Count; 25 26 OracleParameter oraA; 27 oraA = new OracleParameter("A", OracleDbType.Varchar2, ParameterDirection.Input); 28 oraA.ArrayBindSize = listA.Count; 29 oraA.Value = listA.ToArray(); 30 objCmd.Parameters.Add(oraA); 31 32 objCmd.CommandType = CommandType.Text; 33 objCmd.CommandText = strSql.ToString(); 34 intResult = objCmd.ExecuteNonQuery(); 35 36} 37 38objTran.Commit();//コミット

宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KOZ6.0

2022/07/04 07:30

これ本当に実行できますか? OracleParameter.ArrayBindSize は int[] なので oraA.ArrayBindSize = listA.Count; の行がコンパイルエラーになるはずです。
dodox86

2022/07/04 07:53

提示のコードは多分、質問用にオリジナルのコードを編集し、端折っているのでしょうね。提示のコードではobjConnをいきなり使っているし。 > OracleConnection objConn; ... > objTran = objConn.BeginTransaction(); //トランザクション開始 質問のテーマとしては少し興味ありますが、10万件のデータを生成してどこでアプリが落ちているかにもよりますね。10万件をlistA.Add()しているところでメモリ使用量が増えてアップアップしそうですし、あとでlistA.ToArray()したところまた肥大しそうです。executeNonQuery()実行時に止めを刺している可能性も。テンポラリファイルにいったん保存して、外部ツールのSQL*Loaderを起動して実行するなんて手もありそうです。
KOZ6.0

2022/07/04 08:05

あと、oraA.ArrayBindSize には項目長の配列を入れるのですが、TABLE1.TEST1 の項目長はいくつですか?
guest

回答3

0

ベストアンサー

■ OracleBulkCopy を使った方法

C#

1var dt = new DataTable(); 2dt.Columns.Add("TEST1"); 3foreach (var value in listA) { 4 dt.Rows.Add(value); 5} 6 7using (OracleBulkCopy bulkCopy = new OracleBulkCopy(objConn)) { 8 bulkCopy.DestinationTableName = "TABLE1"; 9 bulkCopy.BatchSize = 5000; 10 bulkCopy.WriteToServer(dt); 11}

■ 5000件毎に INSERT

C#

1using (OracleCommand objCmd = new OracleCommand()) { 2 objCmd.CommandText = "INSERT INTO TABLE1(TEST1) VALUES (:A)"; 3 objCmd.Connection = objConn; 4 objCmd.BindByName = true; 5 using (OracleParameter oraA = new OracleParameter("A", OracleDbType.Varchar2, ParameterDirection.Input)) { 6 objCmd.Parameters.Add(oraA); 7 8 const int perCount = 5000; 9 int start = 0; 10 int count; 11 int allCount = listA.Count; 12 oraA.Value = new string[perCount]; 13 14 while (start < allCount) { 15 if (start + perCount < allCount) { 16 count = perCount; 17 } else { 18 count = allCount - start; 19 } 20 objCmd.ArrayBindCount = count; 21 listA.CopyTo(start, (string[])oraA.Value, 0, count); 22 23 using (var objTrn = objConn.BeginTransaction()) { 24 objCmd.Transaction = objTrn; 25 objCmd.ExecuteNonQuery(); 26 objTrn.Commit(); 27 } 28 29 start = start + count; 30 } 31 } 32}

ParameterDirection.Output のとき、OracleParameter.ArrayBindSize は必須ですが、ParameterDirection.Input の場合は省略可能です。
ただ、OracleParameter.Size と、この値を正しく設定すると、10万件まとめて処理できるかもしれません。

投稿2022/07/04 09:18

編集2022/07/05 00:29
KOZ6.0

総合スコア2622

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kumakumatan

2022/07/05 00:43

ご回答ありがとうございます。 5000件毎に INSERTを試したのですが、 例外がスローされました: 'System.InvalidOperationException' (Oracle.ManagedDataAccess.dll の中) 接続はすでにローカルまたは分散トランザクションの一部です となり、書込みできないです・・。 どうしようか悩んでいます。 宜しくお願いします。
KOZ6.0

2022/07/05 01:12

このコードに入る前に objConn.BeginTransaction が実行されているのでは?
kumakumatan

2022/07/05 02:19

はい。されていました。それを外すと、とりあえず実行できました。 もう少しでできそうです。 ありがとうございます。
KOZ6.0

2022/07/05 04:06

ではクローズしてください。
kumakumatan

2022/07/05 05:26

すいません。今回はOracleDbType.Varchar2ですが、これが「OracleDbType.Decimal」の場合、どのように するかで現在悩んでいます。 oraA.Value = new string[perCount]; listA.CopyTo(start, (string[])oraA.Value, 0, count); のstringをDecimalにしてもできないので悩んでいます。 宜しくお願いします。
KOZ6.0

2022/07/05 07:51

便乗質問はやめましょう。 といいたいところですが、listA のところは List<Decimal> になってますか?
kumakumatan

2022/07/05 08:41

すいません。修正したらできました。ありがとうございました。
guest

0

質問のコメント欄に、

https://teratail.com/questions/kx7sfuoukv2uph の私の回答の【追記】で書いたようにしてできませんか?

と書いた件のサンプルコードです。SQL Server の例で SQL 文は UPDATE ですが、一回の接続で 3 回 UPDATE を実行しています。この応用でできませんか?

string query = "UPDATE [TestDatabase].[dbo].[TestResult] " + "SET [StudentID]=@StudentID " + "WHERE [TestResultID]=@TestResultID"; using (var connection = new SqlConnection(connString)) { using (var command = new SqlCommand(query, connection)) { command.Parameters.Add( new SqlParameter("@StudentID", SqlDbType.Int)); command.Parameters.Add( new SqlParameter("@TestResultID", SqlDbType.Int)); connection.Open(); var sqltx = connection.BeginTransaction(); command.Transaction = sqltx; command.Parameters["@StudentID"].Value = 5; command.Parameters["@TestResultID"].Value = 1; command.ExecuteNonQuery(); command.Parameters["@StudentID"].Value = 6; command.Parameters["@TestResultID"].Value = 2; command.ExecuteNonQuery(); command.Parameters["@StudentID"].Value = 4; command.Parameters["@TestResultID"].Value = 3; command.ExecuteNonQuery(); sqltx.Commit(); } }

投稿2022/07/04 07:02

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

例えば、100件のデータをインサートすることはできるでしょうか。
それができたなら、それを千回繰り返せば、10万件インサートできるってことになりますが。

投稿2022/07/04 05:34

y_waiwai

総合スコア87719

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2022/07/04 05:38

Q「分割する方法を教えてください」 A「分割した作業を繰り返せば良い」 こういう回答、そろそろやめませんか?
y_waiwai

2022/07/04 05:41

回答に不満があるならあなたにとってのベストな回答をしてやってください。 自分では回答もしないくせに文句つけるってのはそろそろやめにしませんかw
kumakumatan

2022/07/04 05:51

ご回答ありがとうございます。 100件のデータならインサートは可能です(実証済)。 listAに値を10万件全て入れているので、その値を例えば5千件毎にInsertしてcommitする方法 が知りたく思います。 宜しくお願い致します。
Zuishin

2022/07/04 05:54

> 自分では回答もしないくせに文句つけるってのはそろそろやめにしませんかw 他の質問に回答しています。 回答に不備があれば理由とともに低評価をするのはこのサイトの仕組みなので、気に入らなければ知恵袋へ移行するのが良いと思います。 低評価の理由を書くたびにいちいち煽るのもやめましょう。 直せば済むことです。
Zuishin

2022/07/04 06:06 編集

キャンプ場で「ゴミを散らかすな」と言われて「ゴミを散らかしもしないくせに文句を言うな」と怒る人がいたら滑稽だと思うでしょう。散らかすなと言われたら、散らかすのを我慢すれば良いことです。
Zuishin

2022/07/04 06:13

> これを分割して(5千件毎に)Insertしてcommitを発行させる方法をご教授いただきたく > 思います。 これが質問です。 それにこたえるのが回答です。 自分では回答しているつもりなのか知りませんが、あなたのは回答ではありません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問