ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

DuckDB如何将RDS慢查询提速近百倍:原理与实战

DuckDB如何将RDS慢查询提速近百倍:原理与实战 做数据分析的朋友几乎都被RDS的慢查询折磨过。业务那边一句“看下这个季度的复购率”你的MySQL实例就开始吭哧吭哧跑大表扫描几分钟出不来结果。后来我试着把这类分析查询全部交给DuckDB同一个SQL耗时从分钟级降到秒级快的时候确实有接近百倍的体感。这篇文章不是写给专业数仓工程师的论文而是写给被RDS慢查询困扰的业务分析师、后端开发和运维同学。我会讲清楚DuckDB到底凭什么能实现这种加速也会把从RDS导出数据、用DuckDB加载分析、常见坑怎么避的全流程完整走一遍确保你零基础也能跟着做完。1. 为什么你花了钱还被慢查询折磨RDS做分析的痛点1.1 行存储下的大表扫描天生就是慢的绝大多数RDS实例比如阿里云RDS MySQL、AWS RDS for MySQL/PostgreSQL底层都是传统的OLTP数据库。这种数据库的核心设计目标是高效处理单行或者少数行的高频读写也就是点查和短事务。为了达到这个目标它们使用B树索引配合行式存储一行数据的所有字段在磁盘上连续存放。这个设计完全服务于“按主键找一条记录”的场景但对分析查询非常不友好。分析查询往往是“把1000万行里某几列的数值做聚合”比如按月份做销量汇总。在行式存储下数据库要把1000万行完整读出来即使你只需要其中两个字段整行的磁盘块也得一块不落进内存。数据量大之后这个扫描成本会指数级放大。“你买了一整箱杂物只为拿里面一把螺丝刀”就是这个感觉。MySQL还会额外加上一层惩罚即使查询只涉及部分字段它也要把整行记录的所有字段都过一遍排序和分组时还要生成临时表涉及文件排序的场景更是雪上加霜。很多同学看到EXPLAIN里出现Using temporary; Using filesort就明白这条SQL已经触发了行式存储的软肋。这不是优化不到位而是架构层面就不适合干这种事。1.2 OLTP并发与OLAP分析是两种互相打架的负载RDS的核心矛盾在于它同时要应对在线业务的写入流量和分析查询的读取压力。在线业务的负载特征是每秒几百上千个写入和点查单个查询毫秒级返回但并发极高。分析查询的负载特征是单个查询要吃满多个CPU扫描几百MB甚至几十GB数据耗时几秒到几分钟。这两种负载放在同一个实例上结局基本是两败俱伤。分析查询一跑起来CPU和IO瞬间被打满在线业务的响应变慢甚至出现连接堆积。反过来说在线业务高峰期分析查询的优先级最低排队等资源慢到怀疑人生。我见过很多业务团队出过这类事故周五下午跑月度经营报表十几条聚合SQL一起发上去结果整个RDS实例CPU飙到90%以上线上订单接口跟着超时。最后运维手动kill掉报表SQL业务才恢复。这不是一次两次而是每次月底都要来一遍。问题的根源不在于哪条SQL写得凶而是OLTP和OLAP的负载模型天然互相排斥放进同一个引擎里必然打架。1.3 分析查询全跑到RDS上的隐藏成本很多人觉得“反正RDS已经买了资源多跑几个查询只是慢一点而已”但实际成本远超想象。第一是资源费用。数据库实例的CPU、内存规格是按在线业务的峰值流量定的。分析查询一旦吃紧资源要么扩容实例要么购买只读实例。只读实例也不是免费午餐一个高规格的只读副本月费并不低。而且分析的数据量一般还在增长半年后SQL变慢你又要继续升级费用是无底洞。第二是运维风险。RDS实例的磁盘、CPU、连接数都有关联效应分析SQL长时间占用资源会造成主从复制延迟。复制延迟一旦超过阈值下游的数据同步任务就开始排队甚至业务侧读到主从数据不一致。更别说有DDL锁、大事务、慢SQL这些经典问题叠加在一起半夜被告警电话吵醒是常有的事。第三是协作效率。RDS上跑分析查询往往要问你DBA要账号权限。一个运营临时想看数据流程走两天等拿到权限决策黄金时间都过去了。就算有了账号生产库的schema还经常变查询可能直接报错。相比之下把分析数据导出到一个独立的、无状态的分析引擎里你想怎么查就怎么查不影响任何人才是真正解放生产力。2. DuckDB凭什么能“百倍加速”核心原理解读2.1 DuckDB是什么DuckDB是一个进程内、列式存储的分析型数据库。它不需要单独安装服务端不需要维护数据库进程而是以一个库文件的形式嵌入到你的应用程序或命令行工具里。你下载一个二进制文件进到shell或者pip install duckdb后在Python里import它就是一个完整的数据库。DuckDB的定位是“分析界的SQLite”。SQLite是嵌入式的OLTP数据库负责单机轻量存储DuckDB则是嵌入式的OLAP数据库负责对大规模数据进行分析型查询。它支持标准SQL支持事务支持各种数据类型还能直接读取CSV、Parquet、JSON文件甚至通过扩展连接S3、HTTP服务。很多人第一次用DuckDB时会被它的极简惊艳到不需要写host、port、user、passworddown一个文件就能跑。也正是因为这种嵌入式的轻量特性它非常适合作为离线的分析工作台安安静静地待在数据开发者的本地环境里把十几GB的CSV文件折腾得服服帖帖。2.2 四个让查询变快的关键设计DuckDB快不是单纯靠某个技巧而是几个核心设计的共同作用。第一是列式存储。上一次提到行式存储的分析查询要把整行读出来而DuckDB是按列组织的同一列的数据连续存放。查询只涉及用户ID和金额两列就只把这两列完整读出来其它列完全不动。数据量少了一个量级IO开销大幅下降这是加速的第一个基石。第二是列式压缩。相同类型的数据放在一起在连续存储下能获得非常好的压缩率。比如“支付状态”这一列全是0和1做位打包日期列做单字典或RLE压缩金额字段用Delta编码。压缩之后磁盘扫描的数据量进一步减少很多场景下原本要读500MB的数据实际可能只有50MB。现代CPU读取瓶颈往往在内存带宽和磁盘IO压缩省下来的空间直接反映在查询速度上。第三是向量化执行引擎。传统数据库是一条记录一条记录地“解释执行”每条记录都要经过一遍函数调用链CPU大部分时间花在指令分发和流水线停顿上。DuckDB是批处理模式一次处理一批数据比如1024行通过SIMD指令并行完成这一批的加减乘除、比较、哈希计算。这种批量、向量化的方式让CPU的利用率显著提升对数值计算密集的聚合查询效果立竿见影。第四是并行执行。DuckDB的查询执行器会自动把扫描、聚合、排序拆分成多个任务交给多个线程执行。默认线程数跟CPU核数一致我的机器是8核它就把一个大表拆成8份并行扫描最后把部分结果汇总。相比MySQL很多场景下还停留在单线程扫描为主的状态并行度完全不在一个级别。2.3 DuckDB不是万能的它擅长什么不擅长什么DuckDB可以非常快但它不是数据库界的瑞士军刀。它擅长的是分析型SQL比如GROUP BY聚合、窗口函数、多表JOIN、数据过滤和排序。它对“读多写少”的数据集特别友好数据导入后你可以反复进行复杂的探索式查询速度快、反馈即时。但DuckDB不适合高并发的点查场景。你拿它做一个每秒几千次SELECT的小后台服务效果会很差。它没有独立服务器也没有完整的连接池概念本质上是一个进程内数据库并发上无法与MySQL这类OLTP数据库相比。每次INSERT或UPDATE都会涉及锁和事务开销大量小写入会产生严重的写放大。所以正确的用法是把DuckDB定位成“分析引擎”而不是“应用数据库”。从RDS导出全量数据放入DuckDB做聚合、出报表、跑实验这是它最舒服的姿势。3. 零基础实操从RDS到DuckDB的完整迁移流程3.1 安装DuckDB三种方式任选DuckDB的安装非常友好官方提供了各平台的预编译二进制。Windows下可以下载zip解压出duckdb.exemacOS下载dmg或zipLinux下载相应的AMD64压缩包。解压后在命令行直接运行duckdb就进入SQL shell了。我建议做数据分析为主的朋友优先用Python方式来安装因为后续数据清洗、对接业务系统会更方便。pip install duckdb安装完成后在Python里执行import duckdb conn duckdb.connect(analysis.db) print(conn.sql(SELECT 1 1).df())如果你不写Python只想在命令行用SQL操作那直接下载二进制即可。启动命令就是duckdb可以带一个文件参数./duckdb mydata.duckdb另外DBeaver从较新版本开始原生支持DuckDB连接。新增数据库连接时选DuckDB指定一个路径或直接选择已有的.duckdb文件就能像操作MySQL一样用图形界面执行SQL、查看结果。对刚接触SQL的零基础用户这个图形界面很友好。3.2 从RDS导出数据正确的姿势从任何一个RDS导出数据本质都是把表结构定义和数据本身转换成文件格式再拉下来。我以阿里云RDS MySQL为例最常见的方式是导出CSV。方式一直接在DBeaver或Navicat里对目标表执行查询然后导出结果集为CSV。优点是操作门槛低可视化勾选即可缺点是大表导出会卡界面容易导出到一半超时。适合百万行以内的小表。方式二用mysqldump导出成为文本文件。命令长这样mysqldump -h your-rds-host -u your_user -p --tab/your_temp_dir your_db order_table这条命令会在服务器端生成order_table.sql和order_table.txt前者是建表语句后者是tab分隔的纯数据文件。之后把txt文件下载到本地变成CSV或者直接导入DuckDB。但要注意RDS的实例有时候不允许你直接访问服务器文件系统所以这个方式不完全通用而且tab分隔的文件还需要做格式转换多一层麻烦。方式三在RDS的安全白名单允许你的本地IP访问的前提下直接连接远程库用SQL把数据查询出来并分批写入本地CSV。生产环境我不会推荐直接select大表更稳的方式是用只读账号在业务低峰期跑加ORDER BY主键配合LIMIT分批导出避免一次查询时间太长。不管用哪种方式导出时都要注意几个关键参数字符集统一为UTF-8否则后面在DuckDB里看到中文乱码还得重新处理表头是否导出建议带表头DuckDB自动识别列名NULL值的表示方式RDS导出默认可能是空字符串或者“NULL”这个要统一不然加载后有大量脏数据大表导出建议按天或按月拆分成多个文件便于后续并行加载和排查问题我自己通常会把导出数据做成一张清单哪个文件对应哪张表、多少行、多大体积全部记下来这样加载完成后做校验时会省很多力气。3.3 把CSV加载进DuckDB拿到CSV后进入DuckDB命令行或者用Python连接对象接着执行加载。最简单的方式是read_csv_auto让DuckDB自己推断类型CREATE TABLE orders AS SELECT * FROM read_csv_auto(/data/orders.csv, headertrue);如果CSV文件比较多比如按月份拆了12个文件可以用glob模式一次加载CREATE TABLE orders AS SELECT * FROM read_csv_auto(/data/orders_*.csv, headertrue);read_csv_auto会自动推断每列的类型、判断表头、识别日期格式适合快速试用。但它的自动推断在某些场景下会翻车比如把一个整数列推断成了VARCHAR。严格的生产流程我更推荐先用DESCRIBE看一遍推断结果有问题再手动指定类型DESCRIBE orders;如果你对字段类型有明确预期直接用COPY命令更稳语法上跟PostgreSQL类似COPY orders FROM /data/orders.csv ( FORMAT CSV, HEADER true, NULL NULL, DELIMITER , );COPY方式的好处是类型转换规则更可控NULL指定成字符串“NULL”后会正确变成SQL里的NULL而不是把一个叫“NULL”的文本塞进字段里。3.4 数据一致性校验加载完成并不等于大功告成。数据导来导去最常见的坑是行数对不上、金额字段精度丢了一两位、日期解析后偏移了时区。我每次加载完都会先跑一下校验SQL。第一步对比行数SELECT count(*) FROM orders;我导出时记录了原始行数这个数字必须一致。不一致就要回去查导出过程有没有分批遗漏、加载过程中有没有因为类型转换错误导致整行被丢弃。第二步抽样对比明细。在RDS上用同样的条件查出一小部分样本再在DuckDB里对比SELECT * FROM orders WHERE order_id IN (某几个编号) ORDER BY order_id;对比几个关键字段的值特别是金额、数量这些数值字段和订单时间这种日期字段。第三步校验聚合结果SELECT date_trunc(month, order_time) AS order_month, round(sum(total_amount)::numeric, 2) AS total_amount FROM orders GROUP BY 1 ORDER BY 1;拿这个结果跟RDS上同一条SQL的结果做对比。如果月度汇总完全一致基本可以断定数据一致性没问题。如果发现对不上优先检查是否时区问题、Decimal精度问题、或者NULL值处理方式不同。4. 真实场景实测一个典型分析查询的加速对比4.1 测试场景设计为了让你对“百倍加速”有个直观概念我拿一组模拟的电商数据做过对比。场景是一张订单表大约1000万行字段包含订单ID、用户ID、商品ID、订单时间、订单金额、支付状态一张用户表50万行一张商品表10万行。分析任务是统计每个城市用户在不同支付方式下的月度订单金额TOP10商品。这个查询涉及三张表JOIN带GROUP BY和窗口函数是典型的业务统计需求。4.2 实测加速效果我把同一套SQL分别在RDS MySQL 8.0实例4核16GB和本机DuckDB8核16GB上跑数据量保持一致结果如下查询场景RDS MySQL耗时DuckDB耗时加速倍数按日汇总订单量18.4s0.21s约87倍三表JOIN取月度城市统计46.2s0.48s约96倍窗口函数排名32.7s0.35s约93倍全量扫描过滤聚合12.6s0.13s约97倍这个结果的前提是RDS里这三个查询全部走全表扫描或者大范围扫描没有合适的复合索引可以优化。如果RDS上恰好有一个覆盖索引MySQL的耗时能降到3秒以内但依然比DuckDB慢一个量级。这说明“百倍加速”在分析型查询场景下是真实存在的只是它取决于查询本身是不是扫描密集型的。4.3 用执行计划看差异RDS MySQL里执行EXPLAIN这条查询的关键行是type: ALL rows: 10000000 Extra: Using where; Using temporary; Using filesort这说明在B树和行式存储下哪怕聚合只用了两列它也要把整表1000万行捞起来中间结果存临时表再进行文件排序。磁盘、内存、CPU全都在高强度运转。DuckDB里执行EXPLAIN ANALYZE能看到物理计划EXPLAIN ANALYZE SELECT ... FROM orders o JOIN users u ON o.user_id u.id JOIN products p ON o.product_id p.id GROUP BY ...输出里会显示每个算子的时间占比比如扫描orders表300MB实际读取的数据量因为列存裁剪可能只有50MB然后进入hash join阶段左右表做并行哈希连接最后GROUP BY使用部分聚合加合并聚合。整个过程没有重复读取行数据也没有超大临时表和文件排序。执行计划就是优缺点的照妖镜。在RDS上一次分析查询的时间大头全花在“无奈的IO扫描”上在DuckDB上时间均匀分配给扫描、连接、聚合三个环节每个环节都很短。4.4 DuckDB里的SQL习惯调整从RDS迁移到DuckDB大部分SQL可以原样执行但有几个习惯可以调整让分析过程更顺手。第一是GROUP BY ALL。DuckDB支持直接GROUP BY所有未聚合的SELECT非聚合列不用重复写一长串SELECT user_id, order_date, sum(amount) FROM orders GROUP BY ALL ORDER BY ALL;ORDER BY ALL也有奇效它会自动按所有SELECT列排序适合快速探查数据。第二是避免无意义的“SELECT *”。DuckDB就算列存再好SELECT *也要把所有列的元数据和可能的投影都过一遍。宽表里你只需要三列就只写三列扫描量进一步减小。第三是充分利用视图和临时表。分析过程经常有中间结果与其反复在大表上跑JOIN不如先创建一个物化小表CREATE TEMP TABLE monthly_user AS SELECT user_id, date_trunc(month, order_date) AS month, sum(amount) AS total FROM orders GROUP BY 1, 2;后续的查询在这个小临时表上进行速度会非常快。第四是合理使用字段类型。日期字段尽量用DATE或TIMESTAMP不要用VARCHAR存日期金额字段用DECIMAL不要用FLOAT否则汇总时会出现精度漂移。这些习惯对任何数据库都适用在DuckDB里正确类型的收益更明显。5. 进阶玩法让DuckDB更好用的几个技巧5.1 不用落地直接读对象存储上的数据传统导数据是“导出CSV、传本地、再导入DuckDB”其实DuckDB可以跳过本地落地直接查询远程对象存储上的文件。安装HTTPFS扩展后可以像操作本地文件一样读取S3、OSS等对象存储路径INSTALL httpfs; LOAD httpfs; SELECT * FROM read_parquet(s3://your-bucket/orders/*.parquet);如果数据以Parquet格式保存在对象存储里DuckDB还能利用Parquet的元数据和谓词下推只读取满足WHERE条件的分区数据加速效果更夸张。这对数据管道里已经产出Parquet文件的团队来说几乎是零成本接入。很多云平台的对象存储支持S3兼容协议只需要配置endpoint、key和secretDuckDB就能安全访问。日常我可以直接在本地用DuckDB查云端数据先在几千万行样本上试聚合逻辑逻辑确认后再让任务调度系统跑全量大作业研发效率提升很明显。5.2 用Python联动pandas/Arrow无缝衔接DuckDB和Python生态的配合是它最让我舒服的一点。以前用pandas处理1亿行数据内存分分钟爆炸现在可以让DuckDB承担所有重活pandas只负责分析展示。直接查DuckDB得到pandas DataFrameimport duckdb conn duckdb.connect(analysis.db) df conn.sql( SELECT date_trunc(month, order_date) AS month, count(*) AS orders, sum(amount) AS revenue FROM orders GROUP BY 1 ORDER BY 1 ).df()反向操作也支持把一个pandas DataFrame注册成临时表直接参与SQL查询conn.register(user_temp, user_df) conn.sql( SELECT u.city, count(DISTINCT o.user_id) FROM orders o LEFT JOIN user_temp u ON o.user_id u.id GROUP BY 1 ).df()更重要的是Arrow生态的对接。DuckDB原生支持Arrow格式可以零拷贝读取Arrow数据。在大数据场景里如果你已经用Arrow存储了中间数据DuckDB直接查询省掉序列化和反序列化开销速度非常可观。这个特性很适合做数据探索的中间层离线任务产出的数据进行轻量转换后直接落到本地DuckDB分析师在本地SQL自由查询迭代速度远超在集群上提交作业。5.3 增量更新与轻量建模View、宏、MERGEDuckDB尽管适合读多写少但每次全量灌数据也不是好习惯。业务表每天增量几百万行全量重建表的时间会线性增长。这时候可以用INSERT和MERGE做增量更新。如果源表是append-only的日志直接追加INSERT INTO orders SELECT * FROM read_csv_auto(/data/orders_new.csv);如果源表有更新和删除则用MERGEMERGE INTO orders t USING read_csv_auto(/data/orders_upsert.csv) s ON t.order_id s.order_id WHEN MATCHED THEN UPDATE SET amount s.amount, status s.status WHEN NOT MATCHED THEN INSERT (order_id, user_id, amount, status) VALUES (s.order_id, s.user_id, s.amount, s.status);DuckDB的MERGE语法跟PostgreSQL类似增量更新的门槛很低。在“轻量建模”方面DuckDB支持常规视图和宏。视图适合把复杂的JOIN逻辑固化下来CREATE VIEW order_user_product AS SELECT o.*, u.city, p.category FROM orders o JOIN users u ON o.user_id u.id JOIN products p ON o.product_id p.id;后面所有查询都基于这个视图逻辑清晰改动成本低。宏则适合封装可复用的计算表达式CREATE MACRO revenue(total_amount, discount) AS total_amount * (1 - discount);后续直接SELECT revenue(amount, discount)就不用到处重复写计算逻辑了。5.4 调整内存和并发参数DuckDB默认会尽可能使用可用内存但如果你一边跑分析一边还要开浏览器建议限制一下内存占用避免系统卡死PRAGMA memory_limit8GB; PRAGMA threads4;内存限制加好之后分析方法再暴力也不会影响本机其它应用。遇到超大查询与其把内存加到很大不如分成几个步骤先聚合到中间表再对中间表做最终汇总。DuckDB还有spill to disk能力超出内存限制的数据会写入临时文件保证查询能跑完不过磁盘读写会拖慢速度所以还是建议合理规划。执行大型查询时可以开启进度条直观查看执行进度SET enable_progress_bar true;这个功能在命令行里尤其好用一眼看出查询到底是在扫描、连接还是排序对于排查性能瓶颈非常有帮助。6. 常见问题与排查实录避坑指南6.1 CSV加载乱码、类型推断错误、NULL乱象CSV乱码是我遇到最多的第一个坑。Windows下用Excel导出的CSV经常是GBK编码直接加载成中文乱码。解决思路是先统一编码iconv -f GBK -t UTF-8 orders_gbk.csv orders_utf8.csvPython方式with open(orders_gbk.csv, encodinggbk) as f1: with open(orders_utf8.csv, w, encodingutf-8) as f2: f2.write(f1.read())其次是类型推断。read_csv_auto会把“2023-01-01”猜成DATE但“20230101”这种格式可能被猜成INTEGER导致日期无法当作时间类型使用。我的做法是先用all_varchartrue把整表读成字符串再手动转换关键列CREATE TABLE orders_raw AS SELECT * FROM read_csv_auto(orders.csv, all_varchartrue); CREATE TABLE orders AS SELECT order_id::BIGINT AS order_id, user_id::BIGINT AS user_id, order_date::DATE AS order_date, total_amount::DECIMAL(18,2) AS total_amount FROM orders_raw;多一步转换但类型完全可控不会出现静默截断或者解析失败。NULL值问题同样隐蔽。有些CSV里NULL是空字符串有些是“NULL”有些是“\N”。DuckDB统一用NULL NULL参数指定。加载之后务必检查SELECT count(*) FROM orders WHERE order_date IS NULL;发现异常就要回到导出环节确认源数据里到底有没有空值别让NULL数据悄悄溜进报表。6.2 内存不够、文件巨大怎么办遇到几个GB的CSV文件DuckDB在加载时可能会把内存顶爆。优先推荐把CSV转成Parquet再查。Parquet是列式存储既能压缩体积又保留类型信息是DuckDB最舒适的格式import duckdb duckdb.sql( COPY (SELECT * FROM read_csv_auto(huge_orders.csv)) TO huge_orders.parquet (FORMAT PARQUET) )转一次Parquet之后后续所有查询都基于Parquet文件扫描数据量大幅下降内存压力显著减轻。如果数据量真的到了几十GB本机内存放不下全量聚合那就调整策略先按月聚合生成月度结果再把月度结果汇总成全量。DuckDB也支持外部表但日常使用下来最稳的方案还是控制单次查询的扫描范围尽量将大查询拆成小查询分步落结果。6.3 日期、时区和Decimal精度问题RDS里TIMESTAMP通常带时区信息DuckDB处理时区的方式略有不同。如果发现日期对不上优先检查是不是时区偏移导致。最直接的办法是把所有时间统一转成UTC存贮展示时再按业务时区转换SELECT order_time AT TIME ZONE Asia/Shanghai AS local_time FROM orders;金额字段的精度问题也很常见。MySQL的DECIMAL(10,2)导入DuckDB后必须显式指定DECIMAL类型否则自动推断可能变成DOUBLE。DOUBLE在大量累加时会有浮点误差报表里出现0.01元的差异对账时就头大。规则很简单所有金额、单价、折扣字段全部用DECIMAL绝不使用FLOAT或DOUBLE承载金额。6.4 常用SQL语法差异表功能MySQLDuckDB备注限制返回行数LIMIT 100LIMIT 100一致日期截断DATE_FORMATdate_truncDuckDB使用PostgreSQL风格字符串拼接CONCAT(a, b)a窗口函数支持支持语法一致正则表达式REGEXPregexp_matchesDuckDB函数更丰富随机采样ORDER BY RAND()USING SAMPLE 10%DuckDB有高效采样语法合并插入INSERT ... ON DUPLICATE KEYMERGE INTO用法需改写这个表不用背遇到不兼容时直接查DuckDB官方文档即可。DuckDB对标准SQL支持度很高绝大多数MySQL分析型查询可以无缝迁移。6.5 从RDS导数据时的其他坑导出数据环节藏着一堆小问题。我遇到过导出文件到一半连接中断之后所有后续步骤全都白做。对策是尽量拆小文件每张表单独导出并且导完立刻做checksum校验wc -l orders_202401.csv再看数据库里的count两边对上了才继续下一步。另外生产RDS如果开了白名单你的本地IP必须提前加白。加了白名单之后还要确保用的是低权限只读账号防止误写入污染生产数据。特大批量导出时建议在业务低峰期操作并选择只读实例来执行导出查询避免对主库产生额外压力。踩过这些坑之后我现在拿到一批数据第一件事永远是先跑一遍DESCRIBE再看一遍count。这两个动作做扎实了后面分析才有底气。如果你正准备把RDS上的分析负载迁到DuckDB建议先挑一个频率最高、耗时最久的查询跑通全流程你就知道这套方案到底有多省事。
返回列表