我进行了一个演示,使用lodash.memoize
解决了N + 1
查询问题。
这是我的查询案例:有10个帖子属于1个用户。而且,客户端GraphQL
像这样查询:
query {
posts{
postId
postTitle
postAuthor{
userId
userNme
userEmail
}
}
}
如果不使用dataloader
或某些记事功能,它将向数据库发送11(10 + 1)次查询。对posts
进行1次查询,对每个帖子的用户进行10次查询。
constructor() {
super();
this.userLoader = this.createLoader(this.findByIds.bind(this));
this.userLoaderLodash = _.memoize(this.findByIds.bind(this));
}
public async findByIds(ids: string[]) {
return this.db('users').whereIn('user_id', ids);
}
public async findById(id: string) {
this.ids.push(id);
// return new Promise((resolve, reject) => {
// process.nextTick(() => {
return this.userLoaderLodash(this.ids).then((users: any[]) => {
// resolve(_.first(users));
return _.first(users);
});
// });
// }).then((user) => {
// this.ids = [];
// return user;
// });
// return this.userLoader.load(id);
}
this.userLoader
是dataloader
,this.userLoaderLodash
由lodash.memoize
实现。
这是数据库调试日志:
{ method: 'raw',
sql: '\n SELECT * FROM posts;\n ',
bindings: [],
options: {},
__knexQueryUid: '046167c1-35d7-427f-8f3d-d4ac203670a6' }
{ method: 'select',
options: {},
timeout: false,
cancelOnTimeout: false,
bindings: [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ],
__knexQueryUid: '450f19b7-3841-4c08-81f0-ca740f3abcf9',
sql: 'select * from "users" where "user_id" in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' }
如您所见,使用lodash.memoize
的方式似乎也可以解决N + 1
查询问题。不使用process.nextTick
似乎不会影响结果。