

EntityFramework6、ASP.NET(MVC)プロジェクト(C#)で初めて開発しています。  
DBはAzure SQLデータベースです。  
IDが主キーで、name,ageなどのカラムがあるmemberというテーブルが検索に時間がかかるので、ageに非クラスタ化インデックスを作成しました。  
その状態で以下の実行プランを見るとnameのデータを取得するためキー参照となります。

[code]

    select id, name, age from member where age >= 25
    
[/code]

それを回避するには、(age, name)で複合インデックスやIncludeオプションで作成すると良いようです。

そこで沸いた疑問なのですが、EntityFrameworkの場合、以下のようにして取得します。  
SELECT句を指定していないのでカラムすべてを取得していると思うのですが、インデックスは効かないということになるのでしょうか？

[code]

    using (var db = new SampleContext())
    {
        var query = db.member.Where(m => m.age >= 25);
    
        foreach (var member in query)
        {
            Console.WriteLine("id={0},name={1},age={2}", member.id, member.name, member.age);
        }
    }
    
[/code]

EntityFrameworkを使う場合はインデックスは無意味になってしまうのか？ということと、その場合処理時間の短縮はどうしたらよいのかお聞きしたいです。  
初心者なので色々おかしいかもしれませんがよろしくお願いいたします。

* * *

（追記）  
以下のコードでSQLを取得してみました。

[code]

    using (var db = new SampleContext())
    {
        db.Database.Log = sql => { Console.WriteLine(sql); };
    
        var query1= db.member.Where(e => e.age == 25);
    
        var query2 = db.member.Where(e => e.age == 25).Select(e => new { e.id, e.name, e.age } );
    }
    
    // query1
    //SELECT 
    //    [Extent1].[id] AS [id],
    //    [Extent1].[name] AS [name],
    //    [Extent1].[mail_address] AS [mail_address],
    //    [Extent1].[type] AS [type],
    //    [Extent1].[age] AS [age]
    //    FROM [dbo].[member] AS [Extent1]
    //    WHERE [Extent1].[age] = @p__linq__0
    //
    // query2
    //SELECT 
    //    1 AS [C1]
    //    [Extent1].[id] AS [id]
    //    [Extent1].[name] AS [name]
    //    [Extent1].[age] AS [age]
    //    FROM [dbo].[member] AS [Extent1]
    //    WHERE [Extent1].[age] = @p__linq__0
    
    
[/code]

このSQLで実行プランを見たところ、主キー(id)しかインデックスがない状態ではどちらもClustered Index Scan 100%でした。  
以下のようにIncludeオプションでインデックスを作成した状態では、query1はIndex Seek50%、キー参照50%で、query2はIndex
Seek100%でした。  
`CREATE INDEX IX_member ON member (age) INCLUDE(name)`

100回ぐらい処理時間を計測したところ、平均して30ミリ秒程度ですがquery2の方が遅かったです。  
既存プログラムでは、query1の使い方がほとんどなので、そうなるとインデックスはあんまり効果ないということになるのでしょうか？

Includeオプションで他のカラムをすべて指定しておくという使い方はアリなのでしょうか？

こちらの利用も初めてですみません。引き続きよろしくお願い致します。


CC BY-SA 4.0
2020-10-27T03:53:07.700
71530
2020-12-14T09:53:46.950
2020-10-28T06:03:19.903
42489
42489
question
c# database sql-server entity-framework sql-azure
EntityFrameworkを使用した場合のSQL Serverのインデックスの有効性について教えてください。


Entity
Frameworkは魔法でもなんでもなく、指示に従ってSQL文を生成したうえで、生成したSQL文をDBエンジンに実行させます。生成したSQL文は[データベース操作のログ記録と受信](https://docs.microsoft.com/ja-
jp/ef/ef6/fundamentals/logging-and-interception)で確認することができます。

DBエンジン側は受け取ったSQL文を解析し、インデックスが使えるかを判断します。

ですので、

  * Entity FrameworkがどのようなSQL文を生成したのか
  * DBエンジンがSQL文をどのように解釈したのか

の2段階に分けて判断してください。

* * *

> 100回ぐらい処理時間を計測したところ、平均して30ミリ秒程度ですがquery2の方が遅かったです。  
>  既存プログラムでは、query1の使い方がほとんどなので、そうなるとインデックスはあんまり効果ないということになるのでしょうか？

相対値として30ms程度とのことですが、絶対値はいかがでしょうか？
もともと短時間で済む処理であれば、インデックスの効果が薄くなってしまうのかもしれません。また、このクエリはプログラム全体の処理の中で有意のあるウェイトを占める処理なのでしょうか？
[80:20の法則](https://ja.wikipedia.org/wiki/%E3%83%91%E3%83%AC%E3%83%BC%E3%83%88%E3%81%AE%E6%B3%95%E5%89%87)という言葉もあるように、十分に高速な部分をさらに高速化しても全体としては得るものがありません。


CC BY-SA 4.0
2020-10-27T06:25:21.727
71533
2020-10-29T08:57:31.153
2020-10-29T08:57:31.153
4236
4236
71530
answer


一般論としては、select * from table where index_column = x でもインデックスは使われます。  
但し、参照するテーブルの件数が少ない場合、オプティマイザが全件取得の方が効率が良いと判断する可能性もあります。この場合は、インデックスは使われません。

おそらくamamさんは、インデックスが利用されることと、インデックスの参照だけでクエリの実行が完了することを混同されているのではないかと思います。

includeオプションで全てのカラムを指定するというのは、本来テーブルとして利用すべきものを全てIndexの領域にも保存するということですので、異常な使い方です（もしかしたらその方が良い場面もあるかもしれませんが）。


CC BY-SA 4.0
2020-12-14T09:53:46.950
72646
2020-12-14T09:53:46.950
8647
71530
answer