2010-12-16 5 views
0

私はページングされたテーブルに使用されるSQLコードにlinqをいくつか見ていました。その中では、レコードのサブセットとデータベース内のレコードの総数を返す必要があります。コードは次のようになります。Linq to sql - レコードのサブセットとレコードの総数を返す最適な方法

var query = (from p in MyTable select new {p.HostCable, p.PatchingSet}); 
int total = query.ToList().Count; 
query = query.Skip(5).Take(10); 

私はこれが実行されたときに何が起こるかにビットを掘るしたい、私は2つのクエリが起こることを確認 - 1デシベルからすべての行を取得するには、サブセットを取得する1。言うまでもありませんが、すべてのレコードを取得するパフォーマンスの影響は良くありません。私は、 "ToList"が強制的にクエリが実行され、Countメソッドがリスト全体に対して実行されると思います。より効率的にするために再ファクタリング声明で

- これが私の改良版である:これは、実際のSQLヒット、その後「.. SELECT COUNT」のためのSQLヒットをもたらし、

int total = MyTable.Count(); 
var query = (from p in MyTable select new {p.HostCable, p.PatchingSet}).Skip(5).Take(10); 

レコードの選択。

これは最適ですか、より良い解決策がありますか?

ありがとうございます!むしろこれは、クエリを経由して、カウントを実行し、ちょうどはるかに高速である必要があり、その数を返します。そして、すべてを選択し、メモリ内のオブジェクトのカウントを行うよりも

答えて

1
int total = query.Count(); 

あなたの更新に応じて、私はあなたがそれを行うより良い方法を得るとは思わない。最終的には、レコードの合計数を取得するクエリと、それらのサブセットを取得するクエリの2つのクエリになります。

+0

私は同意します。これが最善の方法でしょう。カウント(*)操作は通常、(正しいインデックスを使用して)非常に高速です。 – Steven

2

私が見たことから、これはLINQ to SQLではハッキングのビットなしでは不可能です。

この方法が機能することがわかりました。このメソッドの簡単な概要:IQueryableオブジェクトをコマンドオブジェクトに変換し、結果セットに合計カウントを含めるようにコマンドテキストを変更します。元のLINQ to SQLコンバータSQLクエリでは、ROW_NUMBER() OVER()構文を使用して行をページングします。合計カウントを取得するにはCOUNT(*) OVER()を追加するだけです。

このメソッドをDataContextクラスに追加します。

public IEnumerable<TWithTotal> ExecutePagedQuery<T, TWithTotal>(IQueryable<T> query, int pageSize, int pageNumber, out int count) 
    where TWithTotal : IWithTotal 
{ 
    var cmd = this.GetCommand(query.Skip(pageSize * pageNumber).Take(pageSize)); 
    var commandText = cmd.CommandText.Replace("SELECT ROW_NUMBER() OVER", "SELECT COUNT(*) OVER() AS TOTALROWS, ROW_NUMBER() OVER"); 
    commandText = "SELECT TOTALROWS AS TotalCount," + commandText.Remove(0, 6); 
    cmd.CommandText = commandText; 

    var reader = cmd.ExecuteReader(); 

    var list = this.Translate<TWithTotal>(reader).ToList(); 

    if (list.Count > 0) 
     count = list[0].TotalCount; 
    else 
     count = 0; 

    return list; 
} 

IWithTotalインターフェイスを実装する元のオブジェクトのすべてのプロパティを含む新しいクラスを作成する必要があります。

更新日: LINQ to SQLでは、マップされた列とマップされていない列を混在させることはできません。

public interface IWithTotal 
{ 
    int TotalCount { get; set; } 
} 

public class Project : IWithTotal 
{ 
    public int TotalCount { get; set; } 
    public int ProjectID { get; set; } 
    public string Name { get; set; } 
} 

DataContext.Translateあなたはどんな問題がある場合ので、あなたのクエリがこれらの要件を満たしていることを確認し、いくつかの要件があります。

クエリの複雑さによっては、パフォーマンスが向上するはずです。以下は、カウントクエリ、ページングされた選択クエリ、およびカウントクエリを使用したページングされた選択のテストのメトリックです。パーセンテージは、バッチに対するクエリコストです。

Count - 6% 
Select with paging - 47% 
Select with paging + Count - 48% 
関連する問題