warning n-plus-one
Запрос в цикле по результату другого запроса.
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#
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#
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.