
TPC-DS 这套基准跑通不难跑出能拿去说服人的结果很难。我见过太多人拿着一张 Excel 表格说分布式数据库比单机 MySQL 快 5 倍细问下去发现两边数据规模不一样、索引建得不一样、一边跑了热缓存一边跑了冷缓存甚至查询语句都不是同一份方言生成的。标题里提到的tpc ds mysql和tpc-ds 测试 tidb 结果本质上是把单机 MySQL 和分布式 TiDB 放在同一套 TPC-DS 负载下做横向对比这件事本身很有价值——它能同时暴露单机数据库的 IO 天花板和分布式数据库的网络与调度开销也能让你真正理解什么时候该上分布式这个绕不开的选型问题。问题在于TPC-DS 是 24 张表、99 条查询、7 张事实表加 17 张维度表组成的复杂分析型负载它对数据生成、DDL 方言、统计信息、缓存状态、并发模型的敏感度极高。任何一个环节没对齐最后的数字就是废的。所以这篇内容不讲空泛的分布式更快而是把这套测试从环境设计到结果解读的完整链路拆开怎么定数据规模、怎么改 DDL、怎么导入、怎么生成 99 条 SQL、怎么统一计时口径、结果出来之后哪些数字能看哪些不能看。适合手里有机器、想自己做一轮靠谱对比的读者也适合只是想知道TPC-DS 结果该怎么读的人。1. 先弄明白 TPC-DS 到底在测什么1.1 24 张表和 99 条查询背后的设计意图TPC-DS 模拟的是一套零售企业的决策支持系统数据模型里有三条销售渠道——门店、目录、网络每条渠道都配了销售事实表和退货事实表再加一张库存表构成 7 张事实表。17 张维度表负责描述客户、商品、门店、时间、促销、地址这些分析维度。这个模型的关键特征是雪花结构而不是规整的星型维度表之间还有层级关联比如客户要经过 customer_address、customer_demographics、household_demographics 才能拼出完整画像商品要经过 item 关联到 brand 和 category。这种设计直接导致查询里出现大量多表 join而不是简单的单表聚合。99 条查询覆盖的场景也很刻意有只扫一张事实表的报表型查询有跨三条渠道做对比的复杂关联有带窗口函数和比率计算的排名查询也有嵌套子查询堆了四五层的地狱查询。SF100 的时候store_sales 大约 2.88 亿行catalog_sales 约 1.44 亿行web_sales 约 7200 万行inventory 大约一亿出头而最大的维度表 customer 也就一千万行左右。这个数据分布意味着事实表决定扫描成本维度表决定 join 的选择顺序两者叠加会出现极强的长尾效应。提示很多人只跑 99 条里的一部分比如挑 20 条有代表性的。这样做省时间但会丢掉最关键的结论。TPC-DS 的价值恰恰在于长尾——那些单条跑十几秒甚至几分钟的查询才是区分两类架构的真正分水岭。所以你在设计测试之前先明确自己要看的是什么。如果是看报表响应时间那就该关注单查询延迟和 P95如果是看批量跑批能力那要看 99 条串行跑完的总时长和吞吐如果是看并发支撑那要走多流模型同时跑 N 个查询流。这三种测法对硬件和参数的要求完全不同混在一起谈就是耍流氓。1.2 为什么单机 MySQL 和分布式 TiDB 放一起比容易失真第一个失真点是数据规模。TPC-DS 的 SF 从 1 到 100000 都有SF1 的时候全部数据也就 1GB 左右这么小的量级塞进 MySQL 的 buffer pool 里所有查询几乎都是纯内存计算分布式架构反而因为多了一层网络 RPC 而变慢。这时候得出的MySQL 更快没有任何工程意义因为你真正上生产的时候数据量不可能是 1GB。反过来如果你直接上 SF1000约 1TB单机 MySQL 光是导入就要跑很久查询里随便一条全表扫描都能把磁盘打满。第二个失真点是索引和表结构。TPC-DS 官方给的是通用 DDL没有业务索引只有主键和少量外键声明。但实际做测试的时候有人会给 MySQL 加一堆二级索引让查询变快却忘了给 TiDB 加同样的索引或者给 TiDB 加了索引但因为优化器选择不同根本没走。这种做法出来的对比毫无意义。第三个失真点是缓存状态。MySQL 的 InnoDB buffer pool 是有状态的第一次跑和第二次跑的差距可以有数倍。TiDB 的 TiKV block cache 和 coprocessor cache 同样有状态而且 region 的分布还会随着访问模式变化。你要么统一跑冷数据每次清 page cache要么统一跑热数据预热两轮取第三轮绝不能一边冷一边热。第四个失真点是执行引擎差异。MySQL 8.0 之后有了 hash join但默认可能还是走 nested loopTiDB 支持 index join、hash join、merge join还能下推聚合和谓词到 TiKV 层如果开了 TiFlash 还能走列存的 MPP 模式。这些开关的不同组合结果能差出好几倍。所以对比报告里必须写清楚什么版本、什么参数、有没有列存副本、优化器版本是什么。2. 环境与参数设计结果差异的八成在这一步决定2.1 硬件、版本与部署形态怎么定做横向对比硬件对齐是第一原则。单机 MySQL 用的机器CPU 核数、内存、磁盘类型要和 TiDB 集群的单节点保持同一档次否则结论会被硬件差异污染。举一个我实际用过的配置形态MySQL 侧一台 16 核 64GB 内存、NVMe SSD 的物理机TiDB 侧三台同规格机器分别部署 TiDB、TiKV、PD小规模测试里混部也能接受但要在报告里注明。这样 TiDB 的总资源是 MySQL 的三倍这是分布式架构的天然属性你在解读结果时必须把这个因素考虑进去——否则TiDB 快 3 倍可能只是资源多 3 倍。版本选择上MySQL 建议 8.0.30 以上主要是 hash join 和直方图统计信息的成熟度TiDB 建议 7.x 系列这个版本的优化器对复杂 join 的处理明显比 5.x 稳定MPP 模式也成熟了。两边的字符集统一用 utf8mb4排序规则统一用 utf8mb4_bin 或 utf8mb4_general_ci不要一边用默认一边用自定义否则字符串比较的开销会不一致。存储层面有个容易被忽略的细节TiKV 对磁盘的随机写非常敏感如果用的是机械盘或者网络存储Raft 日志写入会成为瓶颈导入阶段和写多的场景会被严重拖慢。测 TPC-DS 虽然以读为主但导入阶段的表现会直接影响你的总耗时统计所以 NVMe 是基本要求。MySQL 侧同理InnoDB 的 redo log 和 doublewrite 都需要低延迟磁盘。2.2 数据规模的选择逻辑选 SF 是个权衡题。我的经验是分三档看规模数据量适用场景主要观察点SF100约 100GB快速验证、参数调优优化器行为、SQL 改写是否正确SF300约 300GB中等规模对比缓存命中率下降后的 IO 表现SF1000约 1TB严肃对比分布式并行扫描的真实收益SF100 是最实用的起点。100GB 的数据量MySQL 单机 64GB 内存装不下全部热数据但能装下大部分维度表和一部分事实表这样既能测出内存计算的能力又能测出 IO 回落的拐点。TiDB 三节点加起来内存更多但数据是按 region 分散的单节点缓存命中率未必比 MySQL 高——这个对比本身很有意思。如果你只想验证分布式在什么规模下开始赢SF100 和 SF1000 各跑一遍就够了。中间的 300 更多是用来观察曲线的连续性时间成本高除非你要写正式报告否则可以跳过。注意不要用 SF1 或 SF10 做架构对比。那个量级下所有数据库都跑在内存里测的是 CPU 单核性能和优化器的常数开销跟分布式 vs 单机这个命题没关系。2.3 关键参数对齐清单这一块是最容易被跳过、也最容易导致结果不可比的。下面这张表是我每次做对比都会过一遍的清单类别MySQL 侧设置TiDB 侧设置对齐理由内存innodb_buffer_pool_size 设为物理内存 70%~75%TiKV block cache 设为单节点内存 45% 左右都是读缓存的主力比例要合理并发单查询串行执行单查询串行执行关闭并行算子避免并行度不同造成的不公平统计信息ANALYZE TABLE 全表ANALYZE TABLE 全表调大采样优化器依赖统计信息选 join 顺序索引只保留主键不建二级索引同样只保留主键保证扫描路径一致字符集utf8mb4utf8mb4避免比较开销差异日志关闭 general log 和 slow log 的采样开销关闭 expensive query 日志的额外开销减少测量干扰关于 TiDB 的并行度这里有个取舍。TiDB 默认会开启 coprocessor 的并发扫描这个特性在分布式下是优势但它让单查询延迟这个指标变得不可比——MySQL 是单线程扫TiDB 是多线程扫快是应该的。我的做法是分两组跑一组关闭并行tidb_distsql_scan_concurrency 设为 1tidb_executor_concurrency 设为 1测纯单线程能力一组保持默认并行测实际生产形态。两组数据都记录报告里分开写。3. 数据生成与导入的完整实操3.1 用 dsdgen 生成 100GB 数据TPC-DS 官方工具包里有 dsdgen数据生成和 dsqgen查询生成两个程序源码需要在 Linux 下编译。拿到源码包之后cd tools make OSLINUX编译完会在当前目录生成 dsdgen 和 dsqgen。生成 SF100 的数据注意文件会按表拆成 24 个 .dat 文件mkdir -p /data/tpcds/100g ./dsdgen -scale 100 \ -dir /data/tpcds/100g \ -TERMINATE N \ -FORCE Y-TERMINATE N的作用是让每行末尾带一个分隔符|这是 TPC-DS 的标准格式方便后续用 LOAD DATA 时把行尾的竖线当作行结束符处理。-FORCE Y是覆盖已有文件。生成 100GB 大概需要十几分钟到半小时取决于磁盘写入速度瓶颈主要在 store_sales 和 inventory 这两张大表上。生成完之后建议立刻做两件事一是统计每个文件的行数作为后续导入校验的基准二是把数据放在和数据库不同的磁盘上避免导入时读和写抢同一个设备的 IO。wc -l /data/tpcds/100g/*.dat /data/tpcds/100g/linecount.txt提示如果你打算用 TiDB Lightning 的 local backend 导入数据文件需要能被 Lightning 所在节点访问。分布式部署时要么把数据放在共享存储要么在每个 TiKV 节点都放一份然后用 Lightning 的分布式导入模式。3.2 建表 DDL 的方言改造官方给的 DDL 是通用 ANSI 风格直接拿到 MySQL 或 TiDB 上跑通常会报错。常见问题有这么几类with default子句、not null后面跟的默认值写法、decimal精度声明、日期类型。改造思路是把它简化成 MySQL 兼容的语法因为 TiDB 本身高度兼容 MySQL 协议和语法改一份两边都能用。具体改动包括去掉所有with default去掉外键约束TPC-DS 的外键只是声明实际数据里不一定严格满足加上反而会让导入变慢把char(n)统一成varchar(n)日期字段统一用date金额字段保持decimal(7,2)到decimal(15,2)不等。主键保留因为 TPC-DS 的查询里很少用到主键过滤保留主键主要是为了 TiDB 能有聚簇索引的分布依据。TiDB 这边还有一个额外考虑聚簇索引还是非聚簇索引。对于 store_sales 这种有复合主键的大表用聚簇索引可以让主键相关的范围扫描更快但如果查询模式是随机点查聚簇索引会导致热点。TPC-DS 以扫描为主聚簇索引是更合适的选择建表时不加NONCLUSTERED关键字即可走默认的聚簇模式。两边建表完成后务必核对表数量和字段数量SELECT COUNT(*) FROM information_schema.tables WHERE table_schema tpcds;24 张表一个不多一个不少。3.3 MySQL 侧导入LOAD DATA 的细节坑MySQL 导入 .dat 文件最快的办法是 LOAD DATA INFILE但 TPC-DS 的文件格式有两个坑。第一行尾多一个|需要用LINES TERMINATED BY |\n来处理第二空字符串和 NULL 在文件里都表现为连续两个竖线无法区分。对于性能测试来说把空值统一当空字符串导入是可接受的只要两边处理方式一致就行。LOAD DATA INFILE /data/tpcds/100g/store_sales.dat INTO TABLE store_sales FIELDS TERMINATED BY | LINES TERMINATED BY |\n;导入前必须确认secure_file_priv和local_infile两个参数前者限制 LOAD DATA 能读的目录后者控制是否允许客户端本地文件导入。为了速度导入期间可以临时把innodb_flush_log_at_trx_commit设为 2sync_binlog设为 0导入完再改回来。这两个参数对导入速度的影响是数量级的从每小时几十 GB 提升到几百 GB 很常见。100GB 数据在单机 MySQL 上导入用上面这套优化大概一小时左右能完成前提是磁盘不是瓶颈。如果超过两小时先去看是不是 redo log 太小导致频繁 checkpoint或者是不是 autocommit 逐行提交导致事务开销过大——LOAD DATA 本身是批量提交的但如果表上有触发器或者唯一索引冲突会退化成逐行处理。3.4 TiDB 侧导入为什么必须用 LightningTiDB 用普通的 INSERT 或者 LOAD DATA 导入 100GB 数据会非常慢因为每一行都要走一次 Raft 复制网络往返和日志写入的开销叠加起来可能要跑一整天。正确做法是用 TiDB Lightning尤其是 local backend 模式它会把数据先在本地排序成 SST 文件然后直接 ingest 到 TiKV绕过 SQL 层和 Raft 复制速度能提升一个数量级以上。配置文件大概长这样[lightning] level info file /data/tidb-lightning.log [tikv-importer] backend local sorted-kv-dir /data/nvme/import [mydumper]>SELECT COUNT(*) FROM store_sales;如果不一致大概率是 CSV 解析配置有问题比如某个字段里出现了分隔符或者 terminator 没匹配上。TiDB Lightning 的日志里会有详细的错误行号和字段内容照着改就行。4. 查询生成与执行从 dsqgen 到计时脚本4.1 生成 99 条查询并做方言修正TPC-DS 的查询是用模板加上参数替换生成的dsqgen 支持多种方言包括 db2、oracle、sqlserver、netezza 和 ansi。MySQL 和 TiDB 最接近的是 netezza 和 ansi但还是需要后处理。./dsqgen -DIRECTORY ../query_templates \ -INPUT ../query_templates/templates.lst \ -VERBOSE Y \ -QUALIFY Y \ -SCALE 100 \ -DIALECT netezza \ -OUTPUT_DIR /data/tpcds/query生成之后会得到 query1.sql 到 query99.sql但其中有几条在 MySQL 上会报语法错。典型问题包括substring(x from 1 for 4)这种 ANSI 写法 MySQL 不认要改成substr(x,1,4)fetch first n rows only要改成limit n少数查询里的cast(... as decimal)精度声明不一致会报错。批量替换可以用 sedsed -i s/substring(\([^ ]*\) from \([0-9]*\) for \([0-9]*\))/substr(\1,\2,\3)/g query*.sql sed -i s/fetch first \([0-9]*\) rows only/limit \1/g query*.sql注意替换完一定要逐条试跑一遍确认没有语法错误再开始正式计时。带报错的查询如果被计入耗时统计会让整体结果偏低看起来很美好实际上是无效数据。TiDB 对 netezza 方言的兼容性比 MySQL 好一些因为它的语法解析器本身就是从 MySQL 扩展来的同时又支持不少标准 SQL 特性。但为了两边可比我建议用同一份修正后的 SQL 在两边跑而不是各用各的方言——这样才能保证测的是数据库能力不是方言适配能力。4.2 统计信息与预热策略导入完成后第一件事是收集统计信息。MySQL 用ANALYZE TABLETiDB 也是ANALYZE TABLE但 TiDB 的采样率和自动分析策略需要额外调整。对于大表TiDB 默认的采样量可能不足以让优化器准确估算选择率可以把tidb_analyze_version设为 2并对大表手动指定采样SET tidb_analyze_version 2; ANALYZE TABLE store_sales WITH 50000 BUCKETS;不过桶数设太大也会拖慢分析时间一般 256 到 1024 就够了50000 这个量级是给特别大的表用的实际测试里没必要。预热策略有两种。热数据跑法是在正式计时前把 99 条查询完整跑两遍第三遍才开始记录冷数据跑法是在每一条查询前清空 page cacheecho 3 /proc/sys/vm/drop_caches后者在分布式环境里很难做彻底因为 TiKV 的 block cache 是进程内的清 page cache 只能清掉操作系统层面的缓存。所以更推荐的做法是统一热数据 记录首次加载时间热数据结果反映稳定状态下的能力首次加载时间单独记录反映冷启动成本。两种结果都有意义但不要混在一起取平均。4.3 计时口径统一计时这件事细节决定可信度。最外层用客户端 wall time 测网络加执行的总时间这个最直观但包含了网络往返和结果集传输服务端耗时则能剔掉网络因素。我的做法是两个都记用客户端时间做对比基准用服务端时间做归因分析。统一脚本跑 99 条查询的大致思路#!/bin/bash OUT/data/tpcds/result mkdir -p $OUT for i in $(seq 1 99); do start$(date %s.%N) mysql -h127.0.0.1 -P4000 -uroot tpcds /data/tpcds/query/query$i.sql /dev/null 21 end$(date %s.%N) echo query$i $(echo $end - $start | bc) $OUT/timing.txt done这个脚本很粗糙但够用。要注意的是每次连接都会引入额外的握手开销如果查询本身只有几十毫秒这个开销会显著拉偏结果。更严谨的做法是一个连接里跑完 99 条用 SQL 文件拼接的方式执行或者在客户端里用程序控制连接复用。提示把每条查询的结果行数也记录下来。如果某条查询在一边返回 1000 行、另一边返回 0 行说明真的有问题去查 WHERE 条件里的日期边界或者 NULL 处理别急着相信那个快 10 倍的数字。5. 结果怎么读把数字翻译成结论5.1 单查询耗时分布和长尾99 条查询跑完最常见的结果形态是大部分查询在几百毫秒到两秒之间少数几条超过十秒甚至一分钟最慢的那条通常占了总耗时的很大比例。这种分布下平均值几乎没用你要看的是中位数、P90、P99 和总耗时。在我见过的多次不同规模的对比里SF100 量级下单机 MySQL 在很多轻量查询上并不输甚至更快因为它的执行路径短、没有网络 RPC、没有分布式事务开销。但一旦碰到需要扫描大事实表并做多层聚合的查询TiDB 的并行扫描就开始体现优势尤其是三节点同时读理论上扫描带宽是单机的两倍以上。真正拉开差距的是那几条涉及多个事实表 join 的复杂查询TiDB 可以把 join 的一侧下推到 TiKV 并行处理MySQL 只能在单进程里做 hash join。下面这张表是个示意性的归因具体数值会随硬件和参数浮动重点看为什么那一列查询类型相对表现主要原因单事实表 维度表 join两者接近MySQL 略快执行路径短无 RPC 开销大事实表全扫描聚合TiDB 明显快多节点并行扫描聚合下推多事实表交叉 joinTiDB 明显快分布式 join内存池更大子查询嵌套极深两者都慢差异大优化器能力差异TiDB 更能重写带窗口函数的排名查询取决于数据量内存排序成本和溢写策略不同5.2 冷热缓存和并发流的影响冷热差异能有多大在一张大表上冷缓存第一次访问要走磁盘热缓存直接命中内存单条查询差距可以是十倍以上。所以任何没有说明缓存状态的对比结果都要打问号。并发流的影响更微妙。TPC-DS 的官方测试模型里有一个 throughput test同时跑多个查询流看单位时间完成多少个查询。这个指标和单查询延迟经常是矛盾的单机 MySQL 在低并发下延迟低但并发一上来CPU 和 IO 很快饱和吞吐增长停滞甚至下降TiDB 单条查询可能慢一点但增加并发后能靠更多节点分摊吞吐曲线更平滑。如果你关心的是多人同时用的场景那吞吐比延迟更重要。我的建议是至少跑三档并发1、4、8记录每档的吞吐每秒完成查询数和 P95 延迟。这三个点连成的线比任何单点数据都更能说明问题。5.3 典型查询的逐条归因想真正理解结果别只看总分挑几条有代表性的查询单独分析。比如那些扫描 store_sales 和 catalog_sales 做对比的查询可以看执行计划里扫描的行数、下推的谓词比例、聚合发生在哪一层。TiDB 用EXPLAIN ANALYZE能看到每个算子的实际耗时和行数MySQL 用EXPLAIN ANALYZE也能看到类似的树形结构两边对照着看差异的来源就很清楚了。常见的归因结论有这几类一是扫描量差异TiDB 的 coprocessor 把过滤条件下推到 TiKV实际传输的数据量远小于逻辑扫描量二是 join 策略差异MySQL 可能选了 nested loop 而 TiDB 选了 hash join三是统计信息差异导致的行数估算偏差这个会直接反映在执行计划的选择上。把这几类原因标到具体查询上你的报告才不是一堆数字的堆砌。6. 常见问题与排查技巧实录6.1 导入阶段的典型故障导入慢是最常见的问题。MySQL 这边先看三个参数innodb_flush_log_at_trx_commit、sync_binlog、innodb_buffer_pool_size。前两个控制日志写入频率导入期间放宽能快好几倍第三个决定脏页能缓存多少太小会频繁刷盘。如果这些都调了还慢去看是不是表上建了太多二级索引每插一行都要维护一棵 B 树索引越多导入越慢。TiDB 这边导入失败的典型原因是 sorted-kv-dir 空间不够。这个目录的峰值占用可能是原始数据的两倍多100GB 的数据要预留 250GB 以上空间。另一个常见原因是 region 分裂和调度没跟上导入完成后如果立刻跑查询会发现很多请求打到一个 region 上形成热点等几分钟让 PD 调度完成就好了。6.2 执行阶段的问题排查查询报错集中在方言和类型转换上。日期比较是最容易翻车的地方TPC-DS 的查询里大量使用date_dim的日期范围过滤如果数据导入时日期格式没对上过滤条件会静默失效查询返回 0 行但你不会注意到。排查办法是在查询前后加计数校验或者直接对比两边的结果行数。执行计划不稳定是另一个大坑。TiDB 在统计信息刚收集完的短时间内plan cache 可能命中旧计划导致同一条 SQL 时快时慢。可以在测试前执行SET tidb_enable_prepared_plan_cache 0关掉计划缓存保证每次都重新生成计划代价是多了编译时间但一致性更好。MySQL 的 plan cache 概念不一样主要是 prepared statement 的缓存普通查询每次都要解析影响不大。6.3 结果不一致的排查顺序如果两边跑同一条查询结果行数不一样按这个顺序查排查顺序检查项常见原因1数据量是否一致导入时某张表少导或重复导2日期边界处理时区、日期格式、边界包含关系3NULL 值语义空字符串被当成 NULL 或反之4数值精度截断decimal 精度声明不同导致舍入差异5排序和 limit 组合没有确定性排序时 limit 结果随机6关联条件类型隐式转换字符串和数字比较的隐式转换规则不同这张表里最隐蔽的是第 5 项。TPC-DS 有些查询带order by ... limit N如果排序键有重复值两边的返回顺序可能不同行数一样但内容对不上。这种情况不算错误但如果你拿来做结果校验就会误判。7. 几个容易被忽略但影响很大的细节第一个细节是客户端的开销。用命令行客户端跑查询结果集要序列化成文本再输出如果查询返回几十万行序列化时间可能比查询本身还长。测性能时应该把结果集重定向到 /dev/null或者用-e加--quick参数减少缓冲再或者在程序里用游标逐行读但不做任何处理。这一项没做好轻量查询的耗时会被整体抬高掩盖真实差异。第二个细节是 TiDB 的 region 数量。小规模测试时如果 region 数量太少并行扫描的粒度不够多节点优势发挥不出来。SF100 的数据导入后 region 数量应该能达到几千个如果只有几百个说明 region 切分没做够可以手动 split 或者调小 region 大小再导一遍。这个细节在对比报告里经常被忽略但它直接影响 TiDB 的扫描并行度。第三个细节是操作系统层面的 CPU 调度。TiKV 是 CPU 密集型的NUMA 架构下如果线程和内存跨了节点访问延迟会明显增加。绑定 CPU 亲和性虽然麻烦但在做精确对比时值得做一遍。MySQL 侧同理InnoDB 的后台线程和查询线程如果抢同一个核波动会很大。第四个细节是结果校验的成本。完整的 99 条查询结果集可能几十 GB全量 diff 不现实。实用的做法是挑几条关键查询做 checksum或者对比聚合后的行数和几个数值字段的和。校验的目的是排除算错了所以看起来快这种情况不需要做到逐行一致。最后分享一个我在做这类对比时的习惯每次测试开跑之前把机器上所有无关进程关掉包括监控 agent、日志采集、定时任务然后用vmstat 1和iostat -x 1挂一个后台采集跑完之后看 CPU 空闲率和磁盘利用率曲线。如果发现某段时间 CPU 空闲率掉到 0 或者磁盘 await 飙到几百毫秒那段时间的查询耗时就要标记出来单独解释。这套动作多做几轮你会对自己机器的脾气摸得很清楚也就能分辨出哪些数字是数据库的能力哪些只是机器在喘气。