在工作中总能碰见有人的接口使用循环查询数据库的情况,针对这种情况我总结了一些针对这种情况的初步优化思路.

限制和优点

限制

此种方法只针对循环查询这种类型的优化

优点

不用完全了解业务逻辑,即可完成有效的优化

方法

概述

  1. 先明确循环的位置, 以及循环内要查的数据
  2. 采用包一层的思路(计算机界没有什么是包一层不能解决的, 如果不能就再包一层😊), 把查询提前到循环外, 通过提供相同的查询逻辑(在内存里的查询),替换循环中的查询(数据库的查询),必须保证新的查询和老查询功能一致.

听起来好像没什么特别的,我们来看下具体实施过程

伪代码

假设有一个这种函数


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很多逻辑,很复杂
 }
}