首页 > 解决方案 > 以高性能对地理数据进行分页

问题描述

我正在为移动应用程序构建后端(通过 REST 的 .NET 5 WebApi)。我们在数据库(Azure SQL Server)中有几百万个条目,它们都有一个地理位置。应用程序应按当前位置排序查询它们。此外,这应该是分页的,例如,在第一次调用时获取前 30 个结果,然后是接下来的 30 个,等等。

我想不出一个非常聪明的解决方案。我当前的 30 个条目的第三页代码如下所示:

data.OrderBy(p => p.Location.Distance(currentLocation)).skip(60).take(30).toListAsync()

问题是即使我知道我只需要 30 个结果,查询也需要对整个表进行排序。我知道我可以用索引来提升它,但是有没有人提示如何优化这个 LINQ 代码?

非常感谢!

标签: c#sql-serverentity-frameworkasp.net-coreasp.net-web-api

解决方案


这部分看起来很可疑: 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 搜索中,但如果您想返回结果的距离,这可能会更有用。


推荐阅读