---
title: "[C#] DataTable.SelectとLinqってどっちが早い？ | C#もぐもぐ"
description: "DataTable.SelectメソッドとLinqの検索時間の比較を行いました。"
url: "https://blog.223n.tech/posts/8/"
---

# \[C#] DataTable.SelectとLinqってどっちが早い？

2015年6月26日

[C#](https://blog.223n.tech/tags/C%23/) [Program](https://blog.223n.tech/tags/Program/)

今回は、DataTable.SelectメソッドとLinqの検索時間の比較を行いました。

Linqを使うと「Linq使うから処理が遅いんちゃうん」と、処理が遅い原因だと言われていました。

でも、「DataTableは遅い…でも、Linqはもーっと遅い…」っていうの、本当に正しいのでしょうか？

ということで、ちょっと探してみたところ、こんな記事を見つけてしまいました。

[DataTableからのデータ抽出方法の性能比較（かずきのBlog@hatena）](http://okazuki.hatenablog.com/entry/20091217/1261056768)

もうすでに、記事で結果が出てしまっていますが、百聞は一見に如かず（？）

今回は、この記事のプログラムを元に実際に計測してみました。

また、Linqでは、この記事とは異なる書き方があるので、そちらとの比較してみています。

## 【検証環境】

| 項目 | 内容 |
| - | - |
| CPU | Intel Core i7-4790 (3.60GHz x 2) |
| RAM | 16.0GB |
| OS | Microsoft Windows 8.1 |
| VS | Microsoft Visual Studio Community 2013 Update 4 |
| .NET | .NET Framework 4.5 |
| 言語 | C# |

まず、検索ですが、TEST No.1からNo.5で`DataTable.Select`メソッドと`Linq`を比較しました。

## \[TEST No.1] - Selectメソッドによる検索

何も考えずに、`table.Select(...)`での検索を計測した結果です。

```csharp
var rows = table.Select("COL_0 = 'DATA_10' OR COL_1 LIKE 'DATA_1%'", "COL_0");
```

## \[TEST No.2] - インデックスを作ってSelectメソッドによる検索

インデックスを生成した後、`table.Select(...)`での検索を計測した結果です。

```csharp
table.DefaultView.Sort = "COL_0, COL_1"; // <-この行の処理を計測に含まない
```

```csharp
var rows = table.Select("COL_0 = 'DATA_10' OR COL_1 LIKE 'DATA_1%'", "COL_0");
```

## \[TEST No.3] - インデックスを作ってSelectメソッドによる検索（インデックス生成含む）

インデックスの生成する前から、`table.Select(...)`で検索までを計測した結果です。

```csharp
table.DefaultView.Sort = "COL_0, COL_1"; // <-この行の処理を計測に含む
```

```csharp
var rows = table.Select("COL_0 = 'DATA_10' OR COL_1 LIKE 'DATA_1%'", "COL_0");
```

## \[TEST No.4] - Linq to Data SetでSelect（その１）

`from row in table.AsEnumerable()...` での検索を計測した結果です。

```csharp
var rows = (
                        from row in table.AsEnumerable()
                        let col0 = row.Field<string>("COL_0")
                        let col1 = row.Field<string>("COL_1")
                        where col0 == "DATA_10" || col1.StartsWith("DATA_1")
                        orderby col0
                        select row
                        ).ToArray();
```

## \[TEST No.5] - Linq to Data SetでSelect（その２）

`table.AsEnumerable().Where(...)`での検索を計測した結果です。

```csharp
var rows = table.AsEnumerable()
                        .Where(g => (g.Field<string>("COL_0") == "DATA_10") || g.Field<string>("COL_1").StartsWith("DATA_1"))
                        .OrderBy(g => g.Field<string>("COL_0"))
                        .ToArray();
```

TEST No.6からは、インデックスの有無による書き込みの比較を行いました。

## \[TEST No.6] - インデックスを作らずにデータ書き込み

インデックスを生成せずに、データの上書きを行いました。

## \[TEST No.7] - インデックスを作ってデータ書き込み

インデックスを生成してから、データの上書きを行いました。

計測結果は、以下の通りでした。

### ■SELECTテスト結果

| 回数 | TEST No.1 | TEST No.2 | TEST No.3 | TEST No.4 | TEST No.5 |
| - | - | - | - | - | - |
| 1回目 | 534ms | 161ms | 684ms | 83ms | 85ms |
| 2回目 | 581ms | 153ms | 669ms | 96ms | 86ms |
| 3回目 | 565ms | 167ms | 691ms | 88ms | 79ms |
| 4回目 | 529ms | 159ms | 724ms | 96ms | 73ms |
| 5回目 | 543ms | 160ms | 662ms | 78ms | 72ms |
| 集計 | 550ms | 160ms | 686ms | 88ms | 79ms |

### ■更新テスト結果

| 回数 | TEST No.6 | TEST No.7 |
| - | - | - |
| 1回目 | 131ms | 1231ms |
| 2回目 | 114ms | 1346ms |
| 3回目 | 125ms | 1333ms |
| 4回目 | 115ms | 1330ms |
| 5回目 | 109ms | 586ms |
| 集計 | 119ms | 1165ms |

（Excelのコピペで貼れるって、スゲー）

まず、DataTable.SelectとLinqとの比較結果ですが、差が広がりましたね…

また、件数が1000件程度と少ない場合、両方とも早すぎてわからないぐらい（0ms（計測不可）～8msとか）の差しかありませんでした。

やはり、Linqを使用したほうがよさそうです。

ただ、Linqでの比較でも、
「`from row in table ...`」よりも、「`table.AsEnumerable().Where(...)`」の方が
約10msほど早く処理されることもわかりました。

（これで、Linqは遅いという迷信（？）は払拭された…？）

そして、書き込みの比較は、なんというか、酷いです…

書き込むたびにインデックスを更新しているのでしょうか…？

（その場合、インデックスの再生成を更新のたびに行っているので、この遅さは何となくわかるのですが）

というわけで、くじけずにこれからもLinqを使っていきたいと思います。

以下ソース全文です。

```csharp
using System;
using System.Data;
using System.Diagnostics;
using System.Linq;
namespace DataTableVsLinq
{
    internal class Program
    {
#region Field
        /// 
        /// 行数
        /// 
        private const int COLUMN_NUM = 100000;
        /// 
        /// 列数
        /// 
        private const int ROW_NUM = 10;
#endregion
#region Method
        private static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("### TEST No.1 - Selectメソッドによる検索 ###");
                Console.WriteLine();
                TestNo1();
                Console.WriteLine();
                Console.WriteLine("### TEST No.2 - インデックスを作ってSelectメソッドによる検索 ###");
                Console.WriteLine();
                TestNo2();
                Console.WriteLine();
                Console.WriteLine("### TEST No.3 - インデックスを作ってSelectメソッドによる検索(インデックス生成含む) ###");
                Console.WriteLine();
                TestNo3();
                Console.WriteLine();
                Console.WriteLine("### TEST No.4 - Linq to Data SetでSelect（その１） ###");
                Console.WriteLine();
                TestNo4();
                Console.WriteLine();
                Console.WriteLine("### TEST No.5 - Linq to Data SetでSelect（その２） ###");
                Console.WriteLine();
                TestNo5();
                Console.WriteLine();
                Console.WriteLine("### TEST No.6 - 普通にデータ更新 ###");
                Console.WriteLine();
                TestNo6();
                Console.WriteLine();
                Console.WriteLine("### TEST No.7 - インデックスを作ってデータ更新 ###");
                Console.WriteLine();
                TestNo7();
                Console.WriteLine();
            }
            catch (Exception ex)
            {
                Console.WriteLine("### Error! ###");
                Console.WriteLine(ex.ToString());
                Console.WriteLine("##############");
            }
            finally
            {
                Console.WriteLine("Finish!");
            }
        }
        /// 
        /// TEST No.1 - Selectメソッドで検索する
        /// 
        private static void TestNo1()
        {
            for (int i = 0; i < 5; i++)
            {
                var table = CreateDataTable(COLUMN_NUM, ROW_NUM);
                Watch(() =>
                {
                    var rows = table.Select("COL_0 = 'DATA_10' OR COL_1 LIKE 'DATA_1%'", "COL_0");
                    Console.WriteLine("[検索] {0}行見つかりました", rows.Length);
                });
            }
        }
        /// 
        /// TEST No.2 - インデックスを作ってSelect
        /// 
        private static void TestNo2()
        {
            for (int i = 0; i < 5; i++)
            {
                var table = CreateDataTable(COLUMN_NUM, ROW_NUM);
                table.DefaultView.Sort = "COL_0, COL_1";
                Watch(() => 
                {
                    var rows = table.Select("COL_0 = 'DATA_10' OR COL_1 LIKE 'DATA_1%'", "COL_0");
                    Console.WriteLine("[検索] {0}行見つかりました", rows.Length);
                });
            }
        }
        /// 
        /// TEST No.3 - インデックスを作ってSelect（インデックス生成も含む）
        /// 
        private static void TestNo3()
        {
            for (int i = 0; i < 5; i++)
            {
                var table = CreateDataTable(COLUMN_NUM, ROW_NUM);
                Watch(() =>
                {
                    table.DefaultView.Sort = "COL_0, COL_1";
                    var rows = table.Select("COL_0 = 'DATA_10' OR COL_1 LIKE 'DATA_1%'", "COL_0");
                    Console.WriteLine("[検索] {0}行見つかりました", rows.Length);
                });
            }
        }
        /// 
        /// TEST No.4 - Linq to DataSetで検索（その１）
        /// 
        private static void TestNo4()
        {
            for (int i = 0; i < 5; i++)
            {
                var table = CreateDataTable(COLUMN_NUM, ROW_NUM);
                Watch(() =>
                {
                    var rows = (
                        from row in table.AsEnumerable()
                        let col0 = row.Field<string>("COL_0")
                        let col1 = row.Field<string>("COL_1")
                        where col0 == "DATA_10" || col1.StartsWith("DATA_1")
                        orderby col0
                        select row
                        ).ToArray();
                    Console.WriteLine("[検索] {0}行見つかりました", rows.Length);
                });
            }
        }
        /// 
        /// TEST No.5 - Linq to DataSetで検索（その２：最近自分でやっているLinqの書き方）
        /// 
        private static void TestNo5()
        {
            for (int i = 0; i < 5; i++)
            {
                var table = CreateDataTable(COLUMN_NUM, ROW_NUM);
                Watch(() =>
                {
                    var rows = table.AsEnumerable()
                        .Where(g => (g.Field<string>("COL_0") == "DATA_10") || g.Field<string>("COL_1").StartsWith("DATA_1"))
                        .OrderBy(g => g.Field<string>("COL_0"))
                        .ToArray();
                    Console.WriteLine("[検索] {0}行見つかりました", rows.Length);
                });
            }
        }
        /// 
        /// TEST No.6 - インデックスを作らずにデータ書き込みを行う
        /// 
        private static void TestNo6()
        {
            for (int i = 0; i < 5; i++)
            {
                var table = CreateDataTable(COLUMN_NUM, ROW_NUM);
                Watch(() => 
                {
                    foreach (var row in table.Rows.Cast<DataRow>())
                    {
                        row.BeginEdit();
                        foreach (var col in table.Columns.Cast<DataColumn>())
                            row[col] = "TEST";
                        row.EndEdit();
                    }
                });
            }
        }
        /// 
        /// TEST No.7 - インデックスを作ってからデータ書き込みを行う
        /// 
        private static void TestNo7()
        {
            for (int i = 0; i < 5; i++)
            {
                var table = CreateDataTable(COLUMN_NUM, ROW_NUM);
                table.DefaultView.Sort = "COL_0, COL_1";
                Watch(() =>
                {
                    foreach (var row in table.Rows.Cast<DataRow>())
                    {
                        row.BeginEdit();
                        foreach (var col in table.Columns.Cast<DataColumn>())
                            row[col] = "TEST";
                        row.EndEdit();
                    }
                });
            }
        }
        /// 
        /// サンプルテーブルを生成します
        /// 
        /// "rowCount">行数
        /// "columnCount">列数
        /// 
        private static DataTable CreateDataTable(int rowCount, int columnCount)
        {
            var dt = new DataTable("SampleTable");
            foreach (var column in Enumerable.Range(0, columnCount))
                dt.Columns.Add(string.Format("COL_{0}", column));
            var random = new Random();
            foreach (var row in Enumerable.Range(0, rowCount))
            {
                var newRow = dt.NewRow();
                foreach (var column in Enumerable.Range(0, columnCount))
                    newRow[column] = string.Format("DATA_{0}", random.Next(100));
                dt.Rows.Add(newRow);
            }
            return dt;
        }
        /// 
        /// 処理時間を計測、出力します
        /// 
        /// "action">計測する処理
        private static void Watch(Action action)
        {
            var watch = Stopwatch.StartNew();
            action();
            Console.WriteLine("[計測] 処理時間： {0}ms", watch.ElapsedMilliseconds);
            watch.Stop();
        }
#endregion
    }
}
```

[記事一覧に戻る](https://blog.223n.tech/posts/)
