linq contains 效率的问题

MisterDotNet 2015-07-16 10:08:54
问:有50个班级,50个年级下总共有50000个学生,已知20个班级的班级id集合—list_class,想通过linq获取50000个学生中班级在集合list_class中的学生,使用了两段代码,linq中的contains()方法 和 字符串的indexOf()方法,其中contains()的效率非常低,请问是为什么? 代码如下:

List<int> list_class=new List<int>();//班级
list_int.add(1);
list_int.add(7);
list_int.add(9);
...
list_int.add(48);

public class Student
{
public int id{set;get;}//编号
public int class{set;get;}//班级
public string name{set;get;}//姓名
...
}
List<Student> list_student=new List<Student>();//学生
list_student.add(new Student{id=1,class=1,name="name1"});
list_student.add(new Student{id=2,class=1,name="name2"});
list_student.add(new Student{id=3,class=2,name="name3"});
...
list_student.add(new Student{id=50000,class=48,name="name50000"});

方法1:使用linq效率非常低,程序假死
var list=from s in list_student
where (from c in list_class select c.id).contains(s.class)
select s;

方法2:循环list_class,把已知班级id组合成字符串str_class,通过indexOf()判断学生所在班级是否存在str_class中
string str_class=",";
foreach(int i in list_class)
str_class+=i+",";
var list=from s in list_student
where str_class.indexOf(","+s.class+",")>=0
select s;

...全文
779 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
EIT王子 2019-04-29
  • 打赏
  • 举报
回复
引用 12 楼 MisterDotNet 的回复:
var list_serAll = from o in list_serviceAll
from l in list_ser_id
where l.id == o.id
select o;

这段代码是返回 list_serviceAll中课程id存在list_ser_id中的数据


你这有两个from了
MisterDotNet 2015-07-17
  • 打赏
  • 举报
回复
var list_serAll = from o in list_serviceAll
                         from l in list_ser_id
                         where l.id == o.id
                         select o;
这段代码是返回 list_serviceAll中课程id存在list_ser_id中的数据
MisterDotNet 2015-07-17
  • 打赏
  • 举报
回复
引用 8 楼 starfd 的回复:
var list=from s in list_student
from c in list_class
where c.id == s.classid
select s;

为什么你要写成那样?而不是这样?




var list_serAll = from o in list_serviceAll
from l in list_ser_id
where l.id == o.id
select o;


上面是我的代码,用这段代码执行的时候程序也是假死,请问为什么?
ajianchina 2015-07-17
  • 打赏
  • 举报
回复
引用 9 楼 MisterDotNet 的回复:
老师,我的错,我只是举得一个例子,list_class 存储班级对象,对象有个属性id表示班级id
不要称什么老师了,我懂的不多,我刚刚帮你进行过测试 用用了关键字class,我改名classs了 按这样的查询,得出list结果是8毫秒 var list = (from s in list_student where list_class.Contains(s.classs) select s).ToList(); 第二条语句查询得出list结果是320毫秒 string str_class = ","; foreach (int i in list_class) { str_class += i + ","; } var lists = (from s in list_student where str_class.IndexOf("," + s.classs + ",") >= 0 select s).ToList();
MisterDotNet 2015-07-17
  • 打赏
  • 举报
回复
引用 7 楼 ajianchina 的回复:
你的list_class是List<int> 怎么会select出来id呢,其实你from c in list_class select c这段也本该是多余的,这段查询可以省掉,可以这样子 var list=from s in list_student where list_class.Contains(s.class) select s; 如果 list.ToList()的话得出结果应该可以控制在10毫秒左右,就你的50000条记录而言。
老师,我的错,我只是举得一个例子,list_class 存储班级对象,对象有个属性id表示班级id
  • 打赏
  • 举报
回复
var list=from s in list_student
                     from c in list_class
              where c.id == s.classid
              select s;
为什么你要写成那样?而不是这样?
ajianchina 2015-07-17
  • 打赏
  • 举报
回复
你的list_class是List<int> 怎么会select出来id呢,其实你from c in list_class select c这段也本该是多余的,这段查询可以省掉,可以这样子 var list=from s in list_student where list_class.Contains(s.class) select s; 如果 list.ToList()的话得出结果应该可以控制在10毫秒左右,就你的50000条记录而言。
MisterDotNet 2015-07-17
  • 打赏
  • 举报
回复
引用 5 楼 ajianchina 的回复:
上面又发失败了 var list=from s in list_student where (from c in list_class select c.id).contains(s.class) select s;
老师,student对象里面的class属性是班级的id,不是班级对象啊
ajianchina 2015-07-16
  • 打赏
  • 举报
回复
上面又发失败了 var list=from s in list_student where (from c in list_class select c.id).contains(s.class) select s;
ajianchina 2015-07-16
  • 打赏
  • 举报
回复
既然要比较Contains跟IndexOf,就拿他原来的方法测 var list=from s in list_student where (from c in list_class select c<span style="color: #FF0000;">.id</span>).contains(s.class) select s; 这里的id去掉
ajianchina 2015-07-16
  • 打赏
  • 举报
回复
回过头居然看到你第一条语句居然存在一个错误

var list=from s in list_student
              where (from c in list_class select c.id).contains(s.class)
              select s;
这儿有id吗?你改过来,50000条数据肯定可以在100毫秒以内算完,应该可能只有你第二条语句的1/3时间。
showjim 2015-07-16
  • 打赏
  • 举报
回复
HashSet<int>或者BitArray
ajianchina 2015-07-16
  • 打赏
  • 举报
回复
你这样怎么好比较,完全是两种不同逻辑的查询 拿第二段代码,要比就这样比: where str_class.indexOf(","+s.class+",")>=0 跟 where str_class.Contains(","+s.class+",") 这样采用可比性 我曾经做过测试Contains效率要高于indexOf
Restful.Data是一套通用的轻量级数据持久层组件,除封装了ADO.NET基本的数据库操作以外,也提供了一些orm相关的API,用户可以方便的定义实体类,并使用这些API对数据进行增删改查等操作。 Restful.Data借鉴了业界如nhibernate、entity framework等知名的数据持久层组件,但从一开始设计的初衷就是为了让用户能快速的学习和使用,并写出更加简洁优雅的代码,所以摒弃了一些复杂的设计和功能,用户可以使用变通的方式或方法使用Restful.Data组件实现其目的。 Restful.Data充分考虑了实体框架的执行效率问题,进行了反复的推敲和论证,尽可能的采用高效的设计方案来提高性能。谁需要Restful.Data?  敢于冒险、追求完美、勇于挑战并极具责任感的程序设计人员。Restful.Data提供哪些功能?基本的ADO.NET操作:    BeginTransaction    ExecuteScalar    ExecuteDataReader    ExecuteDataTable    ExecuteDataSet    ExecutePageQuery    ExecuteStoredProcedureORM相关操作:    Insert    Updete    Delete    Find如何使用Restful.Data?  使用前的准备:  下载Restful.dll、Restful.Data、Restful.Data.MySql、Remotion.Linq.dll、MySql.Data.dll,或者直接下载源代码进行编译并获取这5个dll,并在项目中引用这些dll。在 Web.config 或 App.config 中配置连接字符串,如下:注册提供程序工厂:  SessionFactories.Register();  提供程序工厂在一个Application中仅需注册一次。如何进行基本的数据库操作:using( ISession session = SessionFactory.CreateDefaultSession() ){     string sql = "select * from Person";     DataTable dt = session.ExecuteDataTable( sql ); }CreateDefaultSession默认情况下根据配置文件中连接字符串节点的第一项创建数据库连接,你可以调用CreateSession进行指定,或者你也可以使用 SessionFactory.Default = "MySql2"指定默认连接。未防止 SQL 注入,你也使用呆参数方法:using( ISession session = SessionFactory.CreateDefaultSession() )   {     string sql = "select * from Person where Id = @Id;"; IDictionary parameters = new Dictionary(); parameters.Add( "@Id", 5 ); DataTable dt = session.ExecuteDataTable( sql, parameters ); }与此类似的还有ExecuteScalar、ExecuteDataReader、ExecuteDataTable、ExecuteDataSet等方法。如何进行分页查询:using( ISession session = SessionFactory.CreateDefaultSession() )   {       string sql = "select * from User where CreateTime < @CreateTime";   IDictionary parameters = new Dictionary();   parameters.Add( "@CreateTime", DateTime.Now );   // 查询第2页,每页10条,并根据 CreateTime 字段降序排列   PageQueryResult result = session.ExecutePageQuery( sql01, 2, 10, "CreateTime DESC", parameters ); }如何进行数据新增:using( ISession session = SessionFactory.CreateDefaultSession() )   {     var person = new Person(); // person.Id = 1; 若Id字段为自增类型,无需指定。 person.Name = "test01"; person.CreateTime = DateTime.Now; person.IsActive = true; int i = session.Insert( person ); }如何进行数据更新:using( ISession session = SessionFactory.CreateDefaultSession() )   {     var person = new Person(); person.Id = 1;  person.Name = "test01"; person.CreateTime = DateTime.Now; person.IsActive = true; // 在调用此方法时,务必指定实例的主键值。 int i = session.Update( person ); }或者你也可以批量更新:using( ISession session = SessionFactory.CreateDefaultSession() )   {     var person = new Person(); // person.Id = 1;  person.Name = "test01"; person.CreateTime = DateTime.Now; person.IsActive = true; // 在调用此方法时,不需要指定主键值,且不会更新主键字段 session.Update().Set( person ).Where( s => s.IsActive == false ).Execute(); }如何进行数据删除:using( ISession session = SessionFactory.CreateDefaultSession() )   {     var person = new Person() { Id = 1 }; // 在调用此方法时,需要指定主键值 session.Delete( person ); }或者你也可以批量删除:using( ISession session = SessionFactory.CreateDefaultSession() )   {     // 在调用此方法时,不需要指定主键值     session.Delete().Where( s => s.IsActive == false ).Execute();   }如何进行单表查询:using( ISession session = SessionFactory.CreateDefaultSession() )   {     var queryable = session.Find()         .Where( s => s.Name.Contains("a") )         .Where( s => s.CreateTime < DateTime.Now )         .OrderBy( s => s.CreateTime )         .Skip(5)         .Take(10); var list = queryable.ToList(); var count = queryable.Count(); var first = queryable.FirstOrDefault(); var queryable1 = from s in session.Find()             where s => s.Name.Contains("a")             orderby s.CreateTime descending             select new { Id = s.Id, Name = s.Name }; // ... }目前只支持对单表的LINQ查询,且为了降低复杂度,后期也并不打算支持多表查询,对函数的支持也有限,仅支持string类型的 StartsWith、EndsWith、Contains、Equals、IsNullOrEmpty等方法,对于其他方法后期将会继续完善。如果你需要实现一个复杂的查询并将其转换成对象,你也可以这样:using( ISession session = SessionFactory.CreateDefaultSession() )   {     string sql = "..."; T @object = session.Find( sql ); }如何支持事务处理:using( ISession session = SessionFactory.CreateDefaultSession() )   {     using( DbTransaction transaction = session.BeginTransaction() )     {         // ...         // ...     transaction.Commit(); } }SessionHelper的使用:SessionHelper对session对象的方法进行了静态封装,如果你只是需要执行单条语句,并马上关闭连接,你可以使用 SessionHelper 类中提供的一些辅助方法。5、如何定义实体类[Serializable] public class Person : EntityObject  // 需继承与 EntityObject 类 {     private int m_Id;     private string m_Name;     private int? m_Age;     private decimal? m_Money;     private DateTime m_CreateTime;     private bool m_IsActive;     [PrimaryKey, AutoIncrease]  // 如果是自增字段,标记为 AutoIncrease;如果是主键标记为 PrimaryKey     public int Id     {         get { return this.m_Id; }         set { this.m_Id = value; this.OnPropertyChanged( "Id", value ); }     }     public string Name     {         get { return this.m_Name; }         set { this.m_Name = value; this.OnPropertyChanged( "Name", value ); }     }     public int? Age     {         get { return this.m_Age; }         set { this.m_Age = value; this.OnPropertyChanged( "Age", value ); }     }     public decimal? Money     {         get { return this.m_Money; }         set { this.m_Money = value; this.OnPropertyChanged( "Money", value ); }     }     public DateTime CreateTime     {         get { return this.m_CreateTime; }         set { this.m_CreateTime = value; this.OnPropertyChanged( "CreateTime", value ); }     }     public bool IsActive     {         get { return this.m_IsActive; }         set { this.m_IsActive = value; this.OnPropertyChanged( "IsActive", value ); }     } }6、总结因作者时间关系,组件目前并非十分完善,测试工作也只简单的进行了一部分,但您可以完全放心的应用于商业项目中,如遇到问题,作者将尽可能的解决。 标签:Restful

62,073

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧