2011-07-25 8 views
3

私はLINQを使用してデータベーステーブルにアクセスしています。テーブルの中には、何十万というレコードがあるものもあります。HUGEデータベーステーブルから読み取る

は、このようなステートメントを使用して、テーブルからの読み取り:

var records = db.Logs; 

は、アプリケーションが非常に非常に遅くなります。すべてのレコードを一度に読み込みます。

ように私は、条件よりも多くして、結果をフィルタリングする必要があります。問題は、テーブルからの私の最初の読み取りは私にすべてのレコードを持って来ると、アプリケーションが非常に遅くなりますということです

if (UserID != null) 
{ 
    records = records.Where(r => r.User == UserID); 
} 

if (UserIP != null) 
{ 
    records = records.Where(r => r.IP == UserIP); 
} 

SQLステートメントと同じように、LINQステートメントに条件を設定する方法はありますか?

これを作成するために使用方法を古いロジックです:

string sql = "SELECT * FROM Log WHERE 1=1"; 
if (UserID != null) 
{ 
    sql += " AND User = '" + UserID + "'"; 
} 

if (UserIP != null) 
{ 
    sql += " AND IP = '" + UserIP + "'"; 
} 

sqlCmd.query(sql); 
+0

このクエリを独自のスレッドで実行し、コールバックを使用して結果を取得していますか? –

+2

@ハミド、あなたはどのORMを使用していますか?エンティティフレームワーク? LINQ-to-SQL?どちらも、 'IQueryable'から' IEnumerable'や 'ToList()'への強制など、何かが行われない限り、あなたの "古いロジック"のように見えるスマートTSQLを生成します。 – bzlm

+0

@ハミド、可能であれば、SQLプロファイラを起動して、実際にサーバで実行されているクエリを確認できます。それはあなたにLINQ、EFについて多くのことを教えてくれるでしょう。 –

答えて

6

実際のような割り当て:

var records = db.Logs; 

はすぐにクエリを実行しません。後で使用するデータ構造だけを準備します。クエリの実行は、コードにデータが必要な場合にのみ発生し、where句がクエリに統合され、テーブル全体が返されなくなります。

このようなものを行うことは完全に可能である:

var records = db.Logs; 

    if (filter1) records = records.Where(r => r.Field1 == condition1); 
    if (filter2) records = records.Where(r => r.Field2 == condition2); 

これはどこのステートメントの動的(一種の)で、1つのクエリを実行して終了します。

ただし、正しいインデックスを定義する必要があります。

+0

もう一度私たちは次のように見ています。この主張を検証するための測定をしていない限り、ある特定のステートメントでのパフォーマンスの問題を非難しないでください。 'var records = db.Logs; 'は無実です。 – Heinzi

0

はこれを試してみてください:

List<Records> records; 

if (UserID != null) 
{ 
    records = db.Logs.Where(r => r.User == UserID).ToList(); 
} 
else 
{ 
    records = db.Logs.ToList(); 
} 
2

私はあなたが間違っていると思います。 db.Logsの呼び出しはIQueryableを返さなければなりません。つまり、データを取得する必要があるまでクエリは実行されません。 Logクラスのプロパティにアクセスするポイントや、コレクションをリストに変換する場合など.ToList()

2

db.Logsとは何ですか?それはIEnumerable<T>またはIQueryable<T>ではないですか?通常Linq2SQLクエリでは、.ToArrayまたは.ToListを呼び出すまで実行されないので、クエリツリーを最初に構築することができます。

0

SQL Serverを使用していると仮定すると、何十万行も膨大ではありません。

トピックに戻ると、IQueryable<T>を渡すと、列挙されるたびにSQLが実行されます。古いコードが正しいし、新しいコードが遅い場合、これはおそらくあなたの問題です。したがって、ToList()を呼び出してIEnumerable<T>に変換し、すべてのデータをメモリに入れることで回避できます。

最後に、.Skip(PageSize * PageIndex).Take(PageSize)を呼び出してデータをページングできます。

-1

ラムダ式を使用すると、リストに変換したり、すべてのデータを列挙したりするなど、使用するまでクエリは実行されません。

var filtered = (from l in db.Logs 
where l => l.User == UserID 
select l).ToList(); 
+0

話す前にお試しください、ありがとう。パフォーマンスについて本当に気にしているのであれば、linqを使用しないでください。 – gekowa

1

問題がテーブルからの私の最初の読み取りは私にすべてのレコードを持って来ると、アプリケーションが非常に遅くなりますということです。

var records = db.Logs 

テーブルから読み取れません。クエリを作成する以外は何もしていません(実行するためにコマンドテキストをデータベースに送信せずにSQLコマンドテキストを作成することに似ています)。 SQLコマンドをデータベースに送信する機能をオンにすると、このコード行がデータベースに何も送信しないことがわかります。実際には、この行もしませんどちらも:

records = records.Where(r => r.User == UserID); 

これはちょうどUserに条件を追加する(あなたが本当にrecordsQueryそれを呼び出す必要があります)records名前付きクエリを変更しています。クエリを繰り返し実行してから実際にデータベースに送信され、実行されるまではありません。だから、

records.ToList(); 

または

foreach(var record in records) { 
    // something something 
} 

またはクエリを実行する他の多くの方法のいずれか。

これは何歳に作成するために使用されるロジックです:私はないと思い

。ハローインジェクション攻撃!

テーブルの中には、(数十万件)のレコードがあるものがあります。

数十万は何もありません。

1

ページングを使用することで、必要なデータを取得してから別のページを取得することをお勧めします。

+1

+1はページングを提案します。 –