1

次のデータベースがあります。

ここに画像の説明を入力

  1. テーブル メッセージ:

    • 送信されたメッセージを保存する責任は、さまざまな電子メール アドレスに送信されます。
  2. テーブルの電子メール:

    • メールアドレス (主キー = Email) の保存のみを担当します (toEmail はテーブル email と関係があります) (Sotres Foo@gmail.com、Foo2@gmail.com など...)
  3. テーブルの連絡先:

    • ユーザーの連絡先を保存するために使用されます。(マーク、ジョン、トムなどを保存します...)
  4. 表 ContactEmails

    • 連絡先は複数の電子メール アドレスを持っている可能性があるため、このテーブルが必要です。(テーブル Emails で見つかった ID を格納します)

とにかくここに質問があり ます。特定の日付に送信されたすべてのメッセージを選択するクエリを作成したいと考えています。連絡先名が存在する場合は、クエリに含めたいと思います。次のクエリを作成しましたが、低速です。

Func<string, Contact> tryGetContact = (email)=>{
    var contactEmail = db.ContactEmails.FirstOrDefault(x=>x.IdEmail==email);
    if(contactEmail==null)
       return null;
    return contactEmail.Contact; // navigational property created by entity framework.
};

var query = from msg in db.Messages
            join email in db.Emails on msg.ToEmail equals email.Email
            where msg.Date < "some date" && msg.Date > "some other date" 
            select new
            {
                MessageSubject = msg.Subject,
                ToEmail = email.Email,
                Contact = tryGetContact(email.Email) // this slows down the query!
            };

クエリを高速に実行するには、すべての連絡先を辞書に保存し、このクエリを 2 つのクエリに分ける必要がありますか?

すべての連絡先を辞書に保存すると、作業がはるかに効率的になります。しかし、ほとんどの連絡先を必要としないデータベースからすべての連絡先を取得すると、リソースを無駄にしているように感じます。

4

1 に答える 1

3

Linq クエリによって生成された実際の SQL を確認できれば、何がクエリを遅くしているのかを簡単に特定できます。tryGetContactただし、クエリの主要部分と同じコンテキストを共有していない Func と関係がある可能性があると思います。

tryGetContact(email.Email)したがって、私が正しければ、次の行のために、新しい完全なクエリを呼び出すたびに実行されます。

var contactEmail = db.ContactEmails.FirstOrDefault(x=>x.IdEmail==email);

その場合、db.ContactEmailsこれは SQL クエリの結合の一部ではないため、毎回再実行されます。

したがって、私が行うことは、Linq (および後続の SQL) クエリjoinに含めるために別のものを追加することです。ContactEmailsこれは次のようになります。

var query = from msg in db.Messages
            join email in db.Emails on msg.ToEmail equals email.Email
            join contactEmail in db.ContactEmails on contactEmail.IdEmail equals email.Email
            where msg.Date < "some date" && msg.Date > "some other date" 
            select new
            {
                MessageSubject = msg.Subject,
                ToEmail = email.Email,
                Contact = (contactEmail==null) ? contactEmail.Contact : null,
            };

これが機能しない場合はdb.ContactEmails、すべてのtryGetContact呼び出しに対して 1 回だけ実行し、結果を Collection (またはパフォーマンスを向上させるために HashSet) に格納することをお勧めします。

于 2016-10-25T01:23:20.477 に答える