MySQL如何高效地随机读取数据
MySQL如何高效地随机读取数据
线上事故
生产项目中出现了一个线上事故,需求其实很简单:从mysql数据库中中随机读取出100条认证企业的数据到前端来展示,并且要求每一次读取的数据是不同的。
结果上线后,CPU负载过高,发生了报警。
1. 数据表
下面两表中, member_verify 中有约400W数据,company中有约8W条

最开始项目中使用order by rand()这样来实现,具体语句如下:
1 SELECT c.user_id, c.company_name 2 FROM `jc_company` c 3 LEFT JOIN `jc_member_verify` v ON c.user_id = v.user_id 4 WHERE v.company_status = 2 5 AND c.province_id = 0 6 GROUP BY c.company_name 7 ORDER BY rand() 8 LIMIT 1000
我们来用explain看下上面语句使用索引的情况:
由上面的结果可以分析,order by rand() 导致了mysql使用了外部排序,sql效率非常低
优化方案的方案有很多,比如放到redis缓存,每次从redis缓存读取,下面是其中一种:
1)不做连接查询,先到member_verify通过company_status筛选出满足条件的数据,再到company中去查询最后要查询数据
2)每次展示N条,取100页的数据,通过随机生成1-100的页码,取到第N页的数据
示例代码:
1 public function cleaningJob($pageSize): array 2 { 3 $randPage = 1; 4 5 $countQuery= $this->select(['id','user_id']) ->where('company_status', 2);
6 $count= $this->select(['id','user_id']) ->where('company_status', 2)->count(); 7 8 if ($count > $pageSize) { 9 $endNum = (int)ceil($count / $pageSize); 10 $randPage = random_int(1, ($endNum > 100 ? 100 : $endNum)); 11 } 12 13 $offset=(randPage-1)*pageSize; 14 15 $query = $countQuery->limit($offset, $pageSize);
//... 17 18 }
然后通过company的唯一键user_id 去company查询出company_name。
再通过压测,测试下性能,根据情况进行调整。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)