“N+1选择问题”在对象关系映射(ORM)讨论中通常被称为一个问题,我理解这与必须为对象世界中看似简单的东西进行大量数据库查询有关。

有人对这个问题有更详细的解释吗?


当前回答

这是对问题的一个很好的描述

现在您了解了这个问题,通常可以通过在查询中执行连接获取来避免。这基本上强制获取延迟加载的对象,因此数据在一个查询中而不是n+1个查询中检索。希望这有帮助。

其他回答

这是对问题的一个很好的描述

现在您了解了这个问题,通常可以通过在查询中执行连接获取来避免。这基本上强制获取延迟加载的对象,因此数据在一个查询中而不是n+1个查询中检索。希望这有帮助。

N+1选择问题是一个难题,在单元测试中检测这种情况是有意义的。我已经开发了一个小型库,用于验证给定测试方法或任意代码块执行的查询数量-JDBC Sniffer

只需在测试类中添加一个特殊的JUnit规则,并在测试方法上放置带有预期查询数的注释:

@Rule
public final QueryCounter queryCounter = new QueryCounter();

@Expectation(atMost = 3)
@Test
public void testInvokingDatabase() {
    // your JDBC or JPA code
}

假设你有公司和雇员。公司有许多雇员(即雇员有一个字段COMPANY_ID)。

在某些O/R配置中,当您有一个映射的Company对象并访问其Employee对象时,O/R工具将为每个员工执行一次选择,如果您只是在直接SQL中执行操作,则可以从Company_id=XX的员工中选择*。因此,N(员工人数)加1(公司)

这就是EJB实体bean的初始版本是如何工作的。我相信像Hibernate这样的东西已经解决了这个问题,但我不太确定。大多数工具通常包含有关其映射策略的信息。

与产品有一对多关系的供应商。一个供应商拥有(供应)许多产品。

***** Table: Supplier *****
+-----+-------------------+
| ID  |       NAME        |
+-----+-------------------+
|  1  |  Supplier Name 1  |
|  2  |  Supplier Name 2  |
|  3  |  Supplier Name 3  |
|  4  |  Supplier Name 4  |
+-----+-------------------+

***** Table: Product *****
+-----+-----------+--------------------+-------+------------+
| ID  |   NAME    |     DESCRIPTION    | PRICE | SUPPLIERID |
+-----+-----------+--------------------+-------+------------+
|1    | Product 1 | Name for Product 1 |  2.0  |     1      |
|2    | Product 2 | Name for Product 2 | 22.0  |     1      |
|3    | Product 3 | Name for Product 3 | 30.0  |     2      |
|4    | Product 4 | Name for Product 4 |  7.0  |     3      |
+-----+-----------+--------------------+-------+------------+

因素:

供应商的懒惰模式设置为“true”(默认)用于查询产品的获取模式为Select获取模式(默认):访问供应商信息缓存第一次不起作用访问供应商

提取模式为选择提取(默认)

// It takes Select fetch mode as a default
Query query = session.createQuery( "from Product p");
List list = query.list();
// Supplier is being accessed
displayProductsListWithSupplierName(results);

select ... various field names ... from PRODUCT
select ... various field names ... from SUPPLIER where SUPPLIER.id=?
select ... various field names ... from SUPPLIER where SUPPLIER.id=?
select ... various field names ... from SUPPLIER where SUPPLIER.id=?

结果:

1个产品选择语句供应商的N个选择语句

这是N+1选择问题!

查看Ayende关于以下主题的帖子:打击NHibernate中的选择N+1问题。

基本上,当使用像NHibernate或EntityFramework这样的ORM时,如果您有一对多(主详细信息)关系,并且希望列出每个主记录的所有详细信息,则必须对数据库进行N+1次查询调用,“N”是主记录的数量:1次查询获取所有主记录,N次查询,每个主记录一次,获取每个主记录所有详细信息。

更多数据库查询调用→ 延迟时间更长→ 降低了应用程序/数据库性能。

然而,ORM可以选择避免这个问题,主要是使用JOIN。