c# - 以高性能对地理数据进行分页
问题描述
我正在为移动应用程序构建后端(通过 REST 的 .NET 5 WebApi)。我们在数据库(Azure SQL Server)中有几百万个条目,它们都有一个地理位置。应用程序应按当前位置排序查询它们。此外,这应该是分页的,例如,在第一次调用时获取前 30 个结果,然后是接下来的 30 个,等等。
我想不出一个非常聪明的解决方案。我当前的 30 个条目的第三页代码如下所示:
data.OrderBy(p => p.Location.Distance(currentLocation)).skip(60).take(30).toListAsync()
问题是即使我知道我只需要 30 个结果,查询也需要对整个表进行排序。我知道我可以用索引来提升它,但是有没有人提示如何优化这个 LINQ 代码?
非常感谢!
解决方案
这部分看起来很可疑: p.Location.Distance(currentLocation)
。如果这是运行 EF Core 2.x,那么我的猜测是这将触发客户端评估,导致在排序和分页之前查询所有数据。我建议将分析器连接到数据库并查看实际运行的 SQL。
为了更好地安排按距离排序,我会考虑这样的事情:
var x = currentLocation.X;
var y = currentLocation.Y;
var results = await data.OrderBy(p => Math.Abs(p.Location.X - x) + Math.Abs(p.Location.Y - y))
.Skip(pageNumber * pageSize)
.Take(pageSize)
.ToListAsync();
这确保排序是在数据库服务器端完成的。(虽然确保data
仍然是一个IQueryable
。)用 Lat/Long 或您正在使用的任何坐标字段替换 X/Y。
这不会给你距离,但它会给你一个相对于每个点的距离的值,以便与其他点进行比较。要获得距离将是Math.Sqrt(Math.Pow(p.Location.X - x,2) + Math.Pow(Location.Y - y,2))
。我相信 EF 会将其转换为 SQL,至少对于 SQL Server 的提供程序而言。将更多的数学转换放入无法索引的 SQL 搜索中,但如果您想返回结果的距离,这可能会更有用。
推荐阅读
- javascript - JavaScript - 通过对象“过滤” - 最佳实践?
- asp.net-core - AWSSDK.DynamoDBv2 的 Table.PutItemAsync 始终返回 null
- r - 有没有办法在 r 中将 2 位数的年份变成 4 位数的年份
- python - 如何将列添加到漂亮表作为第一列
- swift - 使用@EnvironmentObject 我得到:“不能分配给属性:'viewModel' 是一个只能获取的属性”
- c++ - C++|将用户输入存储到模板变量
- mysql - MySQL: ERROR 1822 (HY000) 无法添加外键约束。缺少约束索引
- c - 如何使用任务和依赖项将 C 代码程序转换为 OpenMP
- batch-file - 批处理脚本在 ssh 后停止并且没有继续
- python - 如何将以下 Python 字符串拆分为字符串列表?