3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LinuxでLINQを使う場合は、LINQ to SQLのみにする

3
Last updated at Posted at 2026-02-17

LINQ とは

LINQ(Language Integrated Query)とは、配列・リスト・DB・XML・JSON・ファイルなど、あらゆるデータに対して、同じ書き方で検索・抽出・変換をすることのできる仕組みです。

主に、SQLのような書き方をし、C#のコードの中でデータを操作します。

いつから使えるの?

.NET Framework 3.5 (2007年頃)から導入されました。C#の言語バージョンは 3.0 からとなります。現在も継続して使える機能の一つで、チューニングされ続けています。

  • .NET Framework 3.5(2007年)
  • C# 3.0
    このタイミングで、
  • ラムダ式
  • 拡張メソッド
  • 匿名型
  • LINQ
    がまとめて導入されました。
    現在の .NET(Core / 5〜8)でも当然使えます。

LINQの最適化と「LINQ to Objects」と「LINQ to SQL」の違い

LINQ の最適化は “LINQ to Objects” と “LINQ to SQL” で挙動が違うってこと。
Linux では特に LINQ to Objects の最適化が弱く、Windows より遅くなるケースがある。
つまり:

  • SQL(Entity Framework / LINQ to SQL)
    → DB 側が最適化するので OS による差はほぼ出ない
  • メモリ上のデータ(LINQ to Objects)
    → 実行環境(Windows / Linux)で最適化の差が出る
    → 特に大量データでは顕著

要件としては次の通り

Linux では

  • 配列数が 10万件を超える場合は、LINQ to Objects を使って where 等はしない方が良い...

Windows では

  • 配列数が多くても LINQ to Objects を使う方が早い...

これは、LinuxとWindows のLINQ に対する最適化やインライン化、OSそのものの仕組みの影響なのか、30万件のデータ処理をしてみると、Windows では LINQ がはやく、Linux では野良書きの方が処理速度が速いという結果に

実際に検証した実行環境

検証した内容

linux 環境(本サーバー)

  • Rocky Linux 9.7
  • Dotnet core 8.0(ASP.NET Core-SDK)
  • CPU: AMD Ryzen Threadripper(32core/64thread)
  • DDR4 128GB
  • M2(PCIe4)

windows(ASP.NET開発環境)

  • Microsoft Windows 11 Professional
  • AMD Ryzen 7 5850U
  • DDR4 32GB
  • M2(PCIe3)

DB に商品情報を 40万件登録している。その構造を元に、staticメモリ上に設置

例:

class Products {
    public ulong Id {set;get;}
    public Guid Guid {set;get;}
    public string Category {set;get;}
    public string ProductTitle {set;get;}
    ...
}

上記構造を

    public static Dictionary<ulong, Products> ProductsCache = new();

    init 処理にて...
    ProductsCach = await _context.Products.AsNoTracking().Where( g => g.Stauts == 1 ).ToDictionaryAsync( g => (ulong)g.Id, g => g );

とし、DBから読み込んだ40万件の結果を ProductsCache に放り込む。なぜ、static にして入れているかは、mariadb を利用しており、日本語検索が弱く、Mroonga では、候補がなかなか引っかからず、LIKE をすると、1サーバーで搭載してのサービス提供なので、DBでは抽出が遅すぎて想定の時間に裁けなかった。しかたないので、物理メモリに押し込んで無理矢理やることにした。

そして、なんか、Windowsでやったときより遅いなーと思って、試しに調べてみると、確かに、Windowsは早いけど、Linux遅い...っていうことに気が付いた。

ちなみに、どうやって調べたのかというと

[HttpGet]
[Route("/")]
public ResponseResult GetListProducts(int page, int line = 100, string sort = "", string orderby = "asc") {
    var start = DateTime.Now;

    ... 処理

    return new {
        RuntimeAt = (DateTime.Now - start).TotalMilliseconds,
        ....
    }
 }

... 処理部に、LINQ to Object による条件式を使って取得する。このとき、処理部に 取得条件やorderby などがはいってくる。この処理を linq to objects を使うと遅くなるが、いくつか条件があり、where 区や any 区が遅いようで、Orderby と .OrderByDescending 区については、あまり遅くない気がしている。(現在、いろいろと検証中)

ちなみに、何があったの

Linuxにて、static のメモリ上に抽出したデータ(40万件)の検索をかけて抽出するコードを、linqを使って実装していた(DBでの検索だと遅すぎるので)。抽出結果は100件毎に json としてまとめて返すようにし、page 処理で分けるようにしていた(つまり、WebApi)。 結果は、windows では600ms で結果を返し、 linux では 3000ms 秒もかかることが判明した。
原因は何かと探った結果、linq の最適化がWindows/Linuxでは違うようで、foreach や List に変換した昔ならあのコーティングをすると、windows と同等の抽出結果になった。 このことから、遅延実行をしたい場合やEntityFramework としてのSQLとして利用する場合を除く、メモリ上のデータをやり取りする場合は、LINQを使わない方が良いという考えになった。

ところが、野良書き(LINQ to Objects を使わず、foreach 等を使って書いたコード)は、Windowsでは、linqよりも遅くなってしまった。この結果、最適化が強い部分が、OSの影響で変わっているようなので、コーティングする場合は、LINQを積極的に使うのがいいか、昔ながらのコーティングのがいいのか考える必要があることがわかった。

3
2
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?