最后
看完美团、字节、腾讯这三家的面试问题,是不是感觉问的特别多,可能咱们又得开启面试造火箭、工作拧螺丝的模式去准备下一次的面试了。
开篇有提及我可是足足背下了1000道题目,多少还是有点用的呢,我看了下,上面这些问题大部分都能从我背的题里找到的,所以今天给大家分享一下互联网工程师必备的面试1000题。
注意不论是我说的互联网面试1000题,还是后面提及的算法与数据结构、设计模式以及更多的Java学习笔记等,皆可分享给各位朋友
互联网工程师必备的面试1000题
而且从上面三家来看,算法与数据结构是必备不可少的呀,因此我建议大家可以去刷刷这本左程云大佬著作的《程序员代码面试指南 IT名企算法与数据结构题目最优解》,里面近200道真实出现过的经典代码面试题。
GET /api/products
{“items”: […100 products],
“cursor”: “qWe”}
API 返回一个无业务意义的字符串(游标),你可以用它来检索下一个页面。
GET /api/products?cursor=qWe
{“items”: […100 products],
“cursor”: “qWr”}
实现游标有很多方法。一般来说,可以通过一些排序字段比如产品 id 来实现。在这种情况下,你可以用一些可逆算法对产品 id 进行编码。而在接收到一个带有游标的请求时,你会对它进行解码,并生成一个类似 WHERE id > :cursor LIMIT 100 的查询。
下面是一个小小的性能对比,先看看 offset 是如何工作:
=# explain analyze select id from product offset 10000 limit 100;
QUERY PLAN
Limit (cost=1114.26…1125.40 rows=100 width=4) (actual time=39.431…39.561 rows=100 loops=1)
-> Seq Scan on product (cost=0.00…1274406.22 rows=11437243 width=4) (actual time=0.015…39.123 rows=10100 loops=1)
Planning Time: 0.117 ms
Execution Time: 39.589 ms
再看看 where (cursor) 语句如何工作:
=# explain analyze select id from product where id > 10000 limit 100;
QUERY PLAN
Limit (cost=0.00…11.40 rows=100 width=4) (actual time=0.016…0.067 rows=100 loops=1)
-> Seq Scan on product (cost=0.00…1302999.32 rows=11429082 width=4) (actual time=0.015…0.052 rows=100 loops=1)
Filter: (id > 10000)
Planning Time: 0.164 ms
Execution Time: 0.094 ms
这是几个数量级的差异! 当然,实际的差异取决于表的大小以及过滤器和存储的实现。有一篇不错的文章 (1) 提供了更多的技术信息,里面有 ppt,性能比较见第 42 张幻灯片。
(1) https://use-the-index-luke.com/no-offset
当然,用户不会按 id 来检索商品,而是会按一些相关性来查询(然后按 id 作为关联字段)。在现实世界中,需要根据你的业务来决定该怎么做。订单可以按 id 排序(因为它是单调增加的)。购买清单可以按 wishlist 时间排序。在我们的案例中,产品来自 ElasticSearch,自然支持游标的特性。
我们可以看到的一个不足是,使用无状态的 API, 无法支持翻到“上一页”这样的功能。所以在面向用户界面中,如果有 prev/next 或者 “直接进入第10页” 这样的按钮,就没有办法绕过前面提到的 offset/limit 这种实现。但是在其他情况下,使用基于游标的分页可以极大地提高性能,特别是在真正的大表和真正的深度分页上。
英文原文:
https://solovyov.net/blog/2020/api-pagination-design/
HackerNews 评论:
https://news.ycombinator.com/item?id=25547716
HN网友 et1337:
使用游标的另一个原因是避免由于并发编辑而导致元素重复或跳过的问题,比如你使用 offset 正在第 10 页上,而有人在第 1 页上删除了一个项目,则整个列表会移动,你可能会意外跳过第 11 页上的一行数据。同样,如果有人在第 1 页上添加了一条记录而你正在第 10 页上,第 10 页中的一项也会重复显示在第 11 页上。
游标优雅地回避了这些问题。
HN 网友 chrismorgan:
有时候,你需要一个游标,这样你就可以从你刚才的地方继续前进,而不用担心新的记录进来扰乱你的分页。
有时你想要基于位置的查询,因为你明确地希望所有的东西都是位置的。
有时你想把这两种技术结合起来,例如,如果你跳到一个大的、不断变化的列表中间,然后想在刚才的位置之后检索下一批结果。
我喜欢 JMAP 最后的设计(https://tools.ietf.org/html/rfc8620#page-45):你可以指定一个位置整数,或者一个锚 ID 和可选的 anchorOffset 整数。锚是游标的一种实现,它使用结果集中一个实体 ID,而不是一个可以嵌入其他信息(比如 coroutine 地址)的不透明类型,,它有一个明显的优点,就是可以由客户端控制。
HN 网友 vincnetas
我认为作者在使用 OFFSET 时忽略了一些关键点。至少 postgres 文档对此有明确的的说法(https://www.postgresql.org/docs/13/queries-limit.html)
When using LIMIT, it is important to use an ORDER BY clause that constrains the result rows into a unique order. Otherwise you will get an unpredictable subset of the query’s rows. You might be asking for the tenth through twentieth rows, but tenth through twentieth in what ordering?
看起来作者提供的分页查询没有考虑到排序,这意味着第 100 页上的项目的 ID 大于 10000,但顺序未定义。
explain analyze select id from product where id > 10000 limit 100
HN 网友 boulos
鉴于对“游标”一词的重用感到困惑,我更喜欢 Google 为分页所使用的术语:页面令牌和页面大小,详细可以参阅:
https://google.aip.dev/158
图片
总结
阿里伤透我心,疯狂复习刷题,终于喜提offer 哈哈~好啦,不闲扯了
1、JAVA面试核心知识整理(PDF):包含JVM,JAVA集合,JAVA多线程并发,JAVA基础,Spring原理,微服务,Netty与RPC,网络,日志,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存,Hadoop,Spark,Storm,YARN,机器学习,云计算共30个章节。
2、Redis学习笔记及学习思维脑图
3、数据面试必备20题+数据库性能优化的21个最佳实践
题+数据库性能优化的21个最佳实践
[外链图片转存中…(img-ua62sTPT-1714849456094)]