c# - 在本地列表和表之间使用 LINQ to SQL Contains() 的最佳方式
问题描述
在本地列表和数据库中的表中查找常用项目的更好方法是什么?
物品或物品2?
var clientId = 2;
// members is a local list, but not anonymous, like this
var members = new[] {
new { MemberId = "1", ... },
new { MemberId = "2", ... },
new { MemberId = "3", ... },
new { MemberId = "4", ... },
new { MemberId = "5", ... },// so on...
};
var items = db.MemberTable.Where(x => members.Select(s => s.MemberId).Contains(x.MemberId) && x.StoreId == storeId).Select(i => i.MemberId).ToList();
var items2 = members.Where(x => db.MemberTable.Where(c => c.StoreId== storeId).Select(s => s.MemberId).Contains(x.MemberId)).Select(i => i.MemberId).ToList();
解决方案
LINQ to SQL 或 LINQ to EF 并不神奇。他们不能做任何不能用 SQL 表达的事情。他们也不会在生成 SQL 语句之前将错误的查询重写为更好的形式。
不幸的是,当 L2S(以及一些早期版本的 EF Core)无法生成正确的 SQL 语句时,它们会尝试加载行并在客户端上处理它们,从而导致查询效率非常低。
根据 ID 列表查询项目的方式是:
select ID
from Members
Where ID in (1,2,6,7,9)
LINQ to EF/SQL只能在 Enumerable.Contains 用于 ID 列表时生成IN
子句,例如:
var ids=new[]{1,2,6,7,9};
var actualIDs = db.MemberTable.Where(x=>ids.Contains(x.ID));
第一个查询以详细的方式执行此操作。本质上和写一样
var ids=members.Select(s => s.MemberId);
var items = db.MemberTable.Where(x => ids.Contains(x.MemberId) && x.StoreId == storeId)
.Select(i => i.MemberId)
.ToList();
这应该生成这个查询:
SELECT MemberID
From Members
Where StoreId=12354 and MemberID in (1,2,5,8,9...)
这是一个快速查询,特别是如果MemberID
和StoreID
被索引。
如果使用 LINQ to SQL,则可能需要向本地查询添加ToArray()
或。ToList()
L2S 至少可以说是非常挑剔的,而且从来都只是一个技术演示。无论如何,本地性能是相同的,在这两种情况下,都需要读取所有 ID 来构造 IN 子句:
var ids=members.Select(s => s.MemberId).ToArray();
第二个查询可能很 慢 - 它的作用并不明显,因为所有内容都写在一行中,并且无法查看哪一部分是数据库查询,哪一部分是本地查询。重写它:
var items2 = members.Where(x =>
db.MemberTable
.Where(c => c.StoreId== storeId)
.Select(s => s.MemberId)
.Contains(x.MemberId))
.Select(i => i.MemberId)
.ToList();
表明这对成员列表中的每个项目执行一次此数据库查询:
db.MemberTable
.Where(c => c.StoreId== storeId)
.Select(s => s.MemberId)
必须跟踪 SQL 语句,但我怀疑这将一遍又一遍地执行以下查询:
select MemberID
from Members
where StoreID=12345
将其重写为:
var dbIDs=b.MemberTable
.Where(c => c.StoreId== storeId)
.Select(s => s.MemberId)
.ToArray();
var items2 = members.Where(x => dbIds.Contains(x.MemberId))
.Select(i => i.MemberId)
.ToList();
这仍然会加载不需要的行并占用额外的数据库锁,但至少它只会这样做一次。
推荐阅读
- android - 无法获取提供者 androidx.startup.InitializationProvider
- xaml - 当用户更改 Xamarin.Forms 应用程序中的动态文本大小时,我如何获得通知?
- javascript - JavaScript 显示在后退按钮单击时弹出
- chat - 如何“说服”微软团队在复制的聊天链接中显示网站徽标
- c# - 为什么我从网页“未定义”中收到错误消息
- rabbitmq - RabbitMQ 队列分片和 HA
- linux - 为什么 Linux 内核从未实现每个数据对象的 RCU 机制?
- python - 将矩阵作为输入的 Python 函数,并使用 np.linalg.cholesky 识别哪些不是正定的
- mongodb - 如何查找任何字段是否包含特定值
- c# - 在代码中设置 RowDefitions 并覆盖现有的