Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# linq和INTERSECT/EXCEPT在小型集合中的性能较低_C#_Sql Server_Performance_Entity Framework_Linq - Fatal编程技术网

C# linq和INTERSECT/EXCEPT在小型集合中的性能较低

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

你好吗

我知道有很多关于它的问题和答案,但我的情况非常特殊,因为我没有大数组可以相交。我正在实现一个搜索方法,该方法接收一个搜索对象,并使用linq搜索数据库(我首先使用EF6和代码)

  • 因此,我在DB中有以下具有这些列的实体:

    -用户:userId(int),name(string)

    -UserFeatures:userId(int)、featuresId(short)

    -特性:featuresId(短)、描述(字符串)

  • 我的搜索对象如下所示:

    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;
    
    { “姓名”:“弗里德里希·威廉”, “特征”:[1,2,3,4] }

  • 我的linq查询是这样的(其目的是获取与登录用户正在寻找的功能相匹配的所有用户)

    context.User.Where(u=> userToSearch.features.Exception(u.UserFeatures.Select(uf=> .Any()==false.toListSync()

这工作正常,但大约需要30秒。我在数据库中有30000个用户,但每个用户都有大约4个和5个功能

我已经尝试使用hashset,但是由于功能集合不大,所以没有什么区别。问题是我可能有3万个用户,每个用户有5个功能。这意味着大约150k次迭代


你知道我该如何改进吗?在查询中,我还有另一个条件。如果我删除带有这些功能的查询,查询速度会快得多(大约需要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中显示该查询的实际执行计划吗?它工作得很好!这实际上比我预期的性能提高了很多:运行不到一秒钟!非常感谢,阿杜奇。太好了!我非常关心我的查询的性能。它非常有效!这实际上比我预期的性能提高了很多:运行不到一秒钟!非常感谢,阿杜奇。太好了!我非常关心我的查询的性能。