OxL Справочник OxL
РусскийEnglish

warning n-plus-one

warning Стандарт: [III.4]

Запрос в цикле по результату другого запроса.

What it means#

A database query (db.find, db.all, db.count, db.T.all(), db.T.count(), a from x in db.T … query) runs inside a for loop — or inside the closure of map/forEach/filter/… — whose iterable is the result of another query, directly or through a local bound to it. The program then sends one query per row: N + 1 round trips instead of 2 (D-6557).

Example#

oxl✓ проверяется в CI
use std.orm { Db }

@table("users")
data User { @pk id: i64; name: str }
@table("orders")
data Order { @pk id: i64; userId: i64; total: i64 }

fn report(db: &Db) io, db {
  let users = from u in db.User select u
  for u in users {
    let orders = from o in db.Order where o.userId == u.id      // <- n-plus-one
    print("{u.name} {orders.len()}")
  }
}
error
n-plus-one

How to fix#

oxl✓ проверяется в CI
use std.orm { Db }

@table("users")
data User { @pk id: i64; name: str }
@table("orders")
data Order { @pk id: i64; userId: i64; total: i64 }

fn report(db: &Db) io, db {
  let users = from u in db.User select u
  let orders = from o in db.Order order by o.userId           // one query for all rows
  var count: Map<i64, i64> = {:}
  for o in orders { count[o.userId] = (count.get(o.userId) ?? 0) + 1 }
  for u in users { print("{u.name} {count.get(u.id) ?? 0}") }
}

Load the related rows with one query before the loop (where o.userId in ids, or load for ref/many relations) and look them up in memory.

See also#

OxL 1.0.0-beta · Версия документации 1.0.0-beta© OxwaldLink · сгенерировано из Стандарта, исходников std и руководства