news 2026/10/3 18:13:09

SQL添加数据全攻略:从INSERT语法到批量导入与性能优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SQL添加数据全攻略:从INSERT语法到批量导入与性能优化

做后端开发这些年,天天跟表结构打交道,被人问得最多的一句话反而是最基础的:“SQL里到底怎么添加数据?”一开始我也很不理解,INSERT INTO谁不会写?后来见过各种线上事故才明白,这个动作看着简单,真要做得稳、做得快、做得不重复,里面全是细节。这篇文章就把SQL添加数据这件事,从最简单的单行插入讲到批量导入、主键冲突、性能优化和常见报错,给你一条能照着复现的经验路径。适合刚学SQL的新手,也适合写过一阵子但没时间系统梳理过的研发同事。

1. 添加数据前,先搞清楚INSERT在数据库里是干什么的

1.1 表结构就是添加数据时的“规则说明书”

每张表在创建时都定好了列、类型、约束。你后来写INSERT,本质就是往一张已经画好格子的表格里填一行。列名是表头上的字,字段类型是格子的规格,NOT NULL表示这一列不能空,默认值表示你不填时有兜底,主键是这一行的身份标识,外键是行与行之间的引用关系。很多人加数据失败,第一步就错在完全不看表结构。

举例,创建一张用户表:

CREATE TABLE t_user ( id INT PRIMARY KEY AUTO_INCREMENT, user_name VARCHAR(50) NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP );

这里id是自增主键,你插入时可以不写,数据库会自动生成;created_at带了默认值,你也可不写,数据库会用当前时间填上。于是最小插入语句只需要给user_name:

INSERT INTO t_user (user_name) VALUES ('张三');

很多新手以为必须把所有列都写出来,最后反而被AUTO_INCREMENT或默认时间搞得心烦。记住:先看CREATE TABLE,再看该写哪些列,这才是加数据的第一步。不同数据库的默认值写法略有不同,MySQL常用DEFAULT CURRENT_TIMESTAMP,SQL Server常用DEFAULT GETDATE(),PostgreSQL常用DEFAULT now(),换库时别想当然。

1.2 INSERT的标准语法,两种写法差别很大

INSERT INTO是SQL标准,主要分两段:指定目标表和列,再给值。最规范的写法:

INSERT INTO 表名 (列1, 列2, 列3) VALUES (值1, 值2, 值3);

如果你省略列名,直接写:

INSERT INTO 表名 VALUES (值1, 值2, 值3);

这表示你把表里所有列都按顺序填一遍。这种写法能跑,但我不推荐。原因很简单:一旦表结构增加一列或调整顺序,这条SQL要么报列数不匹配,要么把值塞进错误的列里。线上出过太多这样的事故。我的习惯是永远带列名,哪怕多敲几个字,至少自解释、可维护。如果你用Navicat这类工具,它生成的INSERT默认也是带列名的,照做就对了。

另外,部分数据库支持在插入后把自增主键或者一些计算列返回出来。PostgreSQL和SQLite可以写RETURNING id,SQL Server可以写OUTPUT inserted.id,MySQL没有标准RETURNING。实际开发里,插入后立刻需要新ID的场景很常见,既然数据库给了这个能力,就不要插入后马上再查一次,平白增加一次往返。

2. 添加数据的主流姿势:单行、多行、查询导入、UPSERT

2.1 单行插入:最直接,但细节别丢

单行插入最常用于手动补数据、写单元测试、初始化配置。拿刚才的用户表举例:

INSERT INTO t_user (user_name, id) VALUES ('李四', 100);

这里故意写了id,说明你可以显式指定自增主键的值。但有前提:id不能和已有记录冲突,否则会报Duplicate entry。生产环境里我不建议手工指定自增ID,除非是在做数据迁移且要保持原ID。你不写,数据库自己排,省心。

字符串和日期是单行插入里最容易被坑的地方。字符串必须用单引号,如果字符串里本身有单引号,要写成两个单引号转义,比如在MySQL和SQL Server里要写'O''Brien'。日期最好用标准格式'2025-07-01 12:00:00',别依赖数据库区域的隐式转换,否则不同环境可能解析错。时间戳类型还要考虑时区,插入前先确认客户端会话和数据库时区是否一致,时区不统一,数据看起来就像“不翼而飞”。

2.2 多行批量插入:一条SQL塞进N条数据

业务上要初始化一批数据,常见做法是把多组VALUES拼在一条INSERT里:

INSERT INTO t_user (user_name) VALUES ('王五'), ('赵六'), ('孙七');

这条语句一次提交三行。相比循环执行三次单条INSERT,它少了SQL解析、网络往返和日志刷新的次数,性能提升非常明显。绝大多数主流数据库都支持这种多行VALUES,但老版本Oracle有些限制,早期写法要用INSERT ALL INTO t_user (user_name) VALUES ('xx') INTO t_user (user_name) VALUES ('yy') SELECT 1 FROM dual;。如果你在写PL/SQL,要注意这个差异。

批量大小不建议无脑贪大。一条SQL塞几万行,SQL文本过长,可能超过max_allowed_packet或数据库对SQL长度、参数个数的限制,还容易造成长时间锁表。我一般控制在500到1000行一组,分批次循环提交。还有个小坑:调试的时候,如果从日志里复制一条特别长的INSERT,复制出来总是缺后半段,很多时候不是SQL错了,而是编辑器或控制台缓冲截断,不代表数据库有问题。

2.3 INSERT INTO ... SELECT:表到表的“搬砖”

比手动写VALUES更高效率的做法,是把查询结果直接当成数据源插入目标表:

INSERT INTO t_user_archive (user_id, user_name) SELECT id, user_name FROM t_user WHERE created_at < '2024-01-01';

这一招特别适合做归档、横向扩展临时表、按条件导数据。目标表必须已存在,且列数量和类型要和SELECT结果对得上。你也可以在SELECT里加DISTINCT,让插入的数据先做一次去重,这在数据清洗时很常用。比如把旧表里的重复手机号清理掉再入库:

INSERT INTO t_user_clean (mobile) SELECT DISTINCT mobile FROM t_user_temp WHERE mobile IS NOT NULL AND mobile != '';

“去除空值”这个需求用WHERE IS NOT NULL过滤,比先插入再DELETE要干净。注意,如果你是想快速复制一张全新表,可以用CREATE TABLE new_table AS SELECT * FROM old_table(MySQL和PostgreSQL),SQL Server则用SELECT * INTO new_table FROM old_table。它们把建表和导数据一步完成,但通常不会复制原有索引和约束,别指望得到一张带主键的完整副本。

2.4 存在就更新,不存在才插入:UPSERT的四种写法

同步数据是日常,最常见的场景:上游每天给我一批记录,主键如果已存在就更新,不存在就新增。这时别写“先SELECT判断,再决定INSERT还是UPDATE”,因为并发情况下两步之间有间隙,两个人同时判断不存在,就会一起插入,还是冲突。正确做法是利用数据库的UPSERT能力。

MySQL:

INSERT INTO t_user (id, user_name) VALUES (101, '小明') ON DUPLICATE KEY UPDATE user_name = VALUES(user_name);

SQLite:

INSERT INTO t_user (id, user_name) VALUES (101, '小明') ON CONFLICT(id) DO UPDATE SET user_name = excluded.user_name;

PostgreSQL:

INSERT INTO t_user (id, user_name) VALUES (101, '小明') ON CONFLICT(id) DO UPDATE SET user_name = EXCLUDED.user_name;

SQL Server最常用的是MERGE:

MERGE t_user AS target USING (VALUES (101, '小明')) AS source (id, user_name) ON target.id = source.id WHEN MATCHED THEN UPDATE SET user_name = source.user_name WHEN NOT MATCHED THEN INSERT (id, user_name) VALUES (source.id, source.user_name);

还要提一下SQLite的INSERT OR REPLACE,它和ON CONFLICT DO UPDATE在语义上不一样。REPLACE会先把旧行删除再插入新行,如果表里有外键指向这行,可能触发级联删除或者自增ID变化,非常危险。能用ON CONFLICT就不要随手用REPLACE。MERGE在某些SQL Server版本下遇到并发也可能有死锁,使用前要评估,不过对于日常小规模同步,它已经够用了。最稳妥的兜底是给表加上唯一约束或唯一索引,让数据库在约束层面拒绝真正的重复,应用层再怎么错乱也不会把脏数据堆进去。

补充一个安全习惯,和INSERT的关系很直接:不要用字符串拼接用户输入,而要用参数化查询。无论你写Java、Python、Go还是Node.js,都别把变量直接拼进SQL文本。比如Python里要写成cursor.execute("INSERT INTO t_user(user_name) VALUES (%s)", (user_name,)),而不是cursor.execute(f"INSERT INTO t_user(user_name) VALUES ('{user_name}')")。前者让数据库把参数当纯数据处理,拼字符串等于把用户输入当SQL代码执行,一次注入事故能让整个库都陷入风险。这个话题点到为止,理解“参数化是底线”就够了。

3. 从文件、脚本和图形界面添加数据:实战工具推荐

3.1 命令行客户端和IDE:别忘记COMMIT

命令行里加数据其实很简单。以MySQL为例:

mysql -uroot -p use test_db; START TRANSACTION; INSERT INTO t_user (user_name) VALUES ('命令行插入'); SELECT * FROM t_user WHERE user_name = '命令行插入'; COMMIT;

先开事务,插入一条,查一下,再提交,这是个好习惯。MySQL默认autocommit是开的,你单独执行一条INSERT会自动提交,所以我上面的写法特意开了START TRANSACTION,防止手滑。SQL Server默认行为不一样,很多环境仍然隐式事务,需要显式COMMIT;Oracle就更典型,执行INSERT后如果不COMMIT,别人会话看不到,甚至你自己断开连接后数据就没了。我见过不少人用PL/SQL Developer执行完INSERT,一看表里没数据,以为是没写进去,其实只是没有提交。

如果你用Navicat管理SQL Server,直接打开查询编辑器跑INSERT同样要留意事务规则。工具里的“提交”按钮有时候隐藏得比较深,新手如果找不到,就记住:命令行里把SQL写完,一定要分清楚当前是在autocommit还是手动事务模式下;手动模式下最后必须有COMMIT。

3.2 图形导入向导:Excel、CSV、SHP都能变成表里的行

日常偶发数据用INSERT还行,真要从Excel里导两万行,谁也不会一条条复制。Navicat这类工具早就给了导入向导:右键目标表,选择“导入向导”,选Excel或CSV,然后做列映射。这里真正决定成败的不是怎么按下一步,而是三个细节:字符集选对没有、日期格式认对没有、空值怎么处理。我建议先导一个几十行的子集到临时表,检查完再全量导,否则一个日期格式错乱就能把整批数据搞脏。

简单提一个相关场景:做GIS二次开发时,经常要把SHP文件“添加”到数据库,本质上也是在数据库表里加数据,只不过加的是空间对象。比如把SHP导入PostGIS,常用工具是shp2pgsql,生成SQL或COPY文件后在psql里执行;也可以用GDAL的ogr2ogr一步到位。转换过程中要处理坐标系、属性字段映射、几何类型转换。很多人卡在“SHP明明能打开,但往库里加的时候报错”,多半是字段类型不匹配或者坐标系参数没写。这个场景看着特殊,背后的逻辑和Excel导入是一样的:先弄清楚目标表结构,再让工具把源数据翻译成SQL能理解的值。

达梦(DM)这类国产数据库也有数据迁移工具,可以把一个SQL文件导入目标库,导入前先检查源SQL里的表名、字段名、字符集是否和目标库一致。不要一次性导入巨大的文件,必要时用工具自带的分段选项,或者把大文件拆成几份逐份导入,出错范围更可控。

3.3 大SQL文件导入的实操细节

Linux服务器上导入一个几GB的SQL备份文件,是很常见的需求:

mysql -uroot -p test_db < /home/backup/data.sql

Windows下则通常在cmd里进到mysql/bin,再执行同样的重定向。如果SQL文件是UTF-8,数据库连接也指定了UTF-8,基本就不会乱码。文件里如果同时包含建表和INSERT,执行完别光顾着看“Query OK”,要检查末尾有没有错误。重定向方式执行时,错误会直接打在控制台,但滚动太快往往看不到。我的做法是先把输出重定向到日志:

mysql -uroot -p test_db < data.sql > import.log 2>&1

导入结束后用grep -i error import.log定位失败点。有时候一条数据违反约束导致整批停止,mysql客户端默认不是“遇到错误继续”,如果你想跳过个别脏数据继续导入,可以用--force参数,但生产环境要谨慎,因为你跳过的可能是数据质量问题,后面迟早要还的。更稳妥的思路是先把所有数据导入临时表,清洗完毕再INSERT INTO正式表。

4. 添加数据性能优化:为什么你的INSERT那么慢

4.1 慢INSERT到底慢在哪

一个很常见的现象:代码里循环执行一万条INSERT,跑了十分钟还没结束,而同样数据量用批量插入几秒就完事。原因主要有四块。

第一,单条自动提交。每条INSERT如果单独提交,数据库都要写事务日志、刷盘、更新binlog,这和寄快递一样,你非要把一百个包裹拆成一百趟快递,时间全花在路上。

第二,索引维护。B+树索引本质是一张“目录”,每插入一条数据都要更新目录。索引越多,每次变更要改的地方越多。

第三,锁与并发冲突。多条会话同时往同一张表插数据时,为了保证唯一性和一致性,数据库会加锁。并发高热度高的时候,锁等待的时间可能比执行SQL还长。

第四,约束检查。主键唯一、外键是否存在、CHECK约束是否满足,每一层都要过一遍。数据越不规范,校验开销越大。

4.2 亲测有效的批量导入优化方案

我总结过一套“三步走”。

第一步,把单条INSERT改成批量。要么用一条SQL包含多组VALUES,要么用PreparedStatement分批addBatch,一次执行几百条。不要一上来纠结SQL文本大小,先把批次定在500行左右试水。

第二步,用事务包住整批操作。MySQL里写:

START TRANSACTION; INSERT INTO t_user (user_name) VALUES ('a'),('b'),('c'); COMMIT;

在程序里就关闭自动提交,每批或每几万条COMMIT一次。这样把事务日志的fsync次数从N万次降到百次,速度天差地别。

第三步,全库导入大历史数据时,先把非唯一索引和外部检查关掉或移除,导完再重建。注意,这不是让你在生产核心时间乱来,而是针对一次性数据初始化场景。比如一张表除了主键外还有两个普通索引,导入500万行,索引维护占了大部分时间;如果先DROP掉两个普通索引,导入后再CREATE INDEX,很多情况下总时间反而更短。

更极端的大批量性能需求,可以直接使用数据库的批量加载工具:MySQL的LOAD DATA INFILE、PostgreSQL的COPY、SQL Server的bcp。这些工具绕开了部分SQL层解析,以数据流形式灌入,比逐条INSERT快一个数量级。比如Python里psycopg2的copy_expert,做了多次项目,几百万行从一小时缩短到几十秒。下面是一个粗略对比参考:

方式常见耗时(几十万行、多字段为例)说明
循环单条INSERT + 自动提交数十分钟甚至更久事务日志、网络往返开销最大
批量多行INSERT + 手动事务几十秒到几分钟最简单,收益最大
LOAD DATA / COPY / bcp几秒到几十秒快,但需要文件格式匹配,可能跳过部分约束检查

这对你的架构也有启发:日常业务请求的插入量小,用普通INSERT没问题;数据平台或初始化任务,永远优先走批量工具。

4.3 并行导入的时候,注意别帮倒忙

有人一看数据量大,立刻开几十个线程并发INSERT,结果不仅没变快,反而把数据库锁到炸。并行写同一张表的本质冲突是锁竞争,不是CPU不够。真正有效的并行方式是分片:按主键ID范围把数据分成多个独立区间,每个线程导一个区间,事务独立、数据不重合,再把并发数控制在2到4个。导完一批后看锁等待时间和IO,再决定加不加。不要看到“并行”就觉得一定是灵药,并行SQL优化讲的是减少互相牵制,而不是无脑堆线程。

另外,大批量写入时数据库日志和IO会被瞬间拉高。如果线上有业务流量,务必错峰执行,或通过限速(比如每批之间sleep)控制节奏,避免一条导入SQL把主库拖成“慢SQL重灾区”。实测下来,晚上低谷期跑批量任务是最稳妥的。

4.4 遇到慢INSERT,先查表结构再查锁

如果你发现单条INSERT也很慢,那问题大概率不在SQL本身,而在锁。MySQL可以通过查询information_schema.innodb_trx看到当前未提交事务和持有的锁,把长时间阻塞的会话KILL掉;SQL Server可以看sys.dm_exec_requests的wait_type和blocking_session_id;Oracle可以用v$session_wait定位。慢INSERT不是一种,先分清是“执行慢”还是“等锁慢”,等锁慢就找堵它的会话,执行慢再去看索引和磁盘IO。这个排查思路,和查慢SELECT是同一套方法论,只不过平时大家关注SELECT多一点,忘了INSERT也会慢。

5. 添加数据常见报错与排查实录

5.1 报错速查表

做开发最烦的就是INSERT报错,因为错误提示往往不是“你第几个字段错了”,而是“Row 1、Row 2”。我把自己遇到频率最高的几个整理成表,你直接对号入座:

报错或现象常见原因解决方案
Column count doesn't match value count at row 1INSERT列数不等于VALUES个数带列名,数好括号,避免省略列名
Unknown column 'xxx' in 'field list'表里没有这个字段,或大小写敏感用SHOW CREATE TABLE核对字段拼写
Duplicate entry '1' for key 'PRIMARY'主键或唯一索引冲突该场景是否该用UPSERT,导入前DISTINCT去重
Data too long for column 'mobile'值长度超过字段长度ALTER TABLE加长VARCHAR,入库前做长度校验
Column 'xxx' cannot be null非空字段没有提供值补值或给数据库默认值,检查导入时空值处理
Cannot add or update a child row: a foreign key constraint fails外键指向的父记录不存在先插父表数据,再插子表,检查外键值
SQLiteException: no such column: test_urlORM模型和表结构不同步,SQLite没自动加列ALTER TABLE ADD COLUMN,更新表结构
ORA-12518: 监听程序无法分发连接Oracle连接数达到上限,监听无法分配调大processes/sessions参数,释放空闲连接,必要时重启监听
中文乱码或问号客户端字符集、连接字符集、表字符集不一致统一UTF-8,连接串加charset=utf8,Oracle注意NLS_LANG
插入很久没有反应表被锁,事务未提交查锁和阻塞会话,COMMIT或ROLLBACK,分批重试

SQLite那个no such column,特别典型:你用ORM建好实体类,给字段加了一个test_url,但SQLite本身的表结构不会因为这个改动自动加列,除非你走迁移。所以你在执行INSERT时,数据库才会说“根本没这个列”。这提醒我们,开发中改模型后,要同步改表结构,不能指望框架帮你处处兜底。

5.2 排查三步法:先看整段,再看表结构,最后做最小复现

不管报错多诡异,我排INSERT问题永远是三步。第一步,把完整报错信息复制下来,不要只看“失败”两个字。错误信息里通常已经写明是哪张表、哪个字段、什么约束。第二步,用SHOW CREATE TABLE核对表结构,重点看字段名、字段类型、默认值、索引、外键。第三步,造最小复现:在一张临时表或事务里,只插入一行最简单的数据,然后逐步加字段,不断缩小范围。绝大多数“加不进去”的问题,在这一步都能定位。而且,把正式数据往临时表里插一遍,本身也是验证的好办法。

这套方法不花哨,但非常实用。有一次系统连续报错“Value too long for character string”,我以为代码里没截断,后来发现临时表字段是VARCHAR(20),源数据手机号区号加号码长度已经25了,把字段扩大成VARCHAR(30)后问题立刻消失。不查表结构,靠猜是猜不出来的。

5.3 做顺手后的几个直觉:先清洗、先备份、先看唯一键

添加数据的场景越做越多后,我会在写INSERT前默认做几件事。第一,上游数据到底是不是干净的?比如去重、去空值、统一大小写和日期格式,在入库前用SQL过滤一下,比入库后一遍遍DELETE要省事得多。第二,如果数据量上千或涉及覆盖更新,先在临时表跑一遍,核对数量和质量没问题再落到正式表。第三,永远关注主键和唯一索引,这是“重复数据”的防火墙。业务逻辑可能会迟到,但唯一键约束永远会兜底。

顺带再提醒一句安全方面的基本功:添加数据时,凡是涉及用户输入,都是注入风险的高发区。不要拼SQL,用参数化。这段我前面说过,但在报错场景里再强调一次:如果你看到一条INSERT语句是拿字符串拼出来的,别觉得“能跑就行”,它在生产环境就是一颗定时炸弹。日志里也别打印完整SQL,尤其别打印包含身份信息的参数,脱敏之后再记录,这是基本功。

6. 写到最后:关于添加数据,我的三个习惯

这些年写SQL,我从“会写INSERT”到“敢在生产环境执行INSERT”,靠的不是背语法,而是三个习惯。

第一个习惯:动手之前先看表结构。花十秒钟SHOW CREATE TABLE,省掉后面半小时的报错排查。第二个习惯:任何手工操作先把事务开起来。INSERT先不要COMMIT,用SELECT先确认数据,确认无误再提交,这个动作救过我很多次手滑。第三个习惯:大批量数据永远先走临时表和批量导入。不管是CSV、SHP还是别的库导出的SQL,先进临时表清洗,再用INSERT INTO SELECT或UPSERT落到正式表,这样即使有问题,也不会把坏数据直接抹到线上。

SQL里添加数据,说到底就是“按照表结构,把数据稳定地放进去”这一件事。步骤永远是那几个,变的是你对细节的敏感度。下次再有人问你“SQL中如何添加数据”,别只甩一条INSERT给他,告诉他:先看结构,再选方式,最后想清楚约束和性能,这句话比任何语法都有用。

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

三星手机误删音乐怎么恢复?从删除原理到备份方案全解析

1. 先把事情搞明白&#xff1a;删掉的音乐到底去了哪里很多人遇到“音乐不小心删了”的第一反应是赶紧装个恢复软件扫一遍手机&#xff0c;但说实话&#xff0c;这个顺序是错的。在谈恢复手段之前&#xff0c;你得先弄清楚一个底层问题&#xff1a;在当前的手机系统里&#xff…

作者头像 李华
网站建设 2026/10/3 18:11:59

随机森林特征选择与降维实战:重要性排序、Python实现与避坑指南

做特征筛选的时候&#xff0c;我见过太多人一上来就咔咔跑相关性矩阵、PCA、LASSO&#xff0c;绕一大圈&#xff0c;最后发现两个问题&#xff1a;一是筛选出的特征换个模型就不灵了&#xff0c;二是根本解释不了为什么选这几个。后来我发现&#xff0c;随机森林在这件事上天然…

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

CS_BOM_EXPL_MAT_V2参数配置详解:BOM展开避坑与实战指南

做SAP ABAP开发绕不开BOM展开。不管是生产订单组件需求计算、成本估算取材料成本&#xff0c;还是给MES/APS系统推送制造物料清单&#xff0c;最终都会落到CS_BOM_EXPL_MAT_V2这个标准函数上。这个函数功能强&#xff0c;参数多&#xff0c;文档里交代得又不细&#xff0c;很多…

作者头像 李华
网站建设 2026/10/3 18:10:54

OpenClaw接入飞书完整指南:WSL2环境配置与AI Agent机器人部署

最近这段时间&#xff0c;OpenClaw 这个开源 AI 助手框架热度越来越高&#xff0c;不少人都想把它接到飞书里&#xff0c;在群聊中直接调教一个属于自己的 AI Agent。我花了一下午把 OpenClaw 和飞书完整打通&#xff0c;从 WSL2 环境检测、开放平台建应用、事件订阅&#xff0…

作者头像 李华
网站建设 2026/10/3 18:10:28

RK3588开发板OpenEuler系统烧写与SSH远程连接实战指南

1. 项目概述与板卡初印象 1.1 海鸥派是什么&#xff0c;为什么选它 海鸥派是一块基于瑞芯微RK3588平台的国产嵌入式开发板&#xff0c;搭配OpenEuler操作系统&#xff0c;定位是给嵌入式开发者、边缘计算玩家和信创领域的技术人员做项目原型验证用的。这块板子最吸引人的一点&…

作者头像 李华
网站建设 2026/10/3 18:09:57

树莓派4B+Ubuntu 22.04+RPLIDAR C1激光雷达环境扫描系统搭建实战

前阵子公司要做一套室内环境快速扫描的验证方案&#xff0c;我顺手把手头闲置的树莓派4B翻了出来&#xff0c;配合思岚的RPLIDAR C1激光雷达&#xff0c;在Ubuntu 22.04上从零开始搭了一套简单环境扫描系统。整个过程比我想象中顺利&#xff0c;但中间也踩了几个典型的坑&#…

作者头像 李华