在工作中总能碰见有人的接口使用循环查询数据库的情况,针对这种情况我总结了一些针对这种情况的初步优化思路.
限制和优点
限制
此种方法只针对循环查询这种类型的优化
优点
不用完全了解业务逻辑,即可完成有效的优化
方法
概述
- 先明确循环的位置, 以及循环内要查的数据
- 采用包一层的思路(计算机界没有什么是包一层不能解决的, 如果不能就再包一层😊), 把查询提前到循环外, 通过提供相同的查询逻辑(在内存里的查询),替换循环中的查询(数据库的查询),必须保证新的查询和老查询功能一致.
听起来好像没什么特别的,我们来看下具体实施过程
伪代码
假设有一个这种函数
func GetPersonList(xx) {
ps := models.GetPersonByXX()
for _, v := range ps {
//xxxx很多逻辑,很复杂
orders := models.GetOrderByPerson(v.ID) //这里循环查数据库,我们需要看懂这块的查询条件和返回值
//xxx很多逻辑,很复杂
}
}
我们可以这样优化
//1. 在models层实现一个批量查询接口
models.GetOrderByPersons(id ...int)
//2. 包一层实现一个数据缓存结构
type OrderDataCache struct {
order map[int/*person id */] []Order //这里的结构根据具体查询定义, 上述例子是通过person id查
}
//3. 初始化数据缓存结构函数, 根据你具体的业务实现
func NewOrderDataCache(personID ....int) OrderDataCache {
//调用批量查询
orders := models.GetOrderByPersons(id ...int)
for _, v := range orders {
//处理成[personid] []Order 结构
}
return OrderDataCache{
//[personid] []Order
}
}
//4. 用来替换循环查询的方法, 和单次查询的查询条件和返回值保持一致
func (o OrderDataCache) GetOrderByPerson( persionID int) []Order {
//这里实现一个和orders := models.GetOrderByPerson(v.ID) 一样的查询逻辑
return o.order[persionID]
}
func GetPersonList(xx) {
ps := models.GetPersonByXX()
orderCache := NewOrderDataCache(ps中提取id) //6.批量查询
for _, v := range ps {
//xxxx很多逻辑,很复杂
orders := orderCache.GetOrderByPerson(v.ID) //7. 查询替换成我们新的方法
//xxx很多逻辑,很复杂
}
}