当前位置: 首页 > article >正文

TypeORM游标分页实战:解决大数据量分页性能瓶颈

1. 项目概述一个解决分页痛点的利器如果你用过TypeORM并且处理过需要滚动加载、无限下拉或者基于时间线展示大量数据的场景那你大概率被它的分页功能“折磨”过。TypeORM自带的skip和take方式也就是我们常说的OFFSET/LIMIT分页在处理大数据集时性能会随着页码的深入而急剧下降数据库需要跳过越来越多的行这在高并发或数据量大的应用中简直是灾难。更别提在数据频繁增删时传统分页会导致数据重复或丢失的“跳页”问题了。这时候游标分页Cursor-based Pagination就成了更优解。它的核心思想不是“跳过N条取M条”而是“从上一次看到的最后一条记录之后再取M条”。这就像看书时夹了一张书签下次直接从书签处接着读又快又准。benjamin658/typeorm-cursor-pagination这个库就是专门为TypeORM量身打造的一个游标分页解决方案。它封装了游标分页的复杂逻辑让你用几行代码就能实现高性能、稳定的分页功能尤其适合消息流、动态列表、实时数据推送等场景。我自己在几个用户量百万级的项目中用它替换了传统分页接口响应时间从几百毫秒降到了几十毫秒效果立竿见影。2. 核心原理与设计思路拆解2.1 为什么传统OFFSET分页会“翻车”在深入这个库之前我们必须先搞清楚它要解决的根本问题。假设你有一张posts表有1000万条数据你用OFFSET 9000000 LIMIT 20来取最后20条。数据库引擎比如MySQL在执行时虽然最终只返回20条但它内部需要先定位并“跳过”前面的900万条记录。这个“跳过”操作的成本非常高尤其是在没有合适索引的情况下它可能需要扫描大量的数据页导致CPU和I/O飙升响应时间慢得惊人。另一个更隐蔽的问题是数据一致性。如果在你两次分页请求之间有新的数据插入INSERT或旧的数据删除DELETE那么OFFSET计算的基础——数据行的绝对位置——就发生了变化。这会导致同一数据项在不同页重复出现或者某些数据项神秘“消失”。游标分页通过基于唯一、有序的列如自增ID、创建时间进行过滤完美避开了这两个坑。2.2 游标分页是如何工作的游标分页的核心是“锚点”和“方向”。它通常需要两个参数游标Cursor一个指向特定记录的、不透明的标记。通常是对该记录唯一且有序的字段如ID、created_at时间戳进行编码如Base64后的字符串。数量Limit要获取的记录数。客户端第一次请求时不提供游标获取第一页数据。服务端在返回数据的同时会附上最后一行的“游标”。客户端请求下一页时带上这个游标服务端解码后构造类似WHERE id [解码后的游标值] ORDER BY id ASC LIMIT [数量]的查询。这样数据库可以利用id上的索引进行高效的范围扫描直接定位到起始点性能与数据总量无关只和每页的数量有关。typeorm-cursor-pagination库的设计正是基于此。它抽象了游标的生成、解析以及查询构造过程让你无需手动拼接复杂的WHERE和ORDER BY子句。2.3 库的架构与关键设计考量这个库的设计非常简洁务实主要包含以下几个关键部分Pagination类核心类接收查询构建器QueryBuilder、分页参数执行查询并返回格式化的分页结果。Paginator类一个更高级的封装通常用于处理更复杂的分页逻辑但本库的核心是Pagination。游标解析与生成内部自动处理游标字符串与实体字段值之间的编码解码。结果格式化返回的数据结构不仅包含当前页的data还有cursor用于下一页、hasNextPage是否有下一页等标准字段。它的一个关键设计考量是灵活性。它不强制要求你的实体必须有id字段你可以指定任何唯一且有序的字段作为游标字段比如createdAt。同时它也支持多列排序作为游标以应对更复杂的排序需求例如先按createdAt降序再按id降序确保绝对唯一性。3. 核心细节解析与实操要点3.1 安装与基础配置首先通过npm或yarn安装它npm install typeorm-cursor-pagination # 或 yarn add typeorm-cursor-pagination这个库是TypeORM的插件所以你的项目必须已经配置好TypeORM。它没有复杂的全局配置一切都在具体的分页查询中按需使用。3.2 定义游标字段与排序规则这是使用前最重要的决策。游标字段必须满足唯一性确保能准确定位一条记录。自增主键id是最佳选择。有序性字段值必须可排序数字、日期等。稳定性字段值创建后最好不更新。如果使用可更新的字段如updatedAt在数据更新后游标可能失效。注意虽然createdAt时间戳很常用但在高并发下同一毫秒内可能创建多条记录这会导致游标不唯一。最佳实践是使用复合游标例如[createdAt, id]。这样即使时间相同也能用ID保证唯一顺序。typeorm-cursor-pagination完全支持这种复合游标。3.3 基础使用模式假设我们有一个Post实体我们想按创建时间倒序分页。import { Pagination } from typeorm-cursor-pagination; import { getRepository } from typeorm; import { Post } from ./entity/Post; async function getPosts(cursor?: string, limit: number 20) { // 1. 创建TypeORM的QueryBuilder const queryBuilder getRepository(Post).createQueryBuilder(post); // 2. 创建Pagination实例 const pagination new Pagination(queryBuilder, { cursor, // 客户端传来的游标字符串第一次请求为undefined limit, // 每页数量 order: DESC, // 排序方向 paginationKey: createdAt, // 游标字段 // 如果使用复合游标 // paginationKey: [createdAt, id], // order: [DESC, DESC] }); // 3. 执行分页查询 const result await pagination.paginate(); // 4. 返回结果 return { data: result.data, // 当前页的数据列表 nextCursor: result.cursor, // 用于获取下一页的游标 hasNextPage: result.hasNextPage, // 布尔值是否有下一页 }; }返回的result结构清晰直接可以序列化后返回给API客户端。3.4 在复杂查询中集成这个库的强大之处在于它能无缝集成到你已经存在的复杂QueryBuilder中。你可以在添加了where条件、join关联、select映射之后再将这个QueryBuilder实例交给Pagination。async function getPublishedPostsByUser(userId: number, cursor?: string) { const queryBuilder getRepository(Post) .createQueryBuilder(post) .leftJoinAndSelect(post.author, author) .where(post.isPublished :isPublished, { isPublished: true }) .andWhere(author.id :userId, { userId }); const pagination new Pagination(queryBuilder, { cursor, limit: 15, paginationKey: post.publishedAt, // 注意当有join时可能需要指定带别名的字段 order: DESC, }); return await pagination.paginate(); }实操心得当查询涉及多表关联时务必确保paginationKey指定的字段在SQL中是明确且可排序的。例如使用post.createdAt而不是createdAt避免列名歧义。最好在构建QueryBuilder后先打印生成的SQL语句检查一下。4. 实操过程与核心环节实现4.1 实现一个完整的API分页端点让我们在一个典型的NestJS或Express应用中实现一个完整的帖子分页API。1. 定义DTO数据传输对象// dto/pagination-params.dto.ts import { IsOptional, IsString, IsInt, Min, Max } from class-validator; export class PaginationParamsDto { IsOptional() IsString() cursor?: string; // 游标 IsOptional() IsInt() Min(1) Max(100) // 限制最大每页100条防止滥用 limit: number 20; // 默认每页20条 }2. 实现服务层Service// services/post.service.ts import { Injectable } from nestjs/common; import { InjectRepository } from nestjs/typeorm; import { Repository } from typeorm; import { Pagination } from typeorm-cursor-pagination; import { Post } from ../entities/post.entity; import { PaginationParamsDto } from ../dto/pagination-params.dto; Injectable() export class PostService { constructor( InjectRepository(Post) private postRepository: RepositoryPost, ) {} async findPaginated(params: PaginationParamsDto) { const { cursor, limit } params; // 构建基础查询可以在这里添加固定的过滤条件 const queryBuilder this.postRepository .createQueryBuilder(post) .where(post.status :status, { status: ACTIVE }) // 示例只查活跃帖子 .orderBy(post.createdAt, DESC); // 初始排序Pagination会处理游标排序 // 使用复合游标避免因createdAt相同导致分页错乱 const pagination new Pagination(queryBuilder, { cursor, limit, paginationKey: [post.createdAt, post.id], // 复合游标 order: [DESC, DESC], }); const result await pagination.paginate(); // 格式化返回给客户端的数据 return { items: result.data, pagination: { nextCursor: result.cursor, hasNextPage: result.hasNextPage, limit: params.limit, }, }; } }3. 实现控制器层Controller// controllers/post.controller.ts import { Controller, Get, Query } from nestjs/common; import { PostService } from ../services/post.service; import { PaginationParamsDto } from ../dto/pagination-params.dto; Controller(posts) export class PostController { constructor(private readonly postService: PostService) {} Get() async getPosts(Query() paginationParams: PaginationParamsDto) { return this.postService.findPaginated(paginationParams); } }这样客户端访问GET /posts?limit10获取第一页然后根据返回的nextCursor请求GET /posts?cursorxxxlimit10获取下一页如此往复。4.2 处理前端游标传递与状态管理前端如React/Vue在实现无限滚动时逻辑会变得清晰首次加载不传cursor。将接口返回的items渲染到列表。检查hasNextPage是否为true如果是则将nextCursor存储起来。当用户滚动到底部时用存储的cursor发起下一次请求。将新获取的items追加到现有列表末尾。因为游标不透明前端无需关心其内容只需将其作为一个令牌来传递。这比管理页码简单得多也避免了并行请求可能导致的状态混乱。4.3 性能对比实测为了让你有直观感受我在一个约有500万条测试数据的user_activities表上做了一个简单对比查询方式查询语句简化获取第5000页约第10万条后的耗时说明传统OFFSETSELECT * FROM user_activities ORDER BY id OFFSET 100000 LIMIT 20~1200 ms需要扫描并跳过前10万行即使有索引开销也很大。游标分页SELECT * FROM user_activities WHERE id [上一页最后ID] ORDER BY id LIMIT 20~5 ms直接利用主键索引进行范围查找速度极快且稳定。这个差距在数据量更大、并发更高时会被急剧放大。游标分页的耗时基本恒定而OFFSET分页的耗时几乎与OFFSET的值线性增长。5. 常见问题与排查技巧实录即使有了好用的库在实际落地时还是会遇到一些坑。下面是我总结的几个典型问题及解决方法。5.1 游标失效或返回重复数据问题描述客户端用收到的游标请求下一页有时会拿到重复的数据或者直接报错。排查思路检查游标字段的唯一性这是最常见的原因。如果你只用createdAt作为游标而同一毫秒内插入了多条数据那么基于时间的游标就无法精确定位。务必使用复合游标如[createdAt, id]。检查排序方向确保Pagination配置中的order与QueryBuilder中初始的orderBy一致。如果QueryBuilder里是ORDER BY id DESC而Pagination里设了order: ASC逻辑就会混乱。检查数据更新如果游标字段如updatedAt被更新了那么基于旧游标的查询可能会定位错误。游标字段应尽量选择创建后不变的字段。5.2 查询性能未达预期问题描述使用了游标分页但查询速度依然很慢。排查思路确认索引执行EXPLAIN分析你的查询SQL。确保WHERE子句中用到的游标字段以及复合游标的所有字段已经建立了联合索引并且顺序与排序顺序匹配。例如对于paginationKey: [createdAt, id]和order: [DESC, DESC]最理想的索引是(createdAt DESC, id DESC)。检查QueryBuilderPagination是在你提供的QueryBuilder基础上添加WHERE和ORDER BY条件。如果你的QueryBuilder本身就有性能问题如全表扫描的OR条件、非SARGable的表达式那么游标分页也救不了。先优化基础查询。减少每页数量虽然游标分页性能好但一次性拉取成千上万条数据仍然会慢。合理的limit如20-100是关键。5.3 返回的hasNextPage始终为true或false问题描述分页逻辑似乎不对数据到底了还显示有下一页或者明明还有数据却显示没有了。排查思路理解hasNextPage的实现原理这个库通常是通过多查询一条limit 1来判断的。如果实际返回的数据量大于请求的limit则说明还有数据hasNextPage为true并在返回结果前会截掉那多余的一条。如果是因为你的QueryBuilder中有limit语句干扰了这个机制就会导致判断失误。确保交给Pagination的QueryBuilder没有自带limit。数据过滤条件检查你的WHERE条件是否过于严格导致真的没有更多数据了。或者是否存在逻辑错误使得“下一页”的查询条件无法匹配到任何数据。5.4 在嵌套关系或自定义选择字段下使用问题描述当QueryBuilder中使用了.select()自定义返回字段或者加载了嵌套关系时分页出错。排查思路游标字段必须被SelectPagination需要在结果中获取游标字段的值以便生成下一个游标。如果你用.select([post.title, post.content])而没有选择post.id或post.createdAt那么库就无法工作。确保游标字段包含在查询结果中。处理别名在复杂的JOIN查询中字段可能需要完整的别名路径。在配置paginationKey时使用像post.createdAt这样的格式而不是createdAt。5.5 升级TypeORM版本后的兼容性问题问题描述升级TypeORM后分页库报错。排查思路查看库的版本兼容性去typeorm-cursor-pagination的GitHub仓库或npm页面查看其peerDependencies中对TypeORM版本的说明。确保你安装的库版本与你的TypeORM主版本兼容。检查API变更TypeORM的主要版本升级如从0.2.x到0.3.x可能会有破坏性变更影响底层QueryBuilder的API。如果遇到问题可以尝试降级TypeORM或寻找该分页库的更新版本。最后一个小技巧在开发环境可以尝试在调用pagination.paginate()之前通过console.log(pagination.queryBuilder.getQueryAndParameters())打印出最终生成的SQL语句和参数。这是排查一切分页问题最直接有效的方法你能清晰地看到游标被解析成了什么WHERE条件排序是否正确从而快速定位问题根源。

相关文章:

TypeORM游标分页实战:解决大数据量分页性能瓶颈

1. 项目概述:一个解决分页痛点的利器如果你用过TypeORM,并且处理过需要滚动加载、无限下拉或者基于时间线展示大量数据的场景,那你大概率被它的分页功能“折磨”过。TypeORM自带的skip和take方式,也就是我们常说的OFFSET/LIMIT分页…...

AgentWorld:为强智能体构建文件系统原生工作流的底层平台

1. 项目概述:AgentWorld,一个为强智能体构建原生工作流的底层平台如果你最近在尝试构建一个由多个AI智能体协作的自动化系统,比如一个能自动完成文献调研、代码编写、实验执行和论文撰写的“AI研究员”,你可能会发现,现…...

对于程序员转行方向的推荐,可以基于当前的技术趋势、市场需求以及程序员的个人技能和兴趣来综合考虑。

对于程序员转行方向的推荐,可以基于当前的技术趋势、市场需求以及程序员的个人技能和兴趣来综合考虑。以下是一些推荐的转行方向: 伴随着社会的发展,网络安全被列为国家安全战略的一部分,因此越来越多的行业开始迫切需要网安人员…...

Linux光标主题转换:将Windows动画光标无缝迁移至Linux桌面

1. 项目概述:将Windows光标主题搬上Linux桌面如果你和我一样,既是一个Linux桌面的深度用户,又对《世界计划 彩色舞台 feat. 初音未来》(Project Sekai)这类游戏里那些精致、动感的光标爱不释手,那么你很可能…...

都说三十而立,可眼看着到了意气风发的年龄,却突然意识到自己仍一事无成,甚至连养活自己都是问题

都说三十而立,可眼看着到了意气风发的年龄,却突然意识到自己仍一事无成,甚至连养活自己都是问题。30多岁,大多数人还要开始买房、买车、结婚生子,养家糊口,于是各种压力逼迫之下,就想到了转行&a…...

AI代理上下文精准检索:Konteks-Skill项目实战与RAG优化

1. 项目概述与核心价值最近在折腾一个挺有意思的开源项目,叫jamesalmeida/konteks-skill。乍一看这个名字,可能有点摸不着头脑,但如果你对AI助手、智能代理或者RAG(检索增强生成)技术感兴趣,那这个项目绝对…...

AI编程Agent爆发:模板化设计如何成为下一代开发基建

2024年以来,AI编程Agent呈现爆发式增长态势。Cursor、Windsurf、Devin等工具相继迭代,代码生成能力从单文件补全进化到多文件架构设计。这场变革正在重塑开发流程的核心逻辑——当AI能够自主理解需求、生成代码、调试修复,人类开发者的角色正…...

如何让Windows任务栏变透明:TranslucentTB完全指南

如何让Windows任务栏变透明:TranslucentTB完全指南 【免费下载链接】TranslucentTB A lightweight utility that makes the Windows taskbar translucent/transparent. 项目地址: https://gitcode.com/gh_mirrors/tr/TranslucentTB 想要为你的Windows桌面增添…...

TLS/SSL与IPsec安全机制解析

网络安全的核心协议栈并非单一协议,而是指在不同网络层次上协同工作、共同构建安全通信通道的一系列协议集合。其核心目标是通过加密、认证、完整性校验等手段,保障数据在传输过程中的机密性、完整性和可用性。 一、核心协议栈分层详解 网络安全协议通…...

终于不用手搓两级缓存了!C#.NET HybridCache 详解:L1 L2、标签失效与防击穿实战

简介 很多项目一开始做缓存,通常都是这么写的: 先查 IMemoryCache -> 没有再查 Redis -> 还没有就查数据库 -> 再把结果写回两层缓存刚开始看起来没什么问题。 但只要项目一复杂,这套逻辑很快就会变得又长又散: 每个地方…...

ComfyUI Manager:3步打造你的AI绘画插件生态圈

ComfyUI Manager:3步打造你的AI绘画插件生态圈 【免费下载链接】ComfyUI-Manager ComfyUI-Manager is an extension designed to enhance the usability of ComfyUI. It offers management functions to install, remove, disable, and enable various custom nodes…...

FastAPI多服务器管理框架:MCP模式实现分布式服务集中运维

1. 项目概述:一个为FastAPI应用设计的MCP多服务器管理框架 最近在重构一个基于FastAPI的微服务项目时,遇到了一个挺典型的痛点:随着业务模块的拆分,我们手头管理着十几个独立的FastAPI服务实例。每次部署、重启、查看日志&#xf…...

3步解锁老旧Mac新生命:OpenCore Legacy Patcher硬件适配全指南

3步解锁老旧Mac新生命:OpenCore Legacy Patcher硬件适配全指南 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 你是否拥有一台性能依然强劲但被苹…...

WP-CLI MCP:用AI智能体自然语言管理WordPress的实践指南

1. 项目概述:当WordPress开发者拥抱AI智能体如果你是一个深度使用WordPress的开发者或站长,那么对WP-CLI这个命令行工具一定不会陌生。它让我们摆脱了后台界面的束缚,通过一行行命令就能高效地管理站点、操作数据库、更新插件主题。但今天要聊…...

Kleiber:Claude Code智能体编排框架实战,解决角色混乱与成本失控

1. 项目概述:Kleiber,为Claude Code打造的智能体编排框架 如果你和我一样,是Claude Code的深度用户,那你一定对它的原生“智能体团队”功能又爱又恨。爱的是,它第一次让一个AI能像真正的开发团队一样分工协作&#xff…...

如何快速解密QQ音乐文件:qmc-decoder终极指南

如何快速解密QQ音乐文件:qmc-decoder终极指南 【免费下载链接】qmc-decoder Fastest & best convert qmc 2 mp3 | flac tools 项目地址: https://gitcode.com/gh_mirrors/qm/qmc-decoder 你是否曾经下载了QQ音乐文件,却发现只能在特定播放器里…...

风管制作的自动化技术升级:效率与精度提升

风管在暖通系统中扮演着至关重要的角色,它负责空气的输送与分配,其质量和性能直接影响着整个暖通系统的运行效果。随着科技的不断进步,风管制作的自动化技术也在持续升级,以满足更高的效率与精度要求。江苏顺锦暖通设备有限公司作…...

谷歌DeepMind少数股权投资《星战前夜:晨曦》开发商,借游戏探索AI新边界

谷歌DeepMind 1.2亿背后:游戏与AI的跨界联姻 谷歌专注于人工智能的DeepMind部门对热门科幻模拟游戏《星战前夜:晨曦》的开发商进行了少数股权投资。与此同时,《星战前夜:晨曦》开发商CCP Games的管理层斥资1.2亿美元从韩国发行商P…...

2026年天门财务新选择:专业服务,值得信赖!

在当前经济环境下,财务管理对于企业的成功至关重要。无论是初创企业还是成熟企业,都需要专业的财务团队来帮助他们处理复杂的财务问题。天门市大掌柜财务咨询有限公司(以下简称“大掌柜”)作为一家专业的财务咨询公司,…...

为AI编程助手集成Tmux与多模型咨询,打造可执行代码的伪代码REPL

1. 项目概述:为AI助手装上“手”和“脑”如果你和我一样,日常重度依赖像Cursor这样的AI编程助手,那你肯定也遇到过类似的瓶颈:当你想让它帮你跑一段代码、监控一个长期实验,或者在一个复杂的交互式环境(比如…...

TypeScript 对列,实现消息队列(FIFO显示+定时清理)

使用对列实现消息接收显示与清除, 根据消息的【显示时间】来清除,显示超过 10 秒的自动清理,未显示、显示不足 10 秒的都保留线程安全 Queue/*** 纯先进先出(FIFO)队列独立实现* 支持:入队、出队、查看队头…...

[Deep Agents:LangChain的Agent Harness-01]LangChain、LangGraph和Deep Agents三者之间的关系

Deep Agents是LangChain团队在2025年正式发布的一个开源Agent框架,专门用于构建能够处理生产级、长时程、多步骤任务的深度Agent。与传统的浅层Agent(仅依赖 LLM 简单工具调用循环)不同,Deep Agents 旨在模拟像Claude Code或Deep…...

开源ChatGPT API管理界面部署与定制指南

1. 项目概述:一个为开发者打造的轻量级ChatGPT API管理界面如果你正在寻找一个能快速部署、功能纯粹且完全掌控在自己手中的ChatGPT API交互界面,那么patrikzudel/PatrikZeros-ChatGPT-API-UI这个开源项目绝对值得你花时间研究。它不是一个功能庞杂的“全…...

特斯拉Model 3/Y CAN总线DBC文件完整指南:轻松读懂车辆数据语言

特斯拉Model 3/Y CAN总线DBC文件完整指南:轻松读懂车辆数据语言 【免费下载链接】model3dbc DBC file for Tesla Model 3 CAN messages 项目地址: https://gitcode.com/gh_mirrors/mo/model3dbc 想要深入了解特斯拉车辆的智能控制系统吗?Model3DB…...

3篇3章2节:Obsidian 的下载安装和主页面介绍

本文将从零开始,完整讲解 Obsidian 官方下载方式、软件初始化界面含义、三大核心界面区域功能、所有图标作用,以及仓库位置的完整设置流程。让零基础的你也能一次性吃透 Obsidian 基础操作,为后续双链笔记、插件进阶、知识体系搭建打下扎实基…...

Weaviate向量数据库实战:从核心原理到RAG应用部署

1. 从零到一:理解向量数据库与Weaviate的核心价值如果你最近在捣鼓大语言模型应用,比如想自己搭一个智能客服或者文档问答系统,大概率会听到“向量数据库”这个词。听起来挺高大上,但说白了,它解决的是一个很实际的问题…...

小众却封神的双语字幕工具

挖到一款冷门但巨好用的电脑宝藏插件✨讯飞同传双语字幕插件完美解决看外文、开国际会议的所有烦恼全局悬浮双语字幕,任意窗口都能用AI 智能语音降噪,嘈杂环境识别依旧精准覆盖超多国家语种,翻译自然接地气适配腾讯会议、钉钉、网课、本地视频…...

Quixel Mixer本地材质库管理全攻略:从下载、整理到备份,告别资源混乱

Quixel Mixer本地材质库管理全攻略:从下载、整理到备份,告别资源混乱 打开Quixel Mixer的Local Library时,你是否经常面对满屏未分类的材质球感到无从下手?当硬盘空间告急时,又是否在纠结哪些材质可以安全删除&#xf…...

将Claude Code编程助手无缝对接至Taotoken服务的详细配置步骤

将Claude Code编程助手无缝对接至Taotoken服务的详细配置步骤 1. 准备工作:获取必要的凭证 在开始配置之前,您需要在Taotoken平台上准备好两个关键信息:API Key和模型ID。 首先,登录Taotoken控制台,在API密钥管理页…...

Python网络资源下载工具downcity:模块化设计与高性能并发实践

1. 项目概述与核心价值最近在折腾一个挺有意思的项目,叫“wangenius/downcity”。乍一看这个名字,可能有点摸不着头脑,但如果你经常需要从各种网站批量下载图片、视频、文档,或者搞点数据采集、内容归档,那你大概率会和…...