sql - 哪个是避免 n+1 问题的最快执行方法,为什么?

标签 sql optimization orm select-n-plus-1

我希望添加一些实用方法来帮助避免很多 n+1 issues在遗留应用程序中。

常见的模式是这样的:

select a.* /* over 10 columns */
from [table-A] a
where /* something */

检索到收藏 ClassA记录实例

然后子实例被延迟检索:

select b.* /* over 10 columns */
from [sub-table-B] b
where b.ParentId = @ClassA_ID

这会导致 n+1 选择问题。大多数情况下,这不是主要问题,因为只有几个 ClassA实例是在一个不常被点击的页面上检索的,但是在越来越多的地方,这个 n+1 问题会导致页面随着应用程序的扩展而变得太慢。

我正在寻找替换此应用程序现有数据访问代码的一部分,以便 ClassA实例和 ClassB实例一起检索。

我认为有3种方法可以做到:

1) 获取 ClassA像我们现在所做的那样,然后得到 ClassB一个聚合调用中的实例:

select b.*
from [sub-table-B] b
where b.ParentId in ( /* list of parent IDs */ )

这是两个独立的 DB 调用,动态 SQL 的查询计划将无法缓存(由于 ID 列表)。

2) 获取 ClassB带有子查询的实例:

select b.*
from [sub-table-B] b
    inner join [table-A] a
        on b.ParentId = a.[ID]
where /* something */

这也是两次DB调用,查询[table-A]必须评估两次。

3) 聚在一起并删除 ClassA 的重复数据实例:

select a.*, b.*
from [table-A] a
    left outer join [sub-table-B] b 
        on a.[ID] = b.ParentId
where /* something */

这只是一次数据库调用,但现在我们得到了 [table-A] 的内容重复 - 结果集会更大,并且将数据从数据库发送到客户端的时间会更多。

所以实际上这是 3 种可能的妥协:
  • 2 次数据库调用,无查询缓存
  • 2 次数据库调用,复杂查询计算两次
  • 1 次数据库调用,结果集明显更大

  • 我可以为任何一对父子表测试这三种模式,但我有很多。我想知道的是哪种模式始终更快?更重要的是为什么?这些妥协之一是明显的性能杀手吗?

    Linq、EF 和 NHibernate 等现有机制使用什么?

    有没有比所有 3 种方法都更好的第 4 种方法?

    最佳答案

    我认为 EF 和 L2S 使用您的第三种方法 - 绝对只有一个 db 调用。

    通常,更多的 db 往返比具有更大结果集的更少的 db 往返花费更多的时间。

    也许在某些边缘情况下,您在表 A 中有大量数据,而更大的结果集会增加向客户端的传输时间太多。

    但这主要是数据库服务器和客户端之间的延迟和带宽问题。

    第 4 种方法可能是编写一个返回多个结果集的存储过程。您只查询需要的记录的每个表对应一个。这适合您的第一种方法,但减少为一次往返。但这会使事情变得有点复杂,并且不像其他方法那样灵活。

    关于sql - 哪个是避免 n+1 问题的最快执行方法,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7526227/

    相关文章:

    mysql - SQL ORDER BY - 按两列之间的值选择顺序

    java - 基本的 Java 线程问题

    mysql - 如何在 Rails 中向所有评论者发送关于多态评论的通知?

    php - Doctrine 的查询生成器的目的是什么?

    Windows Azure 中的 Sql 服务器名称别名

    sql - 在 SQL 查询的 WHERE 条件中使用 Oracle SQL 函数的输出

    SQL Server 2005 : How to add a column to a table at the beginning of the table?

    java - 有条件地将项目添加到 HashMap 的有效方法

    c++ - 如何根据先前的行为预测系统的行为

    ruby-on-rails - rails has_many :through has_many :through