news 2026/10/21 16:32:51

慢SQL优化实战:从索引策略到执行计划的性能排查指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
慢SQL优化实战:从索引策略到执行计划的性能排查指南

凌晨一点,电话响了。业务方声音焦急:用户端查询订单列表的接口从平时的200毫秒变成了3秒,后台管理系统的月度报表查询更是跑了两分钟还没出结果。我打开慢查询日志,几条执行时间接近20秒的SQL赫然列在最前面。

这就是典型的慢SQL问题。很多人一听到"SQL优化"就觉得高深,觉得是DBA的专职工作,实际上大部分线上性能问题的根因并不神秘——要么索引设计不合理,要么查询写法让优化器没法定向走索引,要么数据量涨到了某个临界点导致原有的执行计划整体失效。这篇文章就结合实际排查和优化过程,从索引策略讲到具体调优手法,覆盖慢SQL定位、执行计划解读、索引设计思路、并行优化场景和日常防坑经验,希望能帮正在被慢查询困扰的人理清思路。

1. 慢SQL为什么会突然出现:数据量与执行计划的双重拐点

很多团队对慢SQL的第一反应是"加索引"。这个方向没错,但如果搞不清为什么以前快的查询突然慢了,加索引也只是碰运气。我的经验是,慢SQL的出现往往有两个叠加的拐点。

第一个拐点是数据量的量级跃迁。一条查询在10万行数据时走全表扫描可能也就几十毫秒,用户感知不明显。但同一张表涨到500万行、1000万行时,全表扫描的代价呈线性甚至超线性增长,尤其是涉及多表关联、大字段回表的时候,响应时间可能直接从几百毫秒恶化到几十秒。MySQL里有一类默认规则:当优化器估算需要扫描的行数超过全表的一定比例(通常是20%到30%),它就会放弃索引选择全表扫描,因为此时离散IO的成本高于顺序IO。这个拐点非常隐蔽,哪怕索引还在,执行计划也可能已经变了。

第二个拐点是执行计划的漂移。优化器选择索引的依据是统计信息和代价估算。统计信息不更新、字段的数据分布发生变化(比如某个状态值从1%变成50%)、或者查询条件里的参数值改变了选择性,都会导致优化器换一个低效的执行路径。我遇到过最典型的情况:一个order_status字段,平时99%都是completed,查询条件传pending时走索引很快;某天大促期间pending的订单量暴涨到30%,优化器一看估算扫描行数太多,直接选择了全表扫描,结果线上接口瞬间雪崩。

所以做SQL优化的第一个动作不是改SQL,而是先确认:这条SQL一直慢,还是最近才变慢?如果是一直慢,大概率是索引策略从一开始就没设计对;如果是变慢,优先检查数据量变化、统计信息新鲜度和执行计划是否漂移。定位问题的时间点,和解决问题同样重要。

2. 索引策略的核心逻辑:从B+树原理到联合索引的匹配规则

索引不是加得越多越好,也不是随便给查询条件字段加个索引就万事大吉。要设计好索引,得先理解索引为什么能加速,以及它加速的边界在哪里。

2.1 B+树索引加速的本质:减少无效数据的访问

MySQL的InnoDB索引底层是B+树。它的核心优势有两个:一是树的高度低,一般是2到4层,意味着定位到一条记录最多只需要几次磁盘IO;二是叶子节点之间通过链表相连,对范围查询非常友好。很多人忽略了一点:B+树在InnoDB里既存储索引,也存储数据本身。聚簇索引(主键索引)的叶子节点直接存整行数据,二级索引(普通索引)的叶子节点存的是索引列和主键值。

这个结构决定了重要规律:走二级索引查询时,如果目标列不在二级索引里,每次拿到主键后都要再回聚簇索引取一行完整数据,这就是回表开销。回表次数少还好,如果满足条件的记录有上万条,哪怕每条回表只要0.1毫秒,累加起来也是1秒以上的额外耗时。这也是为什么覆盖索引如此重要——查询的列全部包含在二级索引的叶子节点里,数据库直接返回索引数据,连回表都省了。

2.2 联合索引设计:等值匹配、最左前缀和排序利用

联合索引(多列索引)的设计是索引策略里最有技术含量的一环。很多新人常见的困惑是:"我在三个字段上分别建了单列索引,查询时它们应该都会生效吧?" 答案是否定的。MySQL在一个查询里通常只会选择一个索引执行,把三个独立索引(a、b、c)和一个(a,b,c)联合索引混为一谈是常见误区。

联合索引的本质是逐列比较排序,所以它遵守最左前缀原则:查询条件里必须包含联合索引的第一个字段,索引才能被用到。比如索引(a,b,c),只有条件覆盖a、(a,b)、(a,b,c)时能走索引;直接查b或c,索引基本用不上。

设计联合索引时,我通常按这个顺序确认字段:

  1. 可等值匹配的字段放最前。比如user_id通常是等值条件,优先放第一位。
  2. 把选择性高的字段放前面。选择性是指字段去重后的比值,比如status只有"成功、失败、处理中"三种值,选择性极低,放最前反而让索引区分度变差。
  3. 利用索引避免排序。B+树的叶子本身有序,如果查询条件里带了ORDER BY,且排序字段正好是索引的后续列,就能避免文件排序。比如(user_id, create_time)这个索引,在WHERE user_id = 123 ORDER BY create_time场景下,本身就是按时间排好的,直接顺序读取返回就行。

有一种反直觉的情况也值得注意:把选择性低的字段放在联合索引前面,有时候反而是正确的。比如WHERE status = 'pending' AND create_time > '2024-04-01',如果时间列的选择性明显更高,我们会倾向把create_time放前面。但实际还要考虑等值条件与范围条件的区别——等值字段放前面可以让后续字段继续保序,而范围条件字段放前面会导致后面的字段无法参与索引匹配,所以这类查询把等值的status放前面,create_time放在后面,利用范围扫描,效果往往更好。

2.3 索引下推:一个容易忽略的性能红利

说到联合索引,就不得不提索引下推(Index Condition Pushdown)。这个机制看着抽象,其实特别好理解:以前当索引里只有部分列时,引擎用索引定位到一批主键后,会把整行数据捞出来逐条检查剩余条件,这被称为"先捞后筛"。开启索引下推后,引擎直接在索引层面把不满足条件的记录先过滤掉,再回表。这意味着回表次数大幅减少。

举个实际数字。索引是(a,b),查询条件是a = 1 AND b > 100。没有索引下推时,把所有a = 1的记录全部回表,然后再过滤b > 100;有索引下推时,直接在二级索引里同时判断a和b,回表的只有满足b > 100的极少量记录。在MySQL 5.6之后默认开启,如果查看执行计划看到Extra列里有Using index condition,就说明这条SQL已经吃到了这个红利,性能比普通的回表扫描要好很多。

3. 慢SQL排查的完整链路:从日志定位到执行计划定量分析

索引策略理论再熟,线上排查还是得靠工具和流程。我处理慢SQL有一套固定的动作,可以说80%的案例按这个流程走都能找到根因。

3.1 第一步:先把慢查询捞出来

MySQL的慢查询日志是最直接的切入点。生产环境一般建议打开慢查询日志,并设置阈值,我习惯设成1秒:

SET GLOBAL slow_query_log = ON; SET GLOBAL long_query_time = 1; SET GLOBAL log_queries_not_using_indexes = ON;

第一条开启慢查询日志,第二条定义超过1秒的SQL就会被记录。要注意这个参数对已有连接不生效,需要新开的会话才会按新阈值记录,或者直接改配置文件后重启。日志里能看到实际的SQL、执行时间、锁等待时间、返回行数、扫描行数。我通常先看两个数字:扫描行数和返回行数的比值。一条SQL扫描了5万行,最后只返回20条,说明大概率在数据访问路径上做了大量无效工作,这就是优化的方向。

3.2 第二步:EXPLAIN的关键列到底在看什么

EXPLAIN是最常用的分析工具,但要真正读明白它,不能只看key列有没有索引。我习惯按以下顺序看:

  • type列:反映访问类型,从好到差依次是system、const、eq_ref、ref、range、index、ALL。看到ALL就是全表扫描,看到index也不是什么好事,说明全索引扫描,虽然走了索引结构,但本质上还是把所有索引行读了一遍。最应该关注的是这条SQL能不能做到ref或者range,因为这意味着查询用上了索引进行精确定位或范围定位。
  • possible_keys和key列:possible_keys列出优化器认为可用的索引,key是最终选用的索引。如果possible_keys有值但key为NULL,说明优化器算了代价后觉得走索引不如全表扫描。这时候要思考:是统计信息不准,还是确实应该全表扫?
  • rows列:这是执行计划里的预估扫描行数,单位是行。这个数和实际扫描行数对比意义重大。预估与实际严重偏离,通常指向统计信息过期。
  • Extra列:最值得警惕的是Using filesort和Using temporary。出现Using filesort意味着排序没法利用索引,数据量一大就可能在内存或磁盘上做额外排序;Using temporary通常意味着隐式的临时表操作,常见于GROUP BY、DISTINCT或部分子查询场景,这两个都容易引发性能瓶颈。

3.3 第三步:用量纲数据验证,而不是凭感觉

EXPLAIN给出的是代价估算,最终还是要看真实执行。MySQL 5.7以上可以用EXPLAIN ANALYZE直接拿到实际执行时间和扫描行数(8.0.18以上支持):

EXPLAIN ANALYZE SELECT user_id, order_amount FROM orders WHERE status = 'pending' AND create_time > '2024-01-01' LIMIT 20;

结果里能看到类似actual time=0.356..2.181 rows=20 loops=1的输出。这里有个细节:actual time的第一段是取第一行数据的时间,第二段是取全部行的时间,rows=20是实际行数。如果实际行数和执行计划的预估行数差了数量级,基本可以断定是统计信息不准导致的错误执行计划。

到了这一步,问题的性质就已经清楚了:要么是索引缺失,要么是索引设计不合理,要么是执行计划选错了索引。接下来就要进入实际优化动作。

4. 一次订单查询的真实优化过程:从500ms到30ms的路径拆解

前面讲了一堆原理和排查工具,可能还是有点抽象。下面用一个我实际处理过的订单表查询案例,完整走一遍优化过程。表结构大概是这样的:

CREATE TABLE orders ( id BIGINT PRIMARY KEY, user_id BIGINT NOT NULL, order_no VARCHAR(32) NOT NULL, status TINYINT NOT NULL, create_time DATETIME NOT NULL, amount DECIMAL(12,2), KEY idx_user_create (user_id, create_time) );

原始慢SQL长这样:

SELECT id, order_no, amount FROM orders WHERE user_id = 12345 AND DATE_FORMAT(create_time, '%Y-%m-%d') = '2024-05-20' AND status = 1 ORDER BY create_time DESC LIMIT 20;

这条SQL的响应时间稳定在500毫秒左右,数据量大约800万行。乍一看,有联合索引idx_user_create,条件也覆盖了user_id,按说应该不慢。但执行计划一出来,发现问题不少。

4.1 第一个坑:函数包裹索引列,索引失效

执行计划里possible_keys显示idx_user_create,但key为NULL。原因就在DATE_FORMAT(create_time, '%Y-%m-%d')这个写法。当索引列被函数包裹时,优化器无法直接比较B+树里的原始值,索引就废了。这就好比一本电话簿按姓氏拼音排序,你偏要按"名字的笔画数"去查,那只能从头翻到尾。

这个问题的标准改法是去掉函数,把计算放在常量一侧:

AND create_time >= '2024-05-20 00:00:00' AND create_time < '2024-05-21 00:00:00'

改成范围条件后,create_time的原始值可以直接参与索引比较,idx_user_create里以user_id定位后,第二个字段create_time自然形成了范围扫描区间。这一个改动,就把全表扫描变成了索引范围扫描。

4.2 第二个坑:索引字段顺序与SQL条件不匹配

改完函数问题后,执行计划确实走到了索引,但我发现rows还是很高,达到了两万多行。继续深挖,问题出在查询条件里多了个status = 1。

idx_user_create只包含(user_id, create_time)两个字段,status没有参与索引匹配。也就是说,InnoDB拿到满足user_id = 12345且时间在当天的所有记录后,再逐条回表读取数据,然后筛掉status != 1的记录。这个过程并不高效:如果user_id = 12345在当天有500条记录,但有490条都是status = 2,那就有490次回表是白做的。

这个场景正好可以优化联合索引设计。设计时把status字段加进联合索引,放在user_id之后、create_time之前:

ALTER TABLE orders ADD KEY idx_user_status_create (user_id, status, create_time);

推荐的联合索引结构为(user_id, status, create_time)。在WHERE里user_id做等值匹配,status也是等值匹配,索引能够在这两层上精确定位,create_time就利用范围扫描,同时查询和排序都在索引内完成,ORDER BY create_time也能直接顺序读取,不再产生filesort。

4.3 第三个坑:覆盖索引少了一个字段,回表成本翻倍

索引改成(user_id, status, create_time)之后,执行计划上的rows从两万多降到了几百,响应时间到了50毫秒左右,已经不错了,但我觉得还能再压一压。继续看Extra列,发现还是有个现象:同时出现了Using index condition; Backward index scan,说明正在反向扫描索引。条件user_id、status都是等值,create_time是范围,加上ORDER BY create_time DESC,引擎是从后往前读索引,完全正常。

问题在于,目标查询里的order_no和amount字段不在索引中,每返回一行都要执行回表。当结果集有几百行时,回表几百次是不可避免的开销。如果这张表上需要高频跑这个查询,最彻底的优化是把查询需要的列也塞进索引,做成覆盖索引:

ALTER TABLE orders ADD KEY idx_user_status_create_cover (user_id, status, create_time, order_no, amount);

本质上是空间换时间。order_no和amount是查询要返回的列,把它们放进索引叶子节点后,这个查询的全部数据都能从二级索引直接获得,回表这一步彻底消失。优化后这条SQL的执行计划变成了Using index,响应时间稳定在30毫秒以内。这是典型的从"能查出来"到"查得够快"的进阶优化。

4.4 深分页问题:LIMIT很深的隐藏成本

同一个查询还有一个经常被忽视的变体,就是分页翻到很后面时的深分页问题,例如:

SELECT id, order_no, amount FROM orders WHERE user_id = 12345 AND status = 1 ORDER BY create_time DESC LIMIT 100000, 20;

即使索引已经完全覆盖了,数据库也要先读取10万条索引记录,然后丢弃前面的99980条,最后只返回20条。这个过程越往后越慢,本质是"扫描了但不用"的开销。

更优的写法是改造成"先取主键,再关联回原表"。MySQL 8.0以上可以直接用窗口函数,也可以分两步:

SELECT t.id, t.order_no, t.amount FROM ( SELECT id FROM orders WHERE user_id = 12345 AND status = 1 ORDER BY create_time DESC LIMIT 100000, 20 ) AS tmp JOIN orders t ON t.id = tmp.id ORDER BY tmp.create_time DESC;

子查询只扫索引,拿到的还是主键值,然后再用主键去聚簇索引精准取20条。这样能把"扫10万行"的代价限制在索引层面,而不会产生10万次回表。这里有个前提:优化前要确保二级索引的叶子节点里有足够的数据支撑排序和分页,典型的做法是把create_time放在索引里,否则子查询排序还是要回表。

5. 并行SQL优化:什么时候该用,什么时候不该用

热搜词里有"并行sql优化",这个方向确实值得单独聊一聊。很多从Oracle迁移过来的工程师,对并行的态度往往两极分化:要么完全不用,要么到处乱开。我的判断标准很简单——并行主要是用于大查询、批量任务、分析类场景,对OLTP类型的短事务几乎没有任何帮助,甚至可能帮倒忙。

5.1 Oracle并行执行的适用场景

Oracle数据库里,并行执行可以发生在全表扫描、索引全扫描、表关联、聚合操作等多个环节。它的核心思路是:把一个大任务拆成多个小分片,多个服务进程同时处理,最后汇总结果。官方文档里的PARALLEL提示是这么写的:

SELECT /*+ PARALLEL(employees, 4) */ * FROM employees;

适合用并行的场景有几个共同特点:单条SQL处理的数据量特别大(比如几千万行的统计),执行时间以分钟计,而且系统当前有足够的空闲CPU和IO资源。数据仓库跑月报、历史数据归档、大表刷字段,这类任务适合开并行。

不适合的场景也很明确:高并发OLTP事务、短查询、CPU已经接近满载的系统。试想一下,如果一条本来只要20毫秒的小查询,你强行给它开8个并行进程,光是进程调度和结果汇总的通信开销就可能超过执行本身,还会抢占其他事务的CPU资源,最终整体吞吐量反而下降。

5.2 并行度的设置逻辑

并行度设置不是越大越好。Oracle里设置并行度的常用方式是加提示符,比如DOP 4表示用4个并行进程。如果什么都不写,Oracle会根据parallel_degree_policy和机器的CPU核心数自动决定,这时候可能出现一个意外情况:本来只想让报表快一点,结果优化器把并行度开到了机器CPU的核心数,其他应用全部被拖垮。

所以实际运维中,我会对所有大查询明确指定并行度上限,而不是依赖自动策略。并行度一般控制在CPU核心数的一半以内,同时要考虑IO子系统是否跟得上。曾经有一台数据库服务器CPU是32核,SSD阵列,我在一批统计SQL上开了16并行,效果还挺明显。后来往同一台服务器上加了批量的普通查询请求,发现并行进程把IO队列打满,普通查询的等待时间急剧上升,最后还是把并行度降到了8,整个系统的总吞吐量反而上去了。

并行执行还经常和分区表配合使用。如果一张大表按月份做了分区,并行扫描时每个进程可以只负责两个分区,减少相互之间的资源争用。要注意,并行查询在SQL执行计划的Note部分会有提示,调试时记得看有没有真正生效,有时候因为没有授权,提示符只是被当成注释忽略了。

5.3 MySQL的并行限制与替代思路

MySQL在并行执行方面比Oracle保守很多。官方8.0支持innodb_parallel_read_threads,可以在聚集索引的范围扫描层面并行读取,但这些并行策略主要针对特定场景,对普通OLTP查询的收益并不明显。日常MySQL优化里,我更推荐用三种替代思路实现"慢查询的并行效果":

  • 分区裁剪:把大表按时间分区,查询条件里带上分区键,实际执行时只扫描对应分区。
  • 批量任务拆分:如果是一条处理1000万行的UPDATE,可以考虑按主键范围拆成多个小批次UPDATE,并配合限流,小步快跑。既能错峰利用CPU,又能避免大事务占用过多资源和导致主从延迟过大。
  • 读写分离:把复杂的统计查询引流到只读从库,主库专心处理写事务。
  • 实际上,在MySQL场景里,索引策略和查询写法优化到位后,很多"想用并行解决"的问题根本到不了需要并行的程度。

6. 索引优化的边界与防坑经验

优化做到这里,文章已经覆盖了基本的索引设计、慢SQL排查和并行场景。最后这部分想写几个踩过的坑,这些经验在文档里往往不会明确写出来,但线上实战中却经常遇到。

6.1 索引不是越多越好:写入放大和优化器选择困难

索引的代价在于更新成本。每次INSERT、UPDATE、DELETE,除了写入聚簇索引,还要同步维护所有二级索引。一张表如果有10个索引,写入一条数据就相当于更新11处结构。在写入频繁的订单表上,我见过因为索引冗余导致写入性能下降50%以上的情况。

另外,索引过多还会让优化器"花眼"。当一条SQL的可选索引太多,优化器的代价模型偶尔会选中一个次优索引。解决方法往往是精简索引:能复用联合索引前缀的,就不再建单独的单列索引。

6.2 线上加索引的姿势:不是直接ALTER就行

大表加索引是一个高频需求,但风险极高。MySQL 8.0之前,ALTER TABLE ADD KEY在一些版本和场景下会锁表,即使是INPLACE算法也会占用大量IO和空间资源,大表持续时间可能会很长。如果你在8.0以上版本做这类操作,也要先确认ALGORITHM=INPLACE能被执行,否则数据库可能自动降级为COPY原表。拷大表不仅耗时,还会把服务器磁盘空间吃得很紧。

稳妥的办法是用工具在线变更,比如pt-online-schema-change或gh-ost。它们的基本原理是创建一张新表、通过触发器或binlog同步增量数据、在某个时间点切换表名,整个过程业务无感知。我自己在百万级以上的表加索引,都会走这个工具,并且会在业务低峰期执行。哪怕工具再好,物理资源的占用是不可避免的。

6.3 隐式类型转换:最隐蔽的索引失效

有一种索引失效很难被察觉:字段的类型和传入参数类型不一致,优化器会做隐式转换,导致索引无法使用。比如user_id是varchar类型,代码里传了一个整型的userId,查询条件写成WHERE user_id = 12345时,MySQL会把两边的值都转成浮点数再比较,索引就没法直接命中。执行计划里能看到key列为NULL,rows飙高,但好多人想不到是类型转换的原因。

判断隐式转换的快捷方式:在WHERE条件上对索引列做CAST(user_id AS CHAR)之类的操作会导致索引失效,但反过来对常量做转换则不产生影响。所以写法上要尽量保证索引列保持原样。

6.4 统计信息更新:一张命令解决的问题

前面反复提到统计信息过期会导致执行计划漂移。在MySQL里,ANALYZE TABLE可以重新收集统计信息。Oracle里则常用DBMS_STATS.GATHER_TABLE_STATS。这些命令看似简单,却经常被团队遗漏在例行维护清单之外。我的习惯是:核心大表在每周的维护窗口里固定执行一次统计信息收集,尤其是在大批量数据导入之后立刻执行。这一条操作及时与否,能避免掉大量"索引明明存在但就是不走"的诡异问题。

写在最后:一套可复用的SQL优化流程

这几年做了不少SQL优化工作,积累了一套固定的动作。每次接手一条慢SQL,我都会按这个顺序来:

  1. 看慢查询日志记录的实际执行时间和扫描行数;
  2. 用EXPLAIN看执行计划,重点核对type、key、rows和Extra;
  3. 检查是不是统计信息过期或隐式类型转换;
  4. 结合等值条件、排序字段、回表列,重新设计联合索引;
  5. 根据数据量和业务场景判断是否要用覆盖索引或并行策略;
  6. 变更上线前先用测试环境的同量级数据做压测,观察执行时间是否真正回落。

索引策略和SQL优化没有银弹,不可能靠一两个技巧解决所有问题,但只要能在"数据分布—索引结构—查询写法—执行计划"这条链路上建立自己的判断框架,绝大多数慢SQL都能被快速定位和解决。遇到问题时,切记多做执行计划分析,少凭直觉猜。保证每一步操作有据可依,线上系统才会越来越稳,查问题才会越来越快。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 5:35:36

MySQL批量插入慢?JDBC必开参数rewriteBatchedStatements=true详解

很多人第一次遇到“批量插入很慢”这个问题时&#xff0c;第一反应都是换驱动、换数据库版本&#xff0c;甚至有人直接改表结构、上分区表。排查到最后&#xff0c;往往发现根因根本不是数据库不行&#xff0c;而是一个藏在 JDBC URL 里的开关没有打开——rewriteBatchedStatem…

作者头像 李华
网站建设 2026/10/16 14:31:25

n阶导数怎么求?基础公式与四种核心方法一次讲透

“求函数的n阶导”这件事&#xff0c;几乎是高等数学和数学分析里最容易被低估的一个技能。一阶导、二阶导大家都会算&#xff0c;但一旦要求写出 f^{(n)}(x) 的通项&#xff0c;很多人就懵了——有的靠死记硬背&#xff0c;有的靠硬算前几阶再疯狂猜规律&#xff0c;还有的直接…

作者头像 李华
网站建设 2026/10/19 4:32:22

从晨间清单到晚间复盘:笔记整理与时间管理的高效工作日记录

2026年1月26日&#xff0c;周一&#xff0c;晚上十一点出头。我坐在书桌前把今天最后一条待办划掉&#xff0c;突然觉得应该把这一天完整记下来。不是那种“今天做了什么”的流水账&#xff0c;而是想复盘一下&#xff1a;一个普普通通的工作日&#xff0c;为什么到晚上会给我一…

作者头像 李华
网站建设 2026/10/16 7:59:59

多智能体协作框架agency-agents:从架构设计到实操落地

1. 从“agency-agents”这个标题说起&#xff1a;它到底在解决什么问题第一次看到“agency-agents”这个组合词&#xff0c;我脑子里蹦出来的第一反应是&#xff1a;这大概率是一个围绕“代理”和“智能体”做文章的项目。拆开来看&#xff0c;“agency”在英文语境里既可以指“…

作者头像 李华
网站建设 2026/10/15 23:28:45

对话式AI记忆系统设计:从写入、存储到检索的工程实践

1. 从"claude-mem"这个名字说起&#xff1a;它到底想解决什么问题第一次看到claude-mem这个命名&#xff0c;我的直觉是&#xff1a;这是一个围绕对话记忆做文章的项目。拆开来看&#xff0c;"claude" 指向的是对话式 AI 的交互场景&#xff0c;"mem&…

作者头像 李华
网站建设 2026/10/18 5:37:50

终端编码智能体SolonCode:v0.0.18核心设计与实现解析

1. 我为什么会在终端里做一款自己的编码智能体先说个背景。过去两年我一直在用各种AI编程助手&#xff0c;从IDE插件到独立桌面应用&#xff0c;装了卸、卸了装&#xff0c;试了一圈之后发现一个很尴尬的问题&#xff1a;它们主要服务的是"IDE里写代码"这个场景&…

作者头像 李华