C# linq和INTERSECT/EXCEPT在小型集合中的性能较低
你好吗 我知道有很多关于它的问题和答案,但我的情况非常特殊,因为我没有大数组可以相交。我正在实现一个搜索方法,该方法接收一个搜索对象,并使用linq搜索数据库(我首先使用EF6和代码)C# linq和INTERSECT/EXCEPT在小型集合中的性能较低,c#,sql-server,performance,entity-framework,linq,C#,Sql Server,Performance,Entity Framework,Linq,你好吗 我知道有很多关于它的问题和答案,但我的情况非常特殊,因为我没有大数组可以相交。我正在实现一个搜索方法,该方法接收一个搜索对象,并使用linq搜索数据库(我首先使用EF6和代码) 因此,我在DB中有以下具有这些列的实体: -用户:userId(int),name(string) -UserFeatures:userId(int)、featuresId(short) -特性:featuresId(短)、描述(字符串) 我的搜索对象如下所示: int numberOfFeatures = u
- 因此,我在DB中有以下具有这些列的实体: -用户:userId(int),name(string) -UserFeatures:userId(int)、featuresId(short) -特性:featuresId(短)、描述(字符串)
- 我的搜索对象如下所示:
{ “姓名”:“弗里德里希·威廉”, “特征”:[1,2,3,4] }int numberOfFeatures = userToSearch.features.Count(); var userIds = from u in context.Users from uf in u.UserFeatures where userToSearch.features.Contains(uf.featuresId) group u by u.userId into g where g.Count() == numberOfFeatures select u.Key;
- 我的linq查询是这样的(其目的是获取与登录用户正在寻找的功能相匹配的所有用户) context.User.Where(u=> userToSearch.features.Exception(u.UserFeatures.Select(uf=> .Any()==false.toListSync()
你知道我该如何改进吗?在查询中,我还有另一个条件。如果我删除带有这些功能的查询,查询速度会快得多(大约需要4秒钟才能运行。我还实现了分页—Take、skip等)。该查询和类似的查询对我来说效果很好。至于查询表单,除非您的模型中有链接实体,否则下面两个是唯一想到的。无论如何,看看这个程序,看看它是否对你有不同的表现
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;
namespace ConsoleApp8
{
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
public virtual ICollection<Feature> Feaures { get; } = new HashSet<Feature>();
}
public class Feature
{
public int FeatureId { get; set; }
public string Description { get; set; }
public virtual ICollection<User> Users { get; } = new HashSet<User>();
}
class Db : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Feature> Features { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
class Program
{
static void Main(string[] args)
{
if (true)
{
Database.SetInitializer(new DropCreateDatabaseAlways<Db>());
using (var db = new Db())
{
var features = Enumerable.Range(1, 20).Select(i => new Feature() { Description = $"Feature{i}" }).ToList();
var users = Enumerable.Range(1, 30000).Select(i => new User() { Name = $"User{i}" }).ToList();
var rand = new Random();
foreach (var u in users)
{
var featureCount = rand.Next(4, 5);
for (int i = 0; i < featureCount; i++)
{
u.Feaures.Add(features[rand.Next(0, features.Count - 1)]);
}
}
db.Users.AddRange(users);
db.Features.AddRange(features);
db.SaveChanges();
}
}
List<int> requestedFeatureIds;
using (var db = new Db())
{
db.Database.Log = m => Console.WriteLine(m);
var user = db.Users.Where(u => u.Feaures.Count() == 4).AsEnumerable().Last() ;
requestedFeatureIds = user.Feaures.Select(f => f.FeatureId).ToList();
}
using (var db = new Db())
{
db.Database.Log = m => Console.WriteLine(m);
//context.User.Where(u => userToSearch.features.Except(u.UserFeatures.Select(uf => uf.featuresId))).Any()==false).toListAsync();
var q = db.Users.Where(u => requestedFeatureIds.Except(u.Feaures.Select(uf => uf.FeatureId)).Any() == false);
var results = q.ToList();
var q2 = from u in db.Users
where requestedFeatureIds.Intersect(u.Feaures.Select(f => f.FeatureId)).Count() == requestedFeatureIds.Count
select u;
var results2 = q2.ToList();
}
Console.WriteLine("Hit any key to exit");
Console.ReadKey();
}
}
}
这个问题,还有一个类似的问题,对我来说很好。至于查询表单,除非您的模型中有链接实体,否则下面两个是唯一想到的。无论如何,看看这个程序,看看它是否对你有不同的表现
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;
namespace ConsoleApp8
{
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
public virtual ICollection<Feature> Feaures { get; } = new HashSet<Feature>();
}
public class Feature
{
public int FeatureId { get; set; }
public string Description { get; set; }
public virtual ICollection<User> Users { get; } = new HashSet<User>();
}
class Db : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Feature> Features { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
class Program
{
static void Main(string[] args)
{
if (true)
{
Database.SetInitializer(new DropCreateDatabaseAlways<Db>());
using (var db = new Db())
{
var features = Enumerable.Range(1, 20).Select(i => new Feature() { Description = $"Feature{i}" }).ToList();
var users = Enumerable.Range(1, 30000).Select(i => new User() { Name = $"User{i}" }).ToList();
var rand = new Random();
foreach (var u in users)
{
var featureCount = rand.Next(4, 5);
for (int i = 0; i < featureCount; i++)
{
u.Feaures.Add(features[rand.Next(0, features.Count - 1)]);
}
}
db.Users.AddRange(users);
db.Features.AddRange(features);
db.SaveChanges();
}
}
List<int> requestedFeatureIds;
using (var db = new Db())
{
db.Database.Log = m => Console.WriteLine(m);
var user = db.Users.Where(u => u.Feaures.Count() == 4).AsEnumerable().Last() ;
requestedFeatureIds = user.Feaures.Select(f => f.FeatureId).ToList();
}
using (var db = new Db())
{
db.Database.Log = m => Console.WriteLine(m);
//context.User.Where(u => userToSearch.features.Except(u.UserFeatures.Select(uf => uf.featuresId))).Any()==false).toListAsync();
var q = db.Users.Where(u => requestedFeatureIds.Except(u.Feaures.Select(uf => uf.FeatureId)).Any() == false);
var results = q.ToList();
var q2 = from u in db.Users
where requestedFeatureIds.Intersect(u.Feaures.Select(f => f.FeatureId)).Count() == requestedFeatureIds.Count
select u;
var results2 = q2.ToList();
}
Console.WriteLine("Hit any key to exit");
Console.ReadKey();
}
}
}
我认为像这样使用
join
和groupby
会更快:
int numberOfFeatures = userToSearch.features.Count();
var userIds = from u in context.Users
from uf in u.UserFeatures
where userToSearch.features.Contains(uf.featuresId)
group u by u.userId into g
where g.Count() == numberOfFeatures
select u.Key;
或者,如果需要用户对象
var users = ...
select u.FirstOrDefault();
我认为像这样使用
join
和groupby
会更快:
int numberOfFeatures = userToSearch.features.Count();
var userIds = from u in context.Users
from uf in u.UserFeatures
where userToSearch.features.Contains(uf.featuresId)
group u by u.userId into g
where g.Count() == numberOfFeatures
select u.Key;
或者,如果需要用户对象
var users = ...
select u.FirstOrDefault();
你能在SQL Server中显示该查询的实际执行计划吗?你能在SQL Server中显示该查询的实际执行计划吗?它工作得很好!这实际上比我预期的性能提高了很多:运行不到一秒钟!非常感谢,阿杜奇。太好了!我非常关心我的查询的性能。它非常有效!这实际上比我预期的性能提高了很多:运行不到一秒钟!非常感谢,阿杜奇。太好了!我非常关心我的查询的性能。