5

私は次のコードを持っていますが、これは誤動作しています:

TPM_USER user = UserManager.GetUser(context, UserId);
var tasks = (from t in user.TPM_TASK
             where t.STAGEID > 0 && t.STAGEID != 3 && t.TPM_PROJECTVERSION.STAGEID <= 10
             orderby t.DUEDATE, t.PROJECTID
             select t);

最初の行UserManager.GetUserは、データベースで単純なルックアップを実行して、正しいTPM_USERレコードを取得します。ただし、2行目は、あらゆる種類のSQLの混乱を引き起こします。

まず、ここで2つのSQLステートメントを実行しています。最初の行は、そのユーザーにリンクされているすべての行を取得TPM_TASKします。これは、数万行になることもあります。

SELECT 
 -- Columns
 FROM  TPMDBO.TPM_USERTASKS "Extent1"
 INNER JOIN TPMDBO.TPM_TASK "Extent2" ON "Extent1".TASKID = "Extent2".TASKID
 WHERE "Extent1".USERID = :EntityKeyValue1

このクエリは、多くのタスクを持つユーザーで約18秒かかります。WHERE句にSTAGEIDフィルターも含まれていると思います。これにより、行の大部分が削除されます。

TPM_PROJECTVERSION次に、上記のリストの各ペアに対して新しいクエリを実行しているようです。

SELECT 
 -- Columns
 FROM TPMDBO.TPM_PROJECTVERSION "Extent1"
 WHERE ("Extent1".PROJECTID = :EntityKeyValue1) AND ("Extent1".VERSIONID = :EntityKeyValue2)

このクエリは高速ですが、ユーザーが多数のプロジェクトにタスクを持っている場合、数百回実行されます。

生成したいクエリは次のようになります。

SELECT 
 -- Columns
 FROM  TPMDBO.TPM_USERTASKS "Extent1"
 INNER JOIN TPMDBO.TPM_TASK "Extent2" ON "Extent1".TASKID = "Extent2".TASKID
 INNER JOIN TPMDBO.TPM_PROJECTVERSION "Extent3" ON "Extent2".PROJECTID = "Extent3".PROJECTID AND "Extent2".VERSIONID = "Extent3".VERSIONID
 WHERE "Extent1".USERID = 5 and "Extent2".STAGEID > 0 and "Extent2".STAGEID <> 3 and "Extent3".STAGEID <= 10

上記のクエリは約1秒で実行されます。通常、メソッドをJOIN使用して指定できます。Includeただし、これはプロパティでは機能しないようです。言い換えれば、私はできません:

from t in user.TPM_TASK.Include("TPM_PROJECTVERSION")

このLINQステートメントを最適化する方法はありますか?バックエンドDBとして.NET4とOracleを使用しています。

解決:

このソリューションは、以下のKirkの提案に基づいており、context.TPM_USERTASK直接クエリできないため機能します。

var tasks = (from t in context.TPM_TASK.Include("TPM_PROJECTVERSION")
             where t.TPM_USER.Any(y => y.USERID == UserId) &&
             t.STAGEID > 0 && t.STAGEID != 3 && t.TPM_PROJECTVERSION.STAGEID <= 10
             orderby t.DUEDATE, t.PROJECTID
             select t);

直接クエリを実行するのではなく、ネストされた結果になりますが、それでもかなり効率的です。SELECTTPM_USERTASK

4

1 に答える 1

4

はい、特定のユーザーをプルダウンしてから、関係を参照していTPM_TASKます。そのユーザーに関連付けられているすべてのタスクをプルダウンしているということは、まさにそれが実行していることになっていることです。この方法で実行している場合、ORMSQL変換はありません。ユーザーを取得し、そのすべてのタスクをメモリに取り込み、クライアント側のフィルタリングを実行します。これはすべて遅延読み込みを使用して行われるため、SQLは何もバッチ処理できないため、非常に非効率になります。

代わりに、クエリを書き直して、ユーザーを直接対象とTPM_TASKし、ユーザーをフィルタリングします。

var tasks = (from t in context.TPM_TASK
         where t.USERID == user.UserId && t.STAGEID > 0 && t.STAGEID != 3 && t.TPM_PROJECTVERSION.STAGEID <= 10
         orderby t.DUEDATE, t.PROJECTID
         select t);

チェック方法に注意してくださいt.USERID == user.UserId。これはと同じ効果を生み出しますuser.TPM_TASKが、今ではすべての面倒な作業はメモリではなくデータベースによって行われます。

于 2012-06-20T18:15:19.253 に答える