ADO.NET 2.0 DataRowのインデクサ呼び出しのアクセススピード

DataRowの各要素にアクセスするには、以下の3通りの方法がある。


1.インデクサに整数を指定する

Int32 n = (Int32)row[0];


2.インデクサに文字列を指定する

Int32 n = (Int32)row["id"];


3.インデクサにDataColumn型を指定する

DataColumn idCol = new DataColumn("id", typeof(Int32));
Int32 n = (Int32)row[idCol];

結論から言うと、この3通りの中の「3.インデクサにDataColumnを指定する」が一番速い。
計測用コードは以下の通り。OdbcDataAdapterのFillでDataTableにレコードを取得し、DataRowのインデクサを実行しているだけのコードです。データベースはPostgreSQLを用いて、DataAdapterのFillで取得したレコード数は3行です。

テーブルは以下のSQLで作成し、データを入れておく。

CREATE TABLE users(id int4, name text);
INSERT INTO users(id, name) VALUES(0, 'name0');
INSERT INTO users(id, name) VALUES(1, 'name1');
INSERT INTO users(id, name) VALUES(2, 'name2');
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Data.Odbc;
using System.Diagnostics;

class Program
{
    static void Main(string[] args)
    {
        String connStr = "接続文字列";
        OdbcConnection conn = new OdbcConnection(connStr);
        OdbcDataAdapter da = new OdbcDataAdapter(connStr, conn);
        DataTable table = new DataTable();

        da.SelectCommand = 
           new OdbcCommand("SELECT id, name FROM users;", conn);
        da.Fill(table);

        const Int32 count = 5000000;
        Stopwatch sw;
        

        //--------------------------------------------
        //1.DataRowのインデクサに整数を指定する
        sw = Stopwatch.StartNew();
        for (Int32 i = 0; i < count; i++)
        {
            foreach (DataRow row in table.Rows)
            {
                Int32 id = (Int32)row[0];
                String name = (String)row[1];
            }
        }
        Console.WriteLine("Case1(Integer)    Elapsed:{0}", sw.Elapsed);



        //--------------------------------------------
        //2.DataRowのインデクサに文字列を指定する
        sw = Stopwatch.StartNew();
        for (Int32 i = 0; i < count; i++)
        {
            foreach (DataRow row in table.Rows)
            {
                Int32 id = (Int32)row["id"];
                String name = (String)row["name"];
            }
        }
        Console.WriteLine("Case2(String)     Elapsed:{0}", sw.Elapsed);



        //--------------------------------------------
        //3.DataRowのインデクサにDataColumnを指定する
        sw = Stopwatch.StartNew();
        DataColumn idCol = table.Columns[0];
        DataColumn nameCol = table.Columns[1];
        for (Int32 i = 0; i < count; i++)
        {
            foreach (DataRow row in table.Rows)
            {
                Int32 id = (Int32)row[idCol];
                String name = (String)row[nameCol];
            }
        }
        Console.WriteLine("Case3(DataColumn) Elapsed:{0}", sw.Elapsed);
    }
}

結果

Case1(Integer)    Elapsed:00:00:01.9515062
Case2(String)     Elapsed:00:00:03.9037814
<span style="color:#FF0000;">Case3(DataColumn) Elapsed:00:00:01.7584871</span>

所要時間は、「DataColumn < Integer < String」となり、DataColumnが一番速い。また、インデクサに文字列を指定するよりもDataColumnを指定した方が2倍以上高速。DataRowに頻繁にアクセスするようなプログラムは、文字列でインデクサにアクセスせずにDataColumnにすると高速化が期待できる。



参考
プログラミングADO.NET2.0 (日経BPソフトプレス David Sceppa著)