今天去面试了一家公司,面试官给出如下的思考题,请教高人
1.设计一个网站,需求:设计一个网页游戏,水中有5只鸭子,给5支箭;射中5只鸭子得一等奖,射中4只鸭子得二等奖,依次类推到射中1只鸭子得五等奖;
条件:每天只能出现1个一等奖,3个二等奖,50个三等奖,200个四等奖,五等奖不限。
请问如何实现客户的需求?从哪些方面考虑?
要求,用户体验不能差,实时地显示结果。
提示:高并发可能产生奖项限制超出
2.ORACLE查询问题,如一张表5千万条数,查询每页显示80,查询第9000页的数据时,SQL语句怎么写?
我列出的select * from table where num<=80*90000 and id not in (select id from table where num<=(80-1)*90000) 效率低,有没有效率高点的SQL语句?引申问题——在没有id的情况下呢?
------解决方案--------------------
5千万条数,可以考虑给表进行分区,百万条数据量一个分区,然后建索引,提高查询效率。
------解决方案--------------------
1.设计一个网站,需求:设计一个网页游戏,水中有5只鸭子,给5支箭;射中5只鸭子得一等奖,射中4只鸭子得二等奖,依次类推到射中1只鸭子得五等奖;
条件:每天只能出现1个一等奖,3个二等奖,50个三等奖,200个四等奖,五等奖不限。
请问如何实现客户的需求?从哪些方面考虑?
要求,用户体验不能差,实时地显示结果。
提示:高并发可能产生奖项限制超出
其实就是一个加锁保证数据安全的问题。这种场景和秒杀类似,但是比秒杀简单,因为不用考虑抗下秒杀在瞬时产生的压力。所以只要关注于如何保证数据安全就行了。
方案:
维护内存标志变量,标识是否有发奖
中奖时更新数据要加锁,这个加锁可以用缓存(redis、memcached),也可以直接用数据库加锁。即一次只能有一个请求在更新数据,并且需要保证其他请求看到的都是最新的数据。
2.ORACLE查询问题,如一张表5千万条数,查询每页显示80,查询第9000页的数据时,SQL语句怎么写?
我列出的select * from table where num<=80*90000 and id not in (select id from table where num<=(80-1)*90000) 效率低,有没有效率高点的SQL语句?引申问题——在没有id的情况下呢?
ORACLE接触不多,mysql里是用limit,oracle里好像有个rowid?忘了。
这种大页数分页的场景,没有太多可优化的余地。一般来说会在业务上屏蔽这种可能:谁那么无聊要一页一页翻到第9000页?
因为数据库实现原理的限制,翻页都是查询出所有数据之后再把之前的数据丢掉,所以在性能上损耗很多,一般都会从业务上来屏蔽掉这种无聊的操作。
------解决方案--------------------
第一个问题个人觉得可以换一个角度去思考,那些将可以每天先随机生成一些编号,等到那个编号的人来了就给他对应的奖。
------解决方案--------------------
设置一个随机数,比如果是5的话,就算中奖。如果当前没有人中奖的话,随机到5就算中了一等奖。如果当前一等奖已经有人获取了,那么随机到5的时候,就加1,让它永远随机不到5。
------解决方案--------------------
1.设计一个网站,需求:设计一个网页游戏,水中有5只鸭子,给5支箭;射中5只鸭子得一等奖,射中4只鸭子得二等奖,依次类推到射中1只鸭子得五等奖;
条件:每天只能出现1个一等奖,3个二等奖,50个三等奖,200个四等奖,五等奖不限。
请问如何实现客户的需求?从哪些方面考虑?
要求,用户体验不能差,实时地显示结果。
提示:高并发可能产生奖项限制超出
其实就是一个加锁保证数据安全的问题。这种场景和秒杀类似,但是比秒杀简单,因为不用考虑抗下秒杀在瞬时产生的压力。所以只要关注于如何保证数据安全就行了。
方案:
维护内存标志变量,标识是否有发奖
中奖时更新数据要加锁,这个加锁可以用缓存(redis、memcached),也可以直接用数据库加锁。即一次只能有一个请求在更新数据,并且需要保证其他请求看到的都是最新的数据。
2.ORACLE查询问题,如一张表5千万条数,查询每页显示80,查询第9000页的数据时,SQL语句怎么写?
我列出的select * from table where num<=80*90000 and id not in (select id from table where num<=(80-1)*90000) 效率低,有没有效率高点的SQL语句?引申问题——在没有id的情况下呢?
ORACLE接触不多,mysql里是用limit,oracle里好像有个rowid?忘了。
这种大页数分页的场景,没有太多可优化的余地。一般来说会在业务上屏蔽这种可能:谁那么无聊要一页一页翻到第9000页?
因为数据库实现原理的限制,翻页都是查询出所有数据之后再把之前的数据丢掉,所以在性能上损耗很多,一般都会从业务上来屏蔽掉这种无聊的操作。
思路不错,oracle我记得是rownum吧,一般我们也都是用Mysql进行分页,oracle还真没有做过
------解决方案--------------------
第一个:有关得奖的问题,感觉先得记录每一种已经获得奖项的数目,如果已经满足,那么把奖项下放到下一个奖项,在进行判断,以此类推,至于高并发,又不影响到用户的体验,感觉可以加锁,为了不影响到用户的体验的话,可以这么做如果进入判断后发现上了锁,可以给该用户直接发放五等奖。
第二个:就sql语句而言了,sql语句的 exists 比 in 的效率高,一般提倡用exists。
------解决方案--------------------
第一个问题LZ看看这样是否可行:
1、2、3、4等奖因为每日有数量限制,设置4个标识位(信号量),用来标识每个用户开始游戏时是否有机会获得相应等级奖励。如你所说,初始为 flag1 = 1; flag2 = 3; flag3 = 50; flag4 = 200;
每个用户在进入游戏的时候请求一次服务器,计算用户可能获得奖励的标识信息。服务器依次判断flag1 ~ flag5,若>0(表示对应等级奖励还有剩余)则此等级可能获得奖励,计算给用户这4个等级的信息,可以用位运算来返回。
在每次请求后,对可能产生的奖励档位,服务器更新对应的flag值-1(维护信号量)。
用户进入游戏前这一次服务器请求就决定了他可能产生哪几等奖,通过这个限制约束用户的游戏结果,
游戏结束后,请求一次服务器,用户游戏后如果中了某一个等级的奖励,记录并发奖,并将其他可能获得的等级奖励的flag值+1,其他用户继续来请求这个信号量。
一个定时器来每天0点重置这些flag。
------解决方案--------------------
第一个问题前面的人已经回答的很好了;
第二个问题,确实 没有任何一个用户会无聊到把5000W条数据以每页80条往后翻;
如果很要用楼主写的那条sql语句,数据库早晚会挂,经不起折腾, 加分区也不是一个合理的选择,如果选择加range分区? 那sql语句怎么写? list分区加不加的进去还要看数据;
楼主只能选择尽量减少对数据库的查询次数,不能每次查80条,开始可能会很快,因为直接使用rounum就可以了,但是当查询的条数上万时,每次查询80条数据 等于 查出10000条数据后丢弃 其中的9920条数据,以此类推,数据库早晚得挂。
相对于每次查80条,楼主可以选择每次查出4000条来 让服务器承担一部分压力,这样虽然数据大了,加个十几条查询现成速度也不会慢很多,然后你再将4000条数据装在介质当中, 每翻一页从4000条中抽取80条够翻50页。
从而往数据库查询的次数从625000减少到了12500次,其中对介质中数据的抽取可以使用算法;
当然 还是那句话,没有人会无聊到每页80条数据的速度翻看5000W条的数据,再不行,就不要做分页了,直接做个数据导出功能,把数据直接导出成文件 让客户慢慢看去吧,一劳永逸。
相信面试官问这种问题不是为了考研你对oracle的操作,而是想要知道你对问题的思考方式,你考虑的全面与否。