【发布时间】:2021-09-30 21:30:19
【问题描述】:
首先,抱歉,如果这是重复的,我真的不知道这个问题的最佳术语。
假设我有代表的 SQL 架构:
Businesses:
id: int
name: string
Employees:
id: int
business_id: int REFERENCES Businesses(id)
name: string
是否有任何可以想象的方法可以查询一个企业列表,每个企业都有一组员工作为字段附加?目前,我正在将企业列表拉入我的服务器,然后对于阵列中的每个企业,获取所有 business_id 等于其 id 的员工。这行得通,但对于大量企业而言,它会导致对数据库的大量查询。
我考虑的另一个选择是将所有员工读入我服务器上的内存,将它们放入[business_id->[employees]] 的映射中,然后将员工数组发送到服务器上正确的企业employees 字段。这似乎是一个性能更高的选项,但我想知道 MySQL 中是否有任何内置功能可以让我开箱即用地执行此操作,因为这似乎是一项非常常见的任务。谢谢!
编辑: @MatBailie 在这里提出了关于代码异味的观点,我只是想澄清这段代码的总体意图。我将从高级别添加逐步演练。
- 从列表中选择所有公司
- 获取每家公司的所有员工
- 向用户显示公司列表,并在每个公司旁边显示每位员工的可滚动列表
我知道,正如@radocaw 所指出的,获取企业的员工列表是一个微不足道的连接,但我的问题是这将需要多次访问数据库。我将在下面的 Golang 中发布我当前解决此问题的方法,使用 MySQL 中的两个简单 SELECT 和使用映射。这是给你的,@Tangentially Perpendicular!
employeeMap := make(map[int][]Employee)
employees,err := db.Query("SELECT business_id,f_name,l_name,email FROM employees")
if err != nil {
//handle error
}
for employees.Next(){
var employee Employee
err = employees.Scan(&employee.BusinessId,&employee.FName,&employee.LName,&employee.Email)
if err != nil {
//handle error
continue
}
if _,ok := employeeMap[employee.BusinessId];ok{
employeeMap[employee.BusinessId] = append(employeeMap[employee.BusinessId],employee)
}else {
employeeMap[employee.BusinessId] = make([]Employee,1)
employeeMap[employee.BusinessId[0] = employee
}
}
这用于构建业务 ID 到员工列表的映射。接下来,我将从数据库中获取企业,并为其 id 附加该员工数组。
我不确定这是否是一个好方法,但它似乎比使用 n 连接访问数据库更优化和直接,其中 n是企业的数量。感谢大家的精彩反馈和高质量的答案/cmets!
【问题讨论】:
-
您可能需要检查stackoverflow.com/questions/97197/…,它将您的问题描述为“N+1 SELECT”问题
-
这可以通过两个表之间的简单
JOIN很好地解决,所有这些都在一个查询中。您将获得每个企业的 N 行,每个员工一个,您可以在客户端将其操作到一个数组中。 SQL中没有数组的概念。 -
@Alejandro 这很有趣,我不确定这种方法是否比我建议的映射到数组的方法更好或更差。我不确定 SQL 是否有任何子表的概念,我知道我已经看到它们由子查询返回,但不是作为列值。感谢您的确认!
-
@Progman +1 提醒我这叫什么。我认为,不管我怎么做,一次读取而不是每次读取的想法更好。
-
当你得到这些数据后你打算做什么?关注最终结果并编写查询来实现这一目标,而不是中间步骤。这里的许多嵌套查询问题都是从尝试跨表检索数据开始的,但可以通过在数据库服务器上正确使用 JOIN 和聚合函数来解决。您可能会发现,对于某些查询,您根本不需要检索基础数据。