Pavel Voronin
Pavel Voronin

Reputation: 13983

What are the ways to optimize Entity Framework queries with Contains()?

Wee load large object graph from DB. The query has many Includes and Where()uses Contains() to filter the final result. Contains is called for the collection containing about thousand entries.

The profiler shows monstrous human-unreadable SQL. The query cannot be precompiled because of Contains().

Is there any ways for optimization of such queries?

Update

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;
        }

Upvotes: 3

Views: 3029

Answers (1)

Gert Arnold
Gert Arnold

Reputation: 109109

It's almost certain that splitting the query in pieces performs better, in spite of more db round trips. It is always advised to limit the number of includes, because they not only blow up the size and complexity of the query (as you noticed) but also blow up the result set both in length and in width. Moreover, they often get translated into outer joins.

Apart from that, using Contains the way you do is OK.

Sorry, it is hard to be more specific without knowing your data model and the size of the tables involved.

Upvotes: 2

Related Questions