(1)背景:
互联网公司,有一个专门的系统通过各种筛选条件筛选出大量的用户,接着对那些用户去推送一些消息,有时可能是一些促销活动的消息,有时可能是让你办会员卡的信息,或者促销信息。
总之,通过一些条件筛选出大量的用户,接着针对这些用户做一些推送,是互联网公司运营系统里常见的一种功能,在这个过程中,比较耗时的是筛选用户的过程。
因为互联网公司,用户日活是百万级,注册用户是千万级,而且如果还没有进行分库分表的话,这个数据库的用户可能就一张,单表里是上千万的用户数据,大概这么一个情况。
(2)SQL语句分析:
现在对运营系统筛选用户的SQL做一个简化,这个SQL经过简化可能是这样:
SELECT id,name FROM users WHERE id IN (SELECT user_id FROM users_extent_info WHERE latest_login_time < xxxx)
解释下SQL:意思就是说一般存储用户数据的表会分为两张表,一个表用来存储用户的核心数据,比如id,name,昵称,手机号之类的信息,就是users表,另外一个表可能会存储用户
的一些拓展信息,也就是users_extent_info ,比如家庭住址,兴趣爱好,最近一次登录时间之类的,就是上面的 users_extent_info表,所以上面SQL语句的意思就是有一个子查询,里面针对
用户的拓展信息表,也就是users_extent_info查询一下最近一个登录时间小于某个时间点的用户,这里其实可以是查询最近才登录过的用户,也可以查询很长时间没登录过的用户,然后给他们发送
一些push,无论哪种场景,这个SQL都是适用的。
然后外层的查询里,直接用了 id IN 子句查询id在子查询结果范围里的users表的所有数据,此时这个SQL往往一下子会查询出来很多数据,可能几千,几万,几十万,都有可能,所以其实
一般运行这类SQL之前,都会先跑一个 count 聚合函数,看看有多少条,比如下面这样:
SELECT COUNT(id) FROM users WHERE id IN (SELECT user_id FROM users_extent_info WHERE latest_login_time
这就是这个案例完整的业务背景,那么会产生什么问题?很简单,就是千万级数据量的大表场景下,上面的SQL直接轻松跑出来耗时几十秒的速度,所以说,这个SQL不优化是绝对不行的。