Mysql解决数据库N+1查询问题

简介

在orm框架中,比如hibernate和mybatis都可以设置关联对象,比如user对象关联dept
假如查询出n个user,那么需要做n次查询dept,查询user是一次select,查询user关联的
dept,是n次,所以是n+1问题,其实叫1+n更为合理一些。

mybatis配置

UserMapper.xml

<resultMap id="BaseResultMap" type="testmaven.entity.User">
  <id column="id" jdbcType="INTEGER" property="id" />
  <result column="name" jdbcType="VARCHAR" property="name" />
  <result column="age" jdbcType="INTEGER" property="age" />
  <result column="dept_id" jdbcType="INTEGER" property="deptId" />
  <association property="dept" column="dept_id" fetchType="eager" select="testmaven.mapper.DeptMapper.selectByPrimaryKey" ></association>
 </resultMap>

数据表如下:

department表

|id|name|

user表

|id|name|department_id|

需求是得到以下结构的数据:

[
  {    "id":1,    "name":"test",    "department_id":1,    "department":{      "id":1,      "name":"测试部门"
    }
  }
]

方法一:循环查询

查询用户列表

循环用户列表查询对应的部门信息

$users = $db->query('SELECT * FROM `user`');foreach($users as &$user) {
  $users['department'] = $db->query('SELECT * FROM `department` WHERE `id` = '.$user['department_id']);
}

该方法查询次数为:1+N(1次查询列表,N次查询部门),性能最低,不可取。

方法二:连表

通过连表查询用户和部门数据

处理返回数据

$users = $db->query('SELECT * FROM `user` INNER JOIN `department` ON `department`.`id` = `user`.`department_id`');// 手动处理返回结果为需求结构

该方法其实也有局限性,如果 user 和 department 不在同一个服务器是不可以连表的。

方法三:1+1查询

该方法先查询1次用户列表

取出列表中的部门ID组成数组

查询步骤2中的部门

合并最终数据

代码大致如下:

$users = $db->query('SELECT * FROM `user`');
$departmentIds =[ ];foreach($users as $user) {  if(!in_array($user['department_id'], $departmentIds)) {
    $departmentIds[] = $user['department_id'];
  }
}
$departments = $db->query('SELECT * FROM `department` WHERE id in ('.join(',',$department_id).')');
$map = []; // [部门ID => 部门item]foreach($departments as $department) {
  $map[$department['id']] = $department;
}foreach($users as $user) {
  $user['department'] = $map[$user['department_id']] ?? null;
 }

该方法对两个表没有限制,在目前微服务盛行的情况下是比较好的一种做法。

(0)

相关推荐

  • Mysql解决数据库N+1查询问题

    简介 在orm框架中,比如hibernate和mybatis都可以设置关联对象,比如user对象关联dept 假如查询出n个user,那么需要做n次查询dept,查询user是一次select,查询user关联的 dept,是n次,所以是n+1问题,其实叫1+n更为合理一些. mybatis配置 UserMapper.xml <resultMap id="BaseResultMap" type="testmaven.entity.User"> <i

  • MySQL全文索引like模糊匹配查询慢解决方法

    目录 需求 全文索引介绍 全文索引使用 中文分词与全文索引 什么是N-gram? 这个上面这个N是怎么去配置的? 修改方式 实际使用 初始化测试数据 添加索引 查询 1.使用自然语言模式 NATURAL LANGUAGE MODE 查询 2.使用布尔模式(BOOLEAN MODE)查询 实际使用 注意点 需求 需要模糊匹配查询一个单词 select * from t_phrase where LOCATE('昌',phrase) = 0; select * from t_chinese_phra

  • Node.js数据库操作之查询MySQL数据库(二)

    前言 我们在上一篇文章<Node.js数据库操作之连接MySQL数据库(一)>中已经学习了Nodejs连接MySQL数据库的几种方法,数据库连接上了之后就需要对数据库进行查询.本篇文章介绍一下查询MySQL数据库的方法.下面话不多说,来看看详细的介绍吧. 查询方式 上一篇文章中,我们用到了一种查询数据库的最基本的方法:connection.query(sqlString, callback) . 第一个参数是一个SQL语句,可以是任意的数据库语句,而第二个参数是一个回调函数,查询结果通过回调参

  • 优化MySQL数据库中的查询语句详解

    很多时候基于php+MySQL建立的网站所出现的系统性能瓶颈往往是出在MySQL上,而MySQL中用的最多的语句就是查询语句,因此,针对MySQL数据库查询语句的优化就显得至关重要!本文就此问题做出详细分析如下: 1.判断是否向MySQL数据库请求了不需要的数据,如下列情况: (1).查询不需要的数据,例如你需要10条数据,但是你选出了100条数据加了limit做限制. (2).多表关联时返回全部列 (3).总是取出全部列select*......取出全部列,会让优化器无法完成索引覆盖扫描这类优

  • MySQL通过触发器解决数据库中表的行数限制详解及实例

    MySQL通过触发器解决数据库中表的行数限制详解及实例 最近项目一个需求是对操作日志的数量限制为10万条,超过十万条便删除最旧的那一条,保存数据库中日志数量不超过10万. 当时我的第一想法是通过触发器来做,便在数据库中执行了如下的SQL: delimiter $ create trigger limitLog before insert on OperationLog for each row begin if (select count(*) from OperationLog) > 1000

  • 完美解决因数据库一次查询数据量过大导致的内存溢出问题

    刚开始接触项目的实习生,积累经验,欢迎交流 之前做项目,遇到过一次查询数据量过大而导致的内存溢出问题,找了很多办法一直未能实际解决问题, 今天又遇到了,经过前辈的指导,终于解决了问题!! 不过此方法只在DBug启动下有效 以上这篇完美解决因数据库一次查询数据量过大导致的内存溢出问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • node使用mysql获取数据库数据中文乱码问题的解决

    参考链接:StackOverflow 问题 问题描述 在学习使用 nodejs 写 web 服务的时候,在用 mysql 获取数据库信息的时候,返回的中文一直是乱码,无论配置 charset 与否,都是乱码. 问题根源 其实这个问题不在 mysql 那边,在配置了 charet 之后,数据库获取到的数据已经不是乱码了,这个乱码是 http 服务器那边的问题 解决方法 在 http 响应数据的头部添加 charset=utf-8 即可 res.setHeader('Content-Type', '

  • 解决Docker之mysql容器数据库更改不生效的问题

    用官方的mysql 镜像需要修改一些内容,比如配置文件的修改,DB数据文件的目录等,更改之后如果重新运行容器,改过的文件就无效了,新生成的容器不会有之前改变的内容 第一种是修改官方下载的镜像,修改之后 提交一个新的镜像文件 docker commit -m 等新生成的镜像信息, 第二种MYSQL的DB数据,容器关闭后 如果用 docker restart 重启同一容器,那么数据是正常的,如果重新docker run 容器那么数据就不会显示,因为每个容器都有一个文件地址 这就需要把数据文件挂载出来

  • 使用Visual Studio Code连接MySql数据库并进行查询

    Visual Studio Code 是微软出品的一款强大的文本编辑器,本文介绍使用 VS Code 链接 MySql 数据库,并执行查询. 使用方法 Step1. 安装 Visual Studio Code VS Code 是一款跨平台的文本编辑器,访问VS Code 官网即可下载安装或者 本地绿色版安装 Step2. 打开 VS Code 并安装插件 安装插件: MySQL MySQL Syntax Step3. 开始使用 在文件菜单可以添加数据库连接: 按照步骤填写服务器.用户名.密码等:

  • 解决MySQL主从数据库没有同步的两种方法

    目录 解决MySQL主从数据库没有同步的两种方法 一.不同步情况 二.解决方案 1.先进入主库,进行锁表,防止数据写入 2.进行数据备份 3.查看master 状态 4.把mysql备份文件传到从库机器,进行数据恢复 5.停止从库的状态 6.然后到从库执行mysql命令,导入数据备份 7.设置从库同步 8.重新开启从同步 9.查看同步状态 10.回到主库并执行如下命令解除表锁定. 解决MySQL主从数据库没有同步的两种方法 工作的过程中发现Mysql的主从数据库没有同步 一.不同步情况 Mast

随机推荐