前言
在 .NET 中,IQueryable 是一种支持 延迟执行 的接口,常用于 LINQ 查询。它允许将查询逻辑转换为底层数据源(如数据库)的原生查询语言(如 SQL),从而优化性能。
一、一次性从数据库加载数据到内存和分批从数据库读取
对比ADO.Net 中读取数据的方式
- DataReader:分批从数据库服务器读取数据。内存占用小、DB连接占用时间长;
- DataTable:把所有数据一次性从数据库服务器都加载到客户端内存中。内存占用大,节省DB连接
验证IQueryable用什么方式
-
给表T_Articles插入适量数据(通过以下SQL)。
INSERT into [dbo].[T_Articles](Title,Content) SELECT Title,Content FROM [dbo].[T_Articles]
-
然后遍历IQueryable(加上Delay/Sleep,延长遍历内容的时间),在遍历执行过程中,停止SQLServer服务器。
foreach (var item in dbContext.Articles) { Console.WriteLine(item.Title); Thread.Sleep(10); }
-
会发现程序运行异常。
异常提示数据库服务不可用,说明IQueryable是一直连接着数据库,它是类似DataReader的方式一批一批的从数据库读取数据。异常信息:A transport-level error has occurred when receiving results from the server. (provider: Session Provider, error: 19 - Physical connection is not usable)
-
优点: 节省客户端内存。
-
缺点:长时间占用数据库连接。
如何一次性加载所有数据到内存
用IQueryable的ToArray()、ToArrayAsync()、ToList()、ToListAsync()等方法。
var res=dbContext.Articles.ToList();
二、何时需要一次性加载所需数据
- 遍历IQueryable并且进行数据处理的过程比较耗时。
- 如果方法需要返回查询结果,并且在方法里销毁DbContext的话,是不能返回IQueryable的,必须一次性加载返回。
- 多个IQueryable的遍历嵌套。很多数据库的ADO.Net Core
Provider是不支持多个DataReader同时执行的。SQL Server
数据库通过配置数据库连接字符串中的MultipleActiveSets=true属性可以支持
总结
IQueryable 的核心优势是 将查询逻辑推送到数据源执行,而非在内存中处理。合理使用可以显著提升性能,尤其是在处理数据库时。需要结合具体场景选择加载方式,并注意避免常见陷阱。