N+1问题是一个指在数据库中发送大量的SQL查询,从而增加负载并导致性能下降的问题。当你使用框架进行开发时,你有没有意识到你可能无意中发送了大量的SQL查询?
更具体地说,N+1问题是指在一个过程中,首先通过一个查询获取父数据,然后获取子数据,每获取一个子数据都会生成一个额外的查询,这种状态不断重复。这就是所谓的N+1问题。
以下是一个在PHP代码中出现N+1问题的例子。在循环中调用了另一个表,并在每次循环中基于父数据的emp_no
发出SQL查询:
<?php
$connection = mysqli_connect("主机名", "用户名", "密码", "数据库名");
$employeesQuery = "SELECT * FROM employees";
$employeesResults = mysqli_query($connection, $employeesQuery);
// N+1问题正在发生。基于父数据的emp_no在循环中发出SQL查询。
while ($employee = mysqli_fetch_assoc($employeesResults)) {
$empNo = $employee['emp_no'];
$salariesQuery = "SELECT * FROM salaries WHERE emp_no = '$empNo'";
$salarieResults = mysqli_query($connection, $salariesQuery);
// 处理
}
mysqli_close($connection);
?>
因为在循环中调用了另一个表,所以该PHP代码产生了N+1问题:
为了解决N+1问题,有两个策略:
1、预先加载(Eager Loading)
预先加载是一种预先获取相关数据的方法。以下的SQL查询在获取父记录时同时获取子记录,从而避免了N+1问题:
SELECT *
FROM employees
JOIN salaries
ON employees.emp_no = salaries.emp_no;
2、批处理加载(Batch Loading)
批处理加载是一种基于父数据的ID,一次性获取所有子数据的方法。这样可以避免N+1问题,并能够一次性获取所需的所有数据:
SELECT *
FROM salaries
WHERE emp_no IN (id1, id2, id3);
总的来说,处理数据库时,有预先加载和批处理加载等方法。要避免冗余的数据库访问。
评论(0)