百万级SQL查询优化
地图信息,需要保存在服务器,redis来做这个工作的话 不太合适,第一数据量太大,第二大部分是冷数据,,,虽然排序用redis来做方便的多,但是还是倾向于mysql。
功能:
1.玩家可以任意创作地图,记录相关信息比如,id ,创建者id,时间戳,鸡蛋数量,鲜花数量。等
2.玩家可以查看已存在的地图,类似于留言板,供玩家浏览(大量的查询,动态加载查询)
3.每天挑选出地图好评数最多的50个,加入自定义地图。(类似于LOL的每周免费英雄)所有玩家的地图=官方地图+自定义地图。
—————————————–redis来做的话 设计结构如下:
地图编辑器的 redis 结构
每张地图信息 string 记录着地图创建者 id 鲜花 鸡蛋 时间戳等信息
key=map-info-XXXX value={"like:12,hate:12"}
XXX表示唯一id
每天上传地图信息 list 只是地图id列表
key=maps-info-day-2018-1-1 value=list 只记录list id 索引
每天的排行榜信息 sorted-set
key=maps-score-day-2018-1-1 value=sorted-set 只记录分数 和地图id 在这里可动态更新 set 集合的 score 和member(value)--排序,分数由鲜花鸡蛋等 计算出来
虽然能很好的额完成排序和单位玩家索引功能, 但是功能2就不好处理了,首先是要遍历整个相关key,或者在建立一个key-list 用来保存所有玩家的所有地图id。这样一个问题是key太多,和多重key,虽然他们大部分都是索引id但是太复杂。删除一个 其他key都要更新,集群的话还不能mset 。
缺陷:整体查询不好做。
优点:排序方便(性能还待和mysql对比)
—————————————MYSQL 来做的话 主要是SQL查询优化。
涉及到2个大问题:查询and 排序;先建立索引 create index idx on map_info(id);
查询:
先创建 500W 条记录,
打开统计,navicat for mysql …….set profiling=1;
显示计时统计:show profiles;
1.暴力全部查询 :select* from map_info 耗时3.282s
2.limit 暴力查询分页:SELECT * FROM `map_info` LIMIT 3000000, 20 耗时0.77s
3.limit where id 优化分页查询:SELECT * FROM `map_info` where id >3000000 limit 20 耗时0.000s
4. 倒叙查看优化limit分页查询:SELECT * FROM `map_info` where id <2000000000000 ORDER BY id desc limit 10 耗时0.000s
排序:
排序就用order by 常规方法来排序,因此不是大问题 就算排序10s 也无所谓。
1:按照鸡蛋数排序:SELECT * FROM `map_info` where id <2000000000000 ORDER BY hate desc limit 50 耗时1.7s
2:1E条数据,完全排序耗时:84.170s
—————————————-redis和mysql协作
思考:mysql 查询优化后确实很快,但是排序就很慢了,。因此我们要缓存排序结果。实际需求是每天凌晨更新一次排序值,这个恰恰能帮助我们进行复杂的sql语句排序工作。
方案:数据查询插入什么的直接操作mysql, 每天凌晨直接排序,然后把结果缓存到redis。所有当日自定义地图(排序后的数据)请求都访问redis中的缓存数据即可。 对于优化后的查询如果还不能满足性能需求的话,可能还要进一步利用redis来缓存(看实际性能指标来衡量,比如大量的链接,虽然单台是0.00s 毫秒级别 但是机器多了,性能也就下去了)。
排序保护(可以考虑和策划商量需求更改,比如凌晨半小时内禁止玩家上传地图什么的,来让排序工作不至于产生意外的事情)。