2017-05-06 158 views
0

我有大約1 500 000個實體的Mysql數據庫。當我嘗試使用EF核心1.1以下語句來執行和Mysql.Data.EntityFrameworkCore 7.0.7-M61大約需要40分鐘完成:使用本地的mysql-CLI和下面的語句EF Core Mysql性能

var results = db.Posts 
    .Include(u => u.User) 
    .GroupBy(g => g.User) 
    .Select(g => new { Nick = g.Key.Name, Count = g.Count() }) 
    .OrderByDescending(e => e.Count) 
    .ToList(); 

。另一方面,需要大約16秒完成。

SELECT user.Name, count(*) c 
FROM post 
JOIN user ON post.UserId = user.Id 
GROUP BY user.Name 
ORDER BY c DESC 

我做錯了什麼,或者EF核心性能的MySql是如此可怕?

+0

是user.name索引? –

+0

我不這麼認爲 – Marduk

+0

嘗試啓用記錄執行的實際sql查詢。我懷疑實際運行的內容離你寫的查詢很遠。 執行EF生成的每個查詢並在mysql-cli中運行它們並計時。你會發現瓶頸 – ironstone13

回答

1

您的查詢正在做不同的事情。在LINQ到實體查詢的一些問題:

  1. 你叫Include(...)將急切地加載User爲每個項目在db.Posts
  2. 您可以撥打Count()查看每組中的每條記錄。這可以重寫爲每組記錄一次記錄。
  3. 最大的問題是您只使用User對象的Name屬性。你可以選擇這個字段並找到相同的結果。在EF中選擇,分組和返回150萬個字符串應該是一個快速操作。

原文:

var results = 
    db.Posts 
     .Include(u => u.User) 
     .GroupBy(g => g.User) 
     .Select(g => new { Nick = g.Key.Name, Count = g.Count() }) 
     .OrderByDescending(e => e.Count) 
     .ToList(); 

建議:

var results = 
    db.Posts 
     .Select(x => x.User.Name) 
     .GroupBy(x => x) 
     .Select(x => new { Name = x.Key, Count = x.Count() }) 
     .OrderByDescending(x => x.Count) 
     .ToList(); 

如果EF核心仍然對類型分組,它允許報表的限制,你可以在第一次調用後ToListSelect(...)聲明。

+0

那麼你的例子已經減少了查詢時間到144秒,但也花了2GB的內存。儘管如此,這比mysql-cli更糟糕。無論如何,這是一些進展。 – Marduk

+1

我每天都在使用EF,而且我很少運行查詢,這些查詢在原始SQL中的運行速度比EF中的速度快了幾分之一秒(一旦完全指定和審查完畢)。如果您的項目團隊允許,我建議您將EF Core交換爲全EF,直到EF Core團隊宣佈它已準備好企業生產。缺乏數據庫方面的分組(這個時候)讓我們團隊的項目鎖定在EF 6中,儘管EF Core有着閃亮的吸引力。 –