SQLServerでDataTableの内容を一度のSQLでデータベースに更新する

DataTable の内容をデータベースに登録、または更新したい場合がある。
しかし、DataTable の行をループしながら行毎に INSERT 文や UPDATE 文を発行すると IO 負荷が高くなり、パフォーマンスが悪化する。
そこで、SQL Server のユーザー定義テーブル型を使用することにより一括での更新が可能となる。

前提条件:SQL Server 2008 以降

 

IO負荷が高い例

まずは、悪例としてデータテーブルのレコードを 1 件ずつ INSERT していく方法。
上記の方法だと件数が少なければ問題が無いように感じるが、1万件を超えてくるとそのパフォーマンスの悪さが目立ってくる。
1万件のデータをループして INSERT すると1万回の IO 処理となり、オーバーヘッドが大きくなる。
しかし、次の方法で INSERT すると1回の IO 処理で済む為、更新するデータ量は変わらないがかなりのパフォーマンス改善が見込まれる。

 

DataTableをパラメータとして渡す

DataTable をパラメータとして渡す為には、SQL Server 側にユーザー定義テーブル型を作成しておく必要がある。

テーブルの定義と同様に括弧の中にフィールド定義を記述する。
テーブルで定義できるフィールドはTableTypeでも定義可能。

続いて、プログラム側の処理。

ユーザー定義テーブル型を使用することで DataTable をテーブルのように渡すことができる為、一括で SELECT して INSERT または UPDATE が可能となる。

<注意事項>

  • DataTable のフィールドはユーザー定義テーブル型のフィールドと一致している必要がある。
  • ユーザー定義テーブル型を渡す場合は、SqlDbType.Structured で渡す。

 

ユーザー定義テーブル型を作成しておく必要はあるが、こちらの方法であれば実行速度が圧倒的に速く、パフォーマンス改善が期待できる。
デメリットとしては、ループせずに一括で更新する為、プログレスバーなどで進捗を表示することができない。

 

.net(VB、C#)でLINQを利用してCSVファイルを読み込む

LINQでCSVファイルを読み込む

.NETには、CSVファイルを読み取る際に便利なクラス(TextFieldParser)が「VB.NET」のライブラリに存在する。

このクラスを利用してCSVファイルをLINQで簡潔に扱えるようにする。

まず、CSVファイルへのコンテキストを生成する為のTextFieldクラスを作成する。

このクラスのContextメソッドでコンテキストを生成することでロジックを意識することなくCSVファイルの読み込みが可能になる。

 

 

次は、実際にTextFieldクラスを利用してコンテキストを生成し、CSVファイルへアクセスしてLINQにより入力した条件に一致するレコードデータを表示するコードを記述する。

尚、AsParallel()メソッドを呼び出すことで条件判定をマルチスレッド化できるので、データ量が多い場合は、並列化による高速化が期待できる。

 

 

複数ファイルを跨いで検索する場合は以下のように記述することができる。

※全てのファイルレイアウトが同じ場合

 

 

 

.net(VB、C#)でWindowの列挙を行う

API関数のEnumWindowsを使うことで、全てのウィンドウのハンドル(HWND)を取得する事ができる。

EnumWindowsを呼び出すと、コールバックメソッドが呼び出され、存在する個々のウィンドウのHWNDが渡される。

以下の例では、EnumWindows()でウィンドウを列挙し、コールバックメソッド内ではIsWindowVisible()を使って可視ウィンドウかどうかを調べている。

また、個々の可視ウィンドウについて、GetWindowText()を使ってウィンドウのキャプションを、GetWindowThreadProcessId()とProcess.GetProcessByIdを使ってプロセス情報を取得・表示している。

 

 

 

 

 

.net(VB、C#)でコンピューター名を取得する

.netでプログラムを実行中のコンピューター名を取得するには、以下の方法がある。

 

Environment.MachineName プロパティ

ローカル コンピュータの NetBIOS 名を取得する。

(NetBIOS名はすべて大文字で、小文字は大文字に自動変換される。)

<必要条件>

名前空間: System
アセンブリ: mscorlib (mscorlib.dll 内)

<構文>

<解説>

コンピュータの名前は、システムの起動時に、名前がレジストリから読み込まれた時点で確定される。

コンピュータがクラスタ内のノードである場合は、ノード名が返される。

<例>

実行しているコンピュータの名前を表示するコード例を次に示す。

 

My.Computer.Name プロパティ(VBのみ)

コンピュータ名を取得する。

戻り値にコンピュータの名前を格納した String を返す。

<必要条件>

名前空間: Microsoft.VisualBasic.Devices
クラス: Computer、ServerComputer
アセンブリ: Visual Basic ランタイム ライブラリ (Microsoft.VisualBasic.dll 内)

<構文>

<解説>

My.Computer.Name プロパティは、MachineName プロパティと同様の機能を提供する。

<例>

実行しているコンピュータの名前を表示するコード例を次に示す。

 

 

.Net(VB、C#)のWPFで要素の行・列のサイズを動的に変更する

<Grid>要素の行・列のサイズを動的に変更したい場合、<Grid>要素の子に<GridSplitter>要素を配置する。

尚、<GridSplitter>要素を利用する場合、以下のような注意点がある。

<GridSplitter>要素自体、<Grid>要素のセルを1つ占有する為、<GridSplitter>要素を配置するための行・列を「auto」指定で作成しておく必要がある。

<GridSplitter>要素は、デフォルトの状態では幅も高さも「0」で不可視となる為、見えるサイズに調整する必要がある。
(HorizontalAlignment属性に「Stretch」を指定して、上下分割の場合はGrid.ColumnSpanとHeight、左右分割の場合はGrid.RowSpanとWidthにそれぞれ値を指定する)

「特定の1行だけ列幅を変えたい」というようなことは1つの<Grid>要素内では行えない為、<Grid>要素を入れ子にして内側の<Grid>要素だけに<GridSplitter>要素を追加するなどの工夫が必要になる。