使用EF进行非常简单的查询时遇到问题。 以下查询需要30多个秒才能运行,并引发超时错误:
var results = _Context.Entity
.Where(x => list1.Contains(x.Id))
.Where(x => !list2.Contains(x.Id))
.ToList();
下面的一个运行时间为1/4秒:
var results = _Context.Entity
.Where(x => list1.Contains(x.Id))
.ToList();
results = results
.Where(x => !list2.Contains(x.Id))
.ToList();
数据库中的集合大约有60k行,而我的两个列表都是大约5k int。 这是缓存问题吗?我的应用程序中有很多类似的查询,都可以顺利运行。我该怎么做才能改善它?
答案 0 :(得分:1)
在情况1中,您将构建一个更复杂的查询,如下所示:
SELECT * FROM Entities WHERE Id in (...) AND Id NOT IN (...)
但是在第2种情况下,您可以进行简单的查询
SELECT * FROM Entities WHERE Id in (...)
,然后用C#过滤出结果。如果您的list2
实际上是HashSet
,它将更快地工作。但是,您使SQL Server返回多余的行,这些行将被过滤掉。
我想,第一个的工作速度较慢,因为它不利用索引,但是我不确定,我可能是错的。
更重要的是,您真正想要的是获取ID在list1
中而不是list2
中的所有项目。在这种情况下,您不需要让SQL Server处理它-只需用代码过滤掉它,然后仅传递您需要的ID:
var listToSearch = list1.Except(list2).ToArray();
var results = _Context.Entity.Where(x => listToSearch.Contains(x.Id)).ToList();
答案 1 :(得分:0)
您的第一个是检查将SQL运行到where条件。
SELECT * FROM Entity WHERE id IN () AND id NOT IN ()
第二个仅在查询中运行检查的地方:
SELECT * FROM Entity WHERE id IN ()
检查第二个语句的第二个语句的位置:
results = results
.Where(x => !list2.Contains(x.Id))
.ToList();
实际上是在Web服务器上运行,而不是使用sql。键入.ToList()后,立即执行SQL Linq。
无论如何,第一个要慢于第二个的原因是因为它将Entity中的每个元素都与两个列表进行了比较。第二步在哪里检查id是否在列表中,然后返回满足该条件的项目列表。然后,程序将使用返回的过滤列表(很可能少于实体表中某些表的总行数)进行检查,以确保该列表中不包含ID为列表2的行。
所以第二个只是比较少了。