3

DBからラージオブジェクトグラフをロードします。クエリには多くのインクルードがあり、Where()はContains()を使用して最終結果をフィルタリングします。約1000のエントリを含むコレクションに対してContainsが呼び出されます。

プロファイラーは、人間が読めない巨大なSQLを示しています。contains()のため、クエリをプリコンパイルできません。

そのようなクエリを最適化する方法はありますか?

アップデート

public List<Vulner> GetVulnersBySecurityObjectIds(int[] softwareIds, int[] productIds)
        {
            var sw = new Stopwatch();

            var query = from vulner in _businessModel.DataModel.VulnerSet
                        join vt in _businessModel.DataModel.ObjectVulnerTieSet.Where(ovt => softwareIds.Contains(ovt.SecurityObjectId))
                        on vulner.Id equals vt.VulnerId
                        select vulner;

            var result = ((ObjectQuery<Vulner>)query.OrderBy(v => v.Id).Distinct())
                .Include("Descriptions")
                .Include("Data")
                .Include("VulnerStatuses")
                .Include("GlobalIdentifiers")
                .Include("ObjectVulnerTies")
                .Include("Object.ProductObjectTies.Product")
                .Include("VulnerComment");

            //Если переданы конкретные продукты, добавляем фильтрацию
            if (productIds.HasValues())
                result = (ObjectQuery<Vulner>)result.Where(v => v.Object.ProductObjectTies.Any(p => productIds.Contains(p.ProductId)));

            sw.Start();
            var str = result.ToTraceString();
            sw.Stop();
            Debug.WriteLine("Сборка запроса заняла {0} секунд.", sw.Elapsed.TotalSeconds);
            sw.Restart();
            var list = result.ToList();
            sw.Stop();
            Debug.WriteLine("Получение уязвимостей заняло {0} секунд.", sw.Elapsed.TotalSeconds);

            return list;
        }
4

1 に答える 1

2

dbラウンドトリップが多いにもかかわらず、クエリを分割してパフォーマンスが向上することはほぼ確実です。インクルードの数を制限することを常にお勧めします。インクルードは、クエリのサイズと複雑さを爆破するだけでなく(お気づきのとおり)、結果セットの長さと幅の両方を爆破するからです。さらに、それらはしばしば外部結合に変換されます。

それとは別に、Containsあなたのやり方を使っても大丈夫です。

申し訳ありませんが、データモデルと関連するテーブルのサイズを知らなければ、より具体的にすることは困難です。

于 2012-11-02T20:56:25.480 に答える