バインド変数の利用

where句に指定されている条件をパラメータ変数にする事で、OracleのSQL解析が少なくなりパフォーマンスの向上につながります。(同時に、共有プールにキャッシュされたSQLを利用する為に、SQLの意味が同じでもスペースの個数、改行位置、大文字、小文字などを開発者間でルール化し記述するようにするといいでしょう)

具体的には、OracleCommandクラスのParameters.addメソッドでパラメータをセットしSQLを実行します。

Using cmd As New OracleCommand("select ENAME from EMPTEST where EMPNO = :P_EMPNO", cn)
    '名前指定パラメータにする
    cmd.BindByName = True

    'OracleCommandにパラメータを追加
    cmd.Parameters.Add("P_EMPNO", OracleDbType.Int32, ParameterDirection.Input)
    cmd.Parameters.Item("P_EMPNO").Value = 12345
End Using

サンプル

EMPTEST表(EMPと同内容で件数100万件)をEMPNOを条件にしてDataReaderでデータを取得するのを指定回数繰り返します。

Imports Oracle.DataAccess.Client

Public Class frmParameterBind

    Const ConnectionString As String = "DATA SOURCE=ORCL;User ID=scott;password=tiger;"


    ''' 
    ''' バインド無し
    ''' 
    ''' 
    ''' 
    ''' 
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim rd As OracleDataReader = Nothing
        Dim sw As New System.Diagnostics.Stopwatch()
        Dim i As Integer

        Try
            Using cn As New OracleConnection(ConnectionString)
                cn.Open()

                Using cmd As New OracleCommand("", cn)

                    'ストップウォッチを開始する 
                    sw.Start()

                    '指定回数ループする
                    For i = 0 To CInt(TextLoopCount.Text) - 1
                        cmd.CommandText = "select ENAME from EMPTEST " & _
						                  "where EMPNO = " & (i + 1).ToString
                        rd = cmd.ExecuteReader
                        rd.Close()
                    Next
                    'ストップウォッチを止める 
                    sw.Stop()

                    '結果を表示する 
                    TextTime1.Text = sw.Elapsed.ToString

                End Using

                cn.Close()

            End Using

        Catch ex As Exception
            MessageBox.Show(ex.Message)
        Finally
            If Not IsNothing(rd) Then
                If Not rd.IsClosed Then
                    rd.Close()
                End If
                rd.Dispose()
            End If

        End Try
    End Sub

    ''' 
    ''' パラメータバインド
    ''' 
    ''' 
    ''' 
    ''' 
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim rd As OracleDataReader = Nothing
        Dim sw As New System.Diagnostics.Stopwatch()
        Dim i As Integer
        Const cmdSelect As String = "select ENAME from EMPTEST where EMPNO = :P_EMPNO"

        Try
            Using cn As New OracleConnection(ConnectionString)
                cn.Open()

                Using cmd As New OracleCommand(cmdSelect, cn)

                    'ストップウォッチを開始する 
                    sw.Start()

                    '名前指定パラメータ指定
                    cmd.BindByName = True
                    'OracleCommandにパラメータを追加
                    cmd.Parameters.Add("P_EMPNO", OracleDbType.Int32, ParameterDirection.Input)

                    '指定回数ループする
                    For i = 0 To CInt(TextLoopCount.Text) - 1
                        cmd.Parameters.Item("P_EMPNO").Value = i + 1
                        rd = cmd.ExecuteReader
                        rd.Close()
                    Next
                    'ストップウォッチを止める 
                    sw.Stop()

                    '結果を表示する 
                    TextTime2.Text = sw.Elapsed.ToString

                End Using

                cn.Close()

            End Using

        Catch ex As Exception
            MessageBox.Show(ex.Message)
        Finally
            If Not IsNothing(rd) Then
                If Not rd.IsClosed Then
                    rd.Close()
                End If
                rd.Dispose()
            End If

        End Try
    End Sub

   
End Class

実行結果

実行時間が短縮されているのがわかります。

10,000回ループしました。
バインド変数無しの方は、約27秒掛かっています。一方バインド変数を利用した方は約18秒となりました。
20,000回ループしました。
2000回ループバインド変数無しの方は、約62秒掛かっています。一方バインド変数を利用した方は約37秒となりました。

履歴

2011/07/17
公開
Loading