【问题标题】:Paginating Geo-Data with high performance以高性能对地理数据进行分页
【发布时间】:2021-06-09 04:59:28
【问题描述】:

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

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

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

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

非常感谢!

【问题讨论】:

  • 您在这里提供的内容不多。数据库是什么,瓶颈到底是什么,执行的查询是什么样的,到目前为止你尝试了什么等等。即我没有看到任何 where 条件,所以问题是为什么?您肯定不想查询 ALL 数据,而是将其限制在最大距离内(即距离您的位置 5000 公里/英里,这对搜索的人来说意义不大)
  • 抱歉 - 在标签中提到了“sql-server”,但忘记将其添加到描述中

标签: c# sql-server entity-framework asp.net-core asp.net-web-api


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 2020-04-09
    • 2019-11-20
    • 2014-09-20
    • 2014-04-03
    • 1970-01-01
    • 1970-01-01
    • 2011-02-15
    • 2020-05-20
    • 1970-01-01
    相关资源
    最近更新 更多