当前位置: 首页 > 后端技术 > PHP

N+1问题是什么,如何解决

时间:2023-03-29 21:28:32 PHP

N+1是ORM(ObjectRelationalMapping)关系型数据读取中的一个问题。在介绍什么是N+1问题之前,先想一个问题:假设有一张用户表(User)和一张余额表(Balance),这两个表是通过user_id关联起来的。现在需要查询18岁以上的用户及其各自的余额。这道题不难,但是对于新手来说,可能经常犯的一个错误就是循环查询。$users=User::where("age",">",18)->select();foreach($usersas$user){$balance=User::getFieldByUserId($user->user_id,"balance");$user['balance']=$balance;}这样做是很不好的,数据量小又小,在数据量很大的情况下,会非常消耗数据库性能。通过Mysql查询日志可以看到,user表被查询了一次,因为满足这个条件的用户有四个,与user表关联的balance表被查询了四次。N+1问题就是这样产生的:查询一次主表,查询了N条记录。根据这N条记录,需要N次查询关联的从(slave)表。因此,称其为1+N问题更为恰当。其实,如果你稍微懂一点SQL,就不用这么麻烦了,用一次IN就完事了。对于这种问题,ORM其实给我们提供了相应的解决方案,就是使用“预加载功能”。预加载函数使用with()方法指定要预加载的关联:$users=User::where("age",">",18)->with("hasBalance")->select();hasBalance是什么?它是User模型中定义的一个方法:classUserextendsModel{//...//User模型和Balance模型的一对一关联publicfunctionhasBalance(){return$this->hasOne(Balance::类,“user_id”,“user_id”);}}通过这个方法,可以将User模型和Balance模型一一对应起来。现在再看Mysql的查询日志:可以清楚的看到查询总数从原来的1+N变成了现在的1+1。总结什么是N+1问题?会有什么影响?应该如何解决?执行一次查询得到N条原始数据后,由于关联对数据执行N条查询带来的不必要的查询开销可以通过框架ORM自带的with来解决