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。

     再通过压测,测试下性能,根据情况进行调整。

posted @   欢乐豆123  阅读(182)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示