您的位置:首页 >c#如何实现分页查询_c#分页查询最全用法总结
发布于2026-05-03 阅读(0)
扫一扫,手机访问

OFFSET-FETCH 做分页最直接说到在SQL Server里做分页,2012及以上版本提供的OFFSET-FETCH子句,无疑是那个最标准、最清晰的选项。它语义一目了然,写法也足够简洁,完全可以作为首选方案。比起依赖ROW_NUMBER()函数或者写复杂的嵌套子查询,它的执行计划通常也更优。
不过,这里有个常见的“坑”得留意:千万别把OFFSET和FETCH的顺序写反了,更别忘了ORDER BY子句——它是必须存在的,否则数据库会直接报错"The OFFSET clause is missing in the ORDER BY clause."。
OFFSET @skip ROWS FETCH NEXT @take ROWS ONLY。其中,@skip = (页码 - 1) * 每页大小,@take = 每页大小。OFFSET值为0是合法的,但不能为负数;FETCH则必须是个正整数。ORDER BY子句末尾,追加一个唯一列(比如主键)。Skip() 和 Take() 就够了如果你在用Entity Framework Core,事情就简单多了。直接使用Skip()和Take()这两个方法,框架会自动帮你翻译成底层数据库对应的分页语法——SQL Server对应OFFSET-FETCH,MySQL对应LIMIT,PostgreSQL对应LIMIT-OFFSET。这意味着,你完全不必手动去拼接那些SQL字符串。
但这里有个性能“杀手”需要警惕:那就是在内存中进行分页。具体来说,就是先调用ToList()或ToListAsync()把所有数据拉到内存里,然后再进行Skip和Take操作。一旦数据量大了,这种操作会导致整个数据集被完整加载,响应速度会急剧下降。
Skip()和Take()是在IQueryable上调用,并且要在最终的ToListAsync()执行之前。Where条件筛选后,紧接着调用AsEnumerable()或ToList(),然后再分页。IQueryable的链式传递,不要提前触发查询执行。当需要手写ADO.NET代码进行分页时,安全性和健壮性就成了首要考量。直接使用字符串拼接来构造SQL(比如"... LIMIT " + pageSize)是极不安全的做法,也为后期维护埋下隐患。正确的做法是:全部使用参数化查询,包括OFFSET和FETCH的数值。
一个常见的错误是把页码或页大小当作字符串类型的参数传递,这会导致SQL报错,例如"Incorrect syntax near '@offset'"。原因在于,SQL参数只能用于代表值,不能用于替代关键字或语法结构的位置。
OFFSET @skip ROWS FETCH NEXT @take ROWS ONLY,并确保参数类型为int。LIMIT @take OFFSET @skip,同样使用MySqlParameter,并且OFFSET参数必须为整数类型(不能是long或string)。string.Format或者字符串插值($"")来拼接分页参数,这是一个高危操作。OFFSET 性能会明显下降当数据量非常庞大时,OFFSET分页的短板就会暴露出来。想象一下,当OFFSET值变得很大(例如要查询第10000页,每页20条,那么OFFSET就是199980),数据库引擎仍然需要扫描并跳过前面所有的行,这会导致IO和CPU开销急剧上升。
这个问题在C#应用层是无法解决的,但开发者必须清楚何时应该切换策略。这时,“游标分页”(cursor-based pagination)就派上用场了。它的核心思路是:利用上一页最后一条记录的排序字段值,作为查询下一页的起点。
CreateTime DESC排序)或者ID有序增长的场景。WHERE CreateTime 话说回来,在实际项目中,90%的分页需求使用EF Core的Skip/Take组合就完全能够胜任。如果真的遇到了需要在百万级数据中深度翻页的场景,那么问题的关键可能不在于OFFSET怎么写更快,而是需要重新审视整个查询逻辑的设计了。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
9