MongoDB性能调优

news2024/12/26 23:07:29

文章目录

  • MongoDB性能调优
    • MongoDB性能不佳原因
    • 影响MongoDB性能的因素
    • MongoDB性能监控工具
      • mongostat
      • mongotop
      • Profiler模块
      • db.currentOp()

MongoDB性能调优

MongoDB性能不佳原因

  1. 慢查询
  2. 阻塞等待
  3. 硬件资源不足

1,2通常是因为模型/索引设计不佳导致的

排查思路:按1-2-3依次排查



影响MongoDB性能的因素

processon在线图

  • 首先需要排除客户端到服务端的网络问题
  • 注意客户端与服务端 版本兼容问题

在这里插入图片描述



MongoDB性能监控工具

mongostat

下载地址:https://www.mongodb.com/try/download/database-tools

mongostat是MongoDB自带的监控工具,其可以提供数据库节点或者整个集群当前的状态视图。

在这里插入图片描述



该功能的设计非常类似于Linux系统中的vmstat命令,可以呈现出实时的状态变化。不同的是,mongostat所监视的对象是数据库进程。mongostat常用于查看当前的QPS/内存使用/连接数,以及多个分片的压力分布。mongostat采用Go语言实现,其内部使用了db.serverStatus()命令,要求执行用户需具备clusterMonitor角色权限

mongostat -h 192.168.75.100 --port 28017 -u hushang -p 123456 --authenticationDatabase=admin --discover -n 300 2

参数说明:

  • -h:指定监听的主机,分片集群模式下指定到一个mongos实例,也可以指定单个mongod,或者复制集的多个节点。
  • –port:接入的端口,如果不提供则默认为27017。
  • -u:接入用户名,等同于-user。
  • -p:接入密码,等同于-password。
  • –authenticationDatabase:鉴权数据库。
  • –discover:启用自动发现,可展示集群中所有分片节点的状态。
  • -n 300 2:表示输出300次,每次间隔2s。也可以不指定“-n 300”,此时会一直保持输出。




在这里插入图片描述

指标名说明
inserts每秒插入数
query每秒查询数
update每秒更新数
delete每秒删除数
getmore每秒getmore数
command每秒命令数,涵盖了内部的一些操作
%dirtyWiredTiger缓存中脏数据百分比
%usedWiredTiger 正在使用的缓存百分比,也就是分配给WiredTiger存储引擎的内存使用情况
flushesWiredTiger执行CheckPoint的次数
vsize虚拟内存使用量
res物理内存使用量
qrw客户端读写等待队列数量,高并发时,一般队列值会升高
arw客户端读写活跃个数
netIn网络接收数据量
netOut网络发送数据量
conn当前连接数
set所属复制集名称
repl复制节点状态(主节点/二级节点……)
time时间戳



mongostat需要关注的指标主要有如下几个:

  • 插入、删除、修改、查询的速率是否产生较大波动,是否超出预期。
  • qrw、arw:队列是否较高,若长时间大于0则说明此时读写速度较慢。
  • conn:连接数是否太多。
  • dirty:百分比是否较高,若持续高于10%则说明磁盘I/O存在瓶颈。
  • netIn、netOut:是否超过网络带宽阈值。
  • repl:状态是否异常,如PRI、SEC、RTR为正常,若出现REC等异常值则需要修复。



使用交互模式

mongostat一般采用滚动式输出,即每一个间隔后的状态数据会被追加到控制台中。从MongoDB 3.4开始增加了--interactive选项,用来实现非滚动式的监视,非常方便。

# 该命令我本机运行有问题
mongostat -h 192.168.75.100 --port 28017 -u hushang -p hushang --authenticationDatabase=admin --discover --interactive -n 2

在这里插入图片描述



mongotop

mongotop命令可用于查看数据库的热点表,通过观察mongotop的输出,可以判定是哪些集合占用了大部分读写时间。mongotop与mongostat的实现原理类似,同样需要clusterMonitor角色权限。

# 默认情况下,mongotop会持续地每秒输出当前的热点表
mongotop -h 192.168.75.100 --port=28017 -u hushang -p 123456 --authenticationDatabase=admin
# 在mongosh端 执行一些插入语句进行测试
rs0 [direct: primary] admin> for(var i = 0;i<5000;i++){db.emp.insertOne({name: "hushang"+i})}



在这里插入图片描述

指标说明:

指标名说明
ns集合名称空间
total花费在该集合上的时长
read花费在该集合上的读操作时长
write花费在该集合上的写操作时长



mongotop通常需要关注的因素主要包括:

  • **热点表操作耗费时长是否过高。**这里的时长是在一定的时间间隔内的统计值,它代表某个集合读写操作所耗费的时间总量。在业务高峰期时,核心表的读写操作一般比平时高一些,通过mongotop的输出可以对业务尖峰做出一些判断。
  • **是否存在非预期的热点表。**一些慢操作导致的性能问题可以从mongotop的结果中体现出来



mongotop的统计周期、输出总量都是可以设定的

#最多输出100次,每次间隔时间为2s
mongotop -h 192.168.75.100 --port=28017 -u hushang -p 123456 --authenticationDatabase=admin -n 100 2



Profiler模块

Profiler模块可以用来记录、分析MongoDB的详细操作日志。默认情况下该功能是关闭的,对某个业务库开启Profiler模块之后,符合条件的慢操作日志会被写入该库的system.profile集合中。

Profiler的设计很像代码的日志功能,其提供了几种调试级别:

级别说明
0日志关闭,无任何输出
1部分开启,仅符合条件(时长大于slowms)的操作日志会被记录
2日志全开,所有的操作日志都被记录



对当前的数据库开启Profiler模块:

# 将level设置为2,此时所有的操作会被记录下来。
db.setProfilingLevel(2)
#检查是否生效
db.getProfilingStatus()

在这里插入图片描述



  • was当前级别
  • slowms是慢操作的阈值,单位是毫秒;
  • sampleRate表示日志随机采样的比例,1.0则表示满足条件的全部输出。



如果希望只记录时长超过500ms的操作,则可以将level设置为1

db.setProfilingLevel(1,500)

还可以进一步设置随机采样的比例

db.setProfilingLevel(1,{slowms:500,sampleRate:0.5})



查看操作日志

开启Profiler模块之后,可以通过system.profile集合查看最近发生的操作日志

db.system.profile.find().limit(5).sort({ts:-1}).pretty()

具体操作如下

# 开启profile后手动插入一条记录
rs0 [direct: primary] test> db.emp.insertOne({username: "hushang", age: 24})
{
  acknowledged: true,
  insertedId: ObjectId("66ab0978c301fc0d4a5343e2")
}

# 在执行一次查询
rs0 [direct: primary] test> db.emp.find()

# 接下来查询profile的数据
rs0 [direct: primary] test> db.system.profile.find().limit(5)
[
  {
    op: 'insert',				# 操作类型,描述增加、删除、修改、查询。
    ns: 'test.emp',			# 名称空间,格式为{db}.{collection}。
    command: {				# 原始的命令文档。
      insert: 'emp',
      documents: [
        {
          username: 'hushang',
          age: 24,
          _id: ObjectId("66ab0978c301fc0d4a5343e2")
        }
      ],
      ordered: true,
      lsid: { id: new UUID("a7724286-4b53-43a0-a827-bec1cc00c81d") },
      txnNumber: Long("1"),
      '$clusterTime': {
        clusterTime: Timestamp({ t: 1722485085, i: 3 }),
        signature: {
          hash: Binary(Buffer.from("0000000000000000000000000000000000000000", "hex"), 0),
          keyId: Long("0")
        }
      },
      '$db': 'test'
    },
    ninserted: 1,
    keysInserted: 1,
    numYield: 0,    # 操作数,大于0表示等待锁或者是磁盘I/O操作。
    locks: {   # 锁占用的情况。
      ParallelBatchWriterMode: { acquireCount: { r: Long("3") } },
      FeatureCompatibilityVersion: { acquireCount: { r: Long("3"), w: Long("2") } },
      ReplicationStateTransition: { acquireCount: { w: Long("4") } },
      Global: { acquireCount: { r: Long("3"), w: Long("2") } },
      Database: { acquireCount: { w: Long("2") } },
      Collection: { acquireCount: { w: Long("2") } },
      Mutex: { acquireCount: { r: Long("4") } }
    },
    flowControl: { acquireCount: Long("1"), timeAcquiringMicros: Long("1") },
    readConcern: { provenance: 'implicitDefault' },
    writeConcern: { w: 2, wtimeout: 0, provenance: 'customDefault' },
    responseLength: 230,   # 响应数据大小(字节数),一次性查询太多的数据会影响性能
    protocol: 'op_msg',
    millis: 3,      	# 命令执行的时长,单位是毫秒。
    ts: ISODate("2024-08-01T04:05:12.985Z"),
    client: '127.0.0.1',
    appName: 'mongosh 1.8.0',
    allUsers: [ { user: 'hushang', db: 'admin' } ],
    user: 'hushang@admin'
  },
  {
    op: 'query',   		# 操作类型,描述增加、删除、修改、查询。
    ns: 'test.emp',		# 名称空间,格式为{db}.{collection}。
    command: {			# 原始的命令文档。
      find: 'emp',
      filter: {},
      lsid: { id: new UUID("a7724286-4b53-43a0-a827-bec1cc00c81d") },
      '$clusterTime': {
        clusterTime: Timestamp({ t: 1722485626, i: 1 }),
        signature: {
          hash: Binary(Buffer.from("0000000000000000000000000000000000000000", "hex"), 0),
          keyId: Long("0")
        }
      },
      '$db': 'test'
    },
    cursorid: Long("5929651518194517166"),		# 游标ID。
    keysExamined: 0,		# 扫描索引条目数,如果比 nreturned 大出很多,则说明查询效率不高。
    docsExamined: 101,		# 扫描文档条目数,如果比nreturned大出很多,则说明查询效率不高。
    numYield: 0,			# 操作数,大于0表示等待锁或者是磁盘I/O操作。
    nreturned: 101,			# 返回条目数。 因为我之前新增过一些数据
    queryHash: '17830885',
    queryFramework: 'classic',
    locks: {				# 锁占用的情况。
      FeatureCompatibilityVersion: { acquireCount: { r: Long("1") } },
      Global: { acquireCount: { r: Long("1") } },
      Mutex: { acquireCount: { r: Long("1") } }
    },
    flowControl: {},
    readConcern: { level: 'local', provenance: 'implicitDefault' },
    responseLength: 4976,		# 响应数据大小(字节数),一次性查询太多的数据会影响性能
    protocol: 'op_msg',
    millis: 0,				# 命令执行的时长,单位是毫秒。
    planSummary: 'COLLSCAN',		# 查询计划的概要,如IXSCAN表示使用了索引扫描。 COLLSCAN表示全表扫描
    execStats: {					# 执行过程统计信息。
      stage: 'COLLSCAN',			# 查询计划的概要,如IXSCAN表示使用了索引扫描。 COLLSCAN表示全表扫描
      nReturned: 101,			# 返回条目数。
      executionTimeMillisEstimate: 0,
      works: 102,
      advanced: 101,
      needTime: 1,
      needYield: 0,
      saveState: 1,
      restoreState: 0,
      isEOF: 0,
      direction: 'forward',
      docsExamined: 101
    },
    ts: ISODate("2024-08-01T04:14:15.763Z"),   # 命令执行的时间点。
    client: '127.0.0.1',
    appName: 'mongosh 1.8.0',
    allUsers: [ { user: 'hushang', db: 'admin' } ],
    user: 'hushang@admin'
  }
]

这里需要关注的一些字段主要如下所示:

  • op:操作类型,描述增加、删除、修改、查询。
  • ns:名称空间,格式为{db}.{collection}。
  • Command:原始的命令文档。
  • Cursorid:游标ID。
  • numYield:操作数,大于0表示等待锁或者是磁盘I/O操作。
  • nreturned:返回条目数。
  • keysExamined:扫描索引条目数,如果比nreturned大出很多,则说明查询效率不高。
  • docsExamined:扫描文档条目数,如果比nreturned大出很多,则说明查询效率不高。
  • locks:锁占用的情况。
  • storage:存储引擎层的执行信息。
  • responseLength:响应数据大小(字节数),一次性查询太多的数据会影响性能,可以使用limit、batchSize进行一些限制。
  • millis:命令执行的时长,单位是毫秒。
  • planSummary:查询计划的概要,如IXSCAN表示使用了索引扫描。
  • execStats:执行过程统计信息。
  • ts:命令执行的时间点。
# 根据这些字段,可以执行一些不同维度的查询。比如查看执行时长最大的10条操作记录
db.system.profile.find().limit(10).sort({millis:-1}).pretty()

# 查看某个集合中的update操作日志
db.system.profile.find({op:"update",ns:"test.emp"})



注意事项

  • system.profile是一个1MB的固定大小的集合,随着记录日志的增多,一些旧的记录会被滚动删除。
  • 在线上开启Profiler模块需要非常谨慎,这是因为其对MongoDB的性能影响比较大。建议按需部分开启,同时slowms的值不要设置太低。
  • sampleRate的默认值是1.0,该字段可以控制记录日志的命令数比例,但只有在MongoDB 4.0版本之后才支持。
  • Profiler模块的设置是内存级的,重启服务器后会自动恢复默认状态。



db.currentOp()

Profiler模块所记录的日志都是已经发生的事情,db.currentOp()命令则与此相反,它可以用来查看数据库当前正在执行的一些操作。

想象一下,当数据库系统的CPU发生骤增时,我们最想做的无非是快速找到问题的根源,这时db.currentOp就派上用场了。

db.currentOp()读取的是当前数据库的命令快照,该命令可以返回许多有用的信息,比如:

  • 操作的运行时长,快速发现耗时漫长的低效扫描操作。
  • 执行计划信息,用于判断是否命中了索引,或者存在锁冲突的情况。
  • 操作ID、时间、客户端等信息,方便定位出产生慢操作的源头。



opid表示当前操作在数据库进程中的唯一编号。如果已经发现该操作正在导致数据库系统响应缓慢,则可以考虑将其“杀”死

db.killOp(4001)



db.currentOp默认输出当前系统中全部活跃的操作,由于返回的结果较多,我们可以指定一些过滤条件:

# 查看等待锁的增加、删除、修改、查询操作
db.currentOp({
    waitingForLock:true,
    $or:[
        {op:{$in:["insert","update","remove"]}},
        {"query.findandmodify":{$exists:true}}
    ]
})



查看执行时间超过1s的操作

db.currentOp({
    secs_running:{$gt:1}
})



查看test数据库中的操作

db.currentOp({
    ns: /test/
})



在这里插入图片描述

在这里插入图片描述

在这里插入图片描述



对示例操作的解读如下:

(1)从ns、op字段获知,当前进行的操作正在对test.items集合执行update命令。

(2)command字段显示了其原始信息。其中,command.q和command.u分别展示了update的查询条件和更新操作。

(3)“planSummary”:“COLLSCAN” 说明情况并不乐观,update没有利用索引而是正在全表扫描。

(4)microsecs_running:NumberLong(186070)表示操作运行了186ms,注意这里的单位是微秒。

优化方向:

  • value字段加上索引
  • 如果更新的数据集非常大,要避免大范围update操作,切分成小批量的操作



currentOp命令输出说明

  • currentOp.type:操作类型,可以是op、idleSession、idleCursor的一种,一般的操作信息以op表示。其为MongoDB 4.2版本新增功能。
  • currentOp.host:主机的名称。currentOp.desc:连接描述,包含connectionId。currentOp.connectionId:客户端连接的标识符。currentOp.client:客户端主机和端口。currentOp.appName:应用名称,一般是描述客户端类型。
  • currentOp.clientMetadata:关于客户端的附加信息,可以包含驱动的版本。currentOp.currentOpTime:操作的开始时间。MongoDB 3.6版本新增功能。
  • currentOp.lsid:会话标识符。MongoDB 3.6版本新增功能。
  • currentOp.opid:操作的标志编号。
  • currentOp.active:操作是否活跃。如果是空闲状态则为false。
  • currentOp.secs_running:操作持续时间(以秒为单位)。
  • currentOp.microsecs_running:操作持续时间(以微秒为单位)。
  • currentOp.op:标识操作类型的字符串。可能的值是:“none” “update” “insert”“query”“command” “getmore” “remove” “killcursors”。其中,command操作包括大多数命令,如createIndexes和findAndModify。
  • currentOp.ns:操作目标的集合命名空间。
  • currentOp.command:操作的完整命令对象的文档。如果文档大小超过1KB,则会使用一种$truncate形式表示。
  • currentOp.planSummary:查询计划的概要信息。
  • currentOp.locks:当前操作持有锁的类型和模式。
  • currentOp.waitingForLock:是否正在等待锁。
  • currentOp.numYields:当前操作执行yield(让步)的次数。一些锁互斥或者磁盘I/O读取都会导致该值大于0。
  • currentOp.lockStats:当前操作持有锁的统计。
  • currentOp.lockStats.acquireCount:操作以指定模式获取锁的次数。
  • currentOp.lockStats.acquireWaitCount:操作获取锁等待的次数,等待是因为锁处于冲突模式。acquireWaitCount小于或等于acquireCount。
  • currentOp.lockStats.timeAcquiringMicros:操作为了获取锁所花费的累积时间(以微秒为单位)。timeAcquiringMicros除以acquireWaitCount可估算出平均锁等待时间。
  • currentOp.lockStats.deadlockCount:在等待锁获取时,操作遇到死锁的次数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1969774.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

再论国产数据库的选择

如何选择国产数据库? 上篇写得很水,本来不想继续写了! 毕竟写一篇很费心力,大家觉得好,就点下广告支持下吧! 因为今天看到类总的朋友圈,发个公号文章.里面讲个故事, 数据最前线 关注数据生态&#xff0c;讲述开源故事 13篇原创内容 公众号 某国产数据库救援现场惊魂8小时…

Golang | Leetcode Golang题解之第313题超级丑数

题目&#xff1a; 题解&#xff1a; func nthSuperUglyNumber(n int, primes []int) int {dp : make([]int, n1)m : len(primes)pointers : make([]int, m)nums : make([]int, m)for i : range nums {nums[i] 1}for i : 1; i < n; i {minNum : math.MaxInt64for j : range…

【大模型框架】【推理加速】KV CACHE

1. 思想 核心思想是空间换时间来进行加速 2. 基本原理 transformer是自回归生成模型&#xff0c;abc三个字符预测def 过程是: abc -> d d进行回归得到abc,回归讲究的是回去&#xff0c;如香港回归 abcd -> e 这里abc的运算中间值Q V可以保存下来作为Cache&#xf…

爬猫眼电ying

免责声明:本文仅做分享... 未优化,dp简单实现 from DrissionPage import ChromiumPage import time urlhttps://www.maoyan.com/films?showType2&offset60 pageChromiumPage()page.get(url) time.sleep(2) for i in range(1,20):# 爬取的页数for iu_list in page.eles(.…

c语言指针中“数组名的理解”以及“一维数组传参”的本质

数组名的理解 数组名就是数组首元素的地址。 例如&#xff1a;输入一个数组的所有元素&#xff0c;再打印出来。 另一种写法 以上可以看出&#xff1a;*arri&#xff09; arr[i] 也即是&#xff1a;*(iarr)i[arr] 本质上无区别 1&#xff1a;数组就是数组&#xff0c;是一块…

List 31

ArrayList底层原理 Linkedlist的底层原理 使用场景

扎克伯格说Meta训练Llama 4所需的计算能力是Llama 3的10倍

Meta 公司开发了最大的基础开源大型语言模型之一 Llama&#xff0c;该公司认为未来将需要更强的计算能力来训练模型。马克-扎克伯格&#xff08;Mark Zuckerberg&#xff09;在本周二的 Meta 第二季度财报电话会议上表示&#xff0c;为了训练 Llama 4&#xff0c;公司需要比训练…

做管理,一定要避开这6个坑,才能成就优秀管理者

做管理&#xff0c;一定要避开这6个坑&#xff0c;才能成就优秀管理者 一、被平庸的员工绑架 要是领导不敢或者不愿意惩罚或者开除那些没完成任务的员工&#xff0c;那优秀的员工就会觉得&#xff0c;做得好做得差都一样&#xff0c;那谁还愿意努力呢&#xff1f; 二、总想改变…

【Mind+】掌控板入门教程01 “秀”出我创意

我们的好朋友麦乐佳即将举办一场派对&#xff0c;她要求每个参加派对的人都要佩戴一个可以彰显自己独特创意的装置。可以是会发光的帽子&#xff0c;可以是复古的电子表&#xff0c;还可以是其他有创意的作品。而现在&#xff0c;我们的手边刚好有一块掌控板&#xff0c;它自带…

汇聚数字智慧 构建新质未来——《CMG数字中国》融媒体节目正式上线

7月25日&#xff0c;由中央广播电视总台上海总站、央视频和数创未来&#xff08;上海&#xff09;传媒科技有限公司联合打造的《CMG数字中国》融媒体节目正式上线。 中国共产党第二十届中央委员会第三次全体会议提出&#xff0c;高质量发展是全面建设社会主义现代化国家的首要…

8.Redis的List类型

Redis中的list跟java中的LinkedList比较相似&#xff0c;可以看做是一个双向链表的结构。 既可以支持正向检索和反向检索。 特点 1.有序 2.元素可以重复 3.插入和删除快 4.查询速度一般 应用场景 点赞和评论功能&#xff0c;都会存在一个顺序&#xff0c;谁先评论&…

AI Agent学习系列:扣子智能体手把手入门教程

AI智能体为什么现在这么火&#xff1f;我个人认为有以下几点原因&#xff1a; 智能体基于大模型而又强于大模型&#xff08;垂直领域&#xff09; 智能体基于零代码或者低代码模式&#xff0c;不需要编程基础&#xff0c;对于非程序员非常友好&#xff0c;使得大多数人都能成…

CoderGuide

CoderGuide是一个针对同学们前后端求职面试的开源项目&#xff0c;作为一名互联网/IT从业人员&#xff0c;经常需要搜索一些书籍、面试题等资源&#xff0c;在这个过程中踩过很多坑、浪费过很多时间。欢迎大家 Watch、Star&#xff0c;供各位同学免费使用&#xff0c;永不收费&…

【Python】pandas:替换值、添加行/列,删除行/列,更改形状(含数据透视表)

pandas是Python的扩展库&#xff08;第三方库&#xff09;&#xff0c;为Python编程语言提供 高性能、易于使用的数据结构和数据分析工具。 pandas官方文档&#xff1a;User Guide — pandas 2.2.2 documentation (pydata.org) 帮助&#xff1a;可使用help(...)查看函数说明文…

9.Redis的Set类型

Redis的Set结构与java中的HashSet类似。 可以看做是一个value为null的HashMap。 特点 1.无序 2.元素不可重复 3.查找快 4.支持交集、并集、差集等功能 应用场景 实现共同关注&#xff0c;共同好友。 常见命令 sadd key 元素1 元素2 给set集合添加一个或多个元素 smem…

Node.js(2)——压缩前端html

需求&#xff1a;把回车符&#xff08;\r&#xff09;和换行符&#xff08;\n&#xff09;去掉后&#xff0c;写入到新的html文件中 步骤&#xff1a; 读取源html文件内容正则替换字符串写入到新的html文件中 示例&#xff1a; 获取html文件中的内容并检查&#xff08;同时…

temu电商的选品师能当成副业做吗?

在当今充满机会的电商行业中&#xff0c;成为一名选品师是否适合作为副业呢?这是一个颇具吸引力的问题&#xff0c;特别是对于那些希望在自由职业和兼职之间寻找平衡的人群。TEMU电商平台的选品师角色&#xff0c;不仅涉及到产品的挑选&#xff0c;还包括市场研究、竞争分析以…

DevOps之Jenkins的CICD

文章目录 CI&CD架构Jenkins介绍GitLab安装SonarQube安装Harbor安装目标服务器的安装与配置Jenkins安装Jenkins集成SonarQube与targetJenkins集成Gitlab推送代码到目标服务器构建项目镜像 CI&CD架构 Jenkins介绍 Jenkins是一个独立的开源软件项目&#xff0c;是基于Java…

IIS解析漏洞~IIS6.X漏洞分析

类型代码量作用一句话木马代码量极少配合webshell管理工具使用小马代码量比小马多大马代码量最多功能比较完善&#xff08;执行命令&#xff0c;文件操作等&#xff09;图片马里面传有一句话木马 文件解析漏洞是由于中间件错误的将特殊格式的文件解析成可执行网页文件(脚本)&am…

学习记录(8):RAG and PAL and ReAct

咱就是说 习惯了做笔记 不做笔记 这知识真的是一点记不住啊&#xff08;实则是脑子笨0.o 那咱就狠狠的来记住这个知识点0.o 参考学习&#xff1a;B站GenJi是真想教会你-《【包教包会】一条视频速通AI大模型原理》 文章目录 一、RAG&#xff1a;检索增强生成二、PAL&#xff1a…