简体   繁体   中英

EF Core query optimization: can I use Contains on List<string>?

Using EF Core + .NET 5.0 preview + Postgres.

I am trying to find all questions with some tag.

I have this Question class:

public class Question : IEntity
{
    /// <summary>
    /// auto index
    /// </summary>
    public int Id { get; set; }
    public List<string> tags { get; set; }
   //other properties       
}

So, I expected that this code would do what I want:

 var questions = _context.Questions
                         .Where(question => question.tags.Contains(tag) == true)
                         .AsQueryable();
return questions.AsAsyncEnumerable();

But nothing happens. I log the EF Core SQL query, it looks like this:

 [22:15:30 INF] Entity Framework Core 3.1.9 initialized 'ApplicationContext' using provider 
'Npgsql.EntityFrameworkCore.PostgreSQL' with options: None
 [22:15:30 INF] Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
 SELECT q."Id", q."OwnerId", q.answer_count, q.bounty_amount, q.bounty_closes_date, q.closed_date, 
 q.closed_reason, q.content_license, q.creation_date, q.is_answered, q.last_activity_date, 
 q.last_edit_date, q.link, q.question_id, q.score, q.tags, q.title, q.view_count
 FROM "Questions" AS q
 WHERE (TRUE = FALSE) = TRUE

This query confused me.

I rewrote the code in a simpler way:

  var qResult = new List<Question>();
  var quests = _context.Questions.AsQueryable();

  foreach (var q in quests)
  {
      if (q.tags.Contains(tag))
          qResult.Add(q);
  }

This code works, but I'm afraid that it is not optimized query and when I will have more questions - I will lose memory.

So, how to do create an optimized query?

PS full code : github repo

And this is my appsettings.Development.json :

{
 "Logging": {
"LogLevel": {
  "Default": "Information",
  "Microsoft": "Warning",
  "Microsoft.Hosting.Lifetime": "Information"
 }
 },
"AllowedHosts": "*",
"ConnectionStrings": {
  "Questions": "Host=localhost;Port=5432;Database=questionsdb;Username=postgres;Password=password"
},
"Tags": [
  "ef core",
  "c#",
  "asp.net core",
  "asp.net core webapi"
  ]
 }

PS: another variant:

    var questions = _context.Questions.Where(question => question.tags.Contains(tag)).AsQueryable();
        return questions.ToList();


  [21:44:29 INF] Executed DbCommand (1ms) [Parameters=[], CommandType='Text', 
  CommandTimeout='30']
  SELECT q."Id", q."OwnerId", q.answer_count, q.bounty_amount, 
  q.bounty_closes_date, q.closed_date, q.closed_reason, q.content_license, 
  q.creation_date, q.is_answered, q.last_activity_date, q.last_edit_date, 
  q.link, q.question_id, q.score, q.tags, q.title, q.view_count
  FROM "Questions" AS q
  WHERE TRUE = FALSE

Just try to change your query to

        return   _context.Questions
                         .Where(q => q.tags.Contains(tag))
                         .ToArrayAsync();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM