
做MySQL优化和架构选型这么多年有一个感受特别深很多人张口就能背“InnoDB支持事务、MyISAM不支持”可真到了生产环境选型、排查慢SQL、甚至面试聊到底层原理时能把 InnoDB、MyISAM、Memory 这三种存储引擎的差异讲透的人并不多。这篇文章我打算把这三大引擎的原理、存储结构、锁机制、适用场景全部拆开揉碎讲一遍重点放在“为什么”上——为什么InnoDB是默认选型为什么MyISAM索引更“瘦”却在写入场景容易翻车为什么Memory引擎的哈希索引只能做等值查询最后再把我这些年踩过的坑、排查过的线上问题整理成清单希望对正在做选型或准备面试的朋友有实际帮助。1. 为什么先聊存储引擎—— 一套服务层与引擎层分离的架构1.1 一条SQL在MySQL里到底是怎么走的要理解存储引擎得先从MySQL的整体架构说起。MySQL的逻辑架构可以粗分成两层上面是服务层Server层下面是存储引擎层Storage Engine Layer。服务层管的是连接管理、查询解析、查询优化、缓存、内置函数这些“通用事务”。一条SQL进来后先经过连接器做身份校验和权限检查然后到分析器做词法和语法解析接着优化器决定用什么索引、以什么顺序连接表最后通过执行器调用存储引擎的API去真正读写数据。换句话说服务层不关心你的数据是存在磁盘还是内存里不关心你是用B树还是哈希索引来组织数据——这些全部由存储引擎决定。这个设计思路非常像餐厅的前台和后厨前台负责点单、推荐菜品、算账后厨决定菜怎么做、用什么锅、什么火候。你是可以换厨师的前台不需要大改。1.2 存储引擎到底负责什么每个存储引擎负责的是最底层的数据管理具体包括数据在磁盘或内存里怎么组织、索引结构用B树还是哈希、并发控制用表锁还是行锁、事务怎么支持、崩溃后怎么恢复、是否支持外键和全文索引。MySQL允许同一实例里同时存在多种引擎——注意是一张表一个引擎不是整个数据库一个引擎。执行SHOW TABLE STATUS或者在information_schema.TABLES里查询ENGINE字段就能看到每张表当前用的引擎。SELECT TABLE_NAME, ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA your_db;这个特性意味着你在选型和迁移时可以区分对待不同的表而不是一刀切。但也正因为如此很多人容易忽略一个核心问题不同引擎的索引结构、锁粒度、事务能力完全不同你不能默认所有表都用一个姿势去优化。1.3 为什么面试和实践中总绕不开这个老话题存储引擎几乎是MySQL面试的必问题因为它是索引、事务、锁、MVCC这些核心概念的总入口。比如问你“索引为什么能加速查询”根本答案是存储引擎里的索引结构决定的问你“为什么InnoDB要用自增主键”答案是在聚簇索引结构下自增主键能避免页分裂问你“为什么MyISAM查询比InnoDB快”答案同样要从索引存储结构上去找。而在实际工作中选错引擎的代价可能要到业务量上来之后才暴露。我见过有人把所有表都设成MyISAM结果并发一高全表锁导致写入排队最终把一个简单的插入操作拖成秒级延迟也见过有人用Memory引擎做会话临时表结果实例一重启数据全没了才发现“快”是有代价的。这些问题的根源都是没有真正理解引擎之间的设计取舍。所以这篇文章我会用一个核心思路贯穿一切选型都是一种取舍了解引擎的本质就是了解你愿意放弃什么来换取什么。2. InnoDB聚簇索引、MVCC与redo log一个都不能少2.1 InnoDB的核心特性一览InnoDB从MySQL 5.5开始就是默认存储引擎8.0时代更是唯一全面支持事务、行级锁、崩溃恢复的常用引擎。整体特性可以用一张表概括特性InnoDB事务支持支持ACID配合redo log和undo log实现锁粒度行级锁基于索引实现索引结构聚簇索引二级索引MVCC支持通过undo log版本链和Read View实现外键支持全文索引5.6开始支持崩溃恢复支持依赖redo log doublewrite buffer数据存储表数据按主键聚集存放在ibd文件在深入细节之前记住一句话InnoDB设计的核心目标就是数据安全与高并发写入。它宁愿多做几次磁盘顺序写redo log也要保证崩溃后数据不丢宁愿用更复杂的MVCC机制也要让读写互不阻塞。2.2 聚簇索引主键就是数据的物理顺序InnoDB默认的主键索引是聚簇索引这决定了它的物理存储方式和MyISAM有本质区别。聚簇索引的叶子节点直接存储整行数据也就是说表数据本身就是按主键顺序排列的一棵B树。当你执行SELECT * FROM user WHERE id 100时InnoDB可以直接沿着主键索引找到包含第100号行的叶子节点直接把整行数据拿出来不需要额外的“回表”操作。但这里有个重要推论二级索引也就是非主键索引的叶子节点存储的不是行数据而是主键值。假设你在user表的name字段上建了一个二级索引查询SELECT * FROM user WHERE name 张三时InnoDB会先通过name索引找到“张三”对应的主键id再拿这个主键到聚簇索引里查一次——这个过程就叫回表。这个设计衍生出一系列经典优化策略。比如覆盖索引——如果查询需要的字段恰好都包含在二级索引里包括主键MySQL会直接利用索引字段返回结果连回表都省了这是很多慢查询优化的核心思路。再比如“InnoDB为什么推荐用自增主键”。如果主键是自增整数新插入的行总是追加到B树的末尾页分裂的概率很低。如果主键是UUID这种随机字符串插入时主键值忽大忽小B树中间页会频繁发生分裂造成大量随机IO和索引碎片。提示所谓的“行锁”在InnoDB里其实是“索引锁”锁是加在索引记录上的。如果一条SQL没有命中任何索引InnoDB会退化为锁定所有扫描到的记录效果近似全表锁。这也是为什么很多开发同学困惑“明明InnoDB支持行锁为什么这个UPDATE把整个表锁住了”——大概率是SQL里的WHERE条件没走索引。2.3 MVCC与undo log如何做到读写互不阻塞InnoDB的又一个核心设计是MVCC多版本并发控制。它解决的问题很明确在高并发下读操作不应该阻塞写操作写操作也不应该阻塞读操作。MVCC的实现依赖两个东西隐藏列和undo log版本链。InnoDB在每行记录后面隐藏了两个字段一个是事务IDDB_TRX_ID一个是回滚指针DB_ROLL_PTR。当一行数据被修改时旧版本的数据不会立刻删除而是通过回滚指针串联成一条版本链链上的每个版本都记录了“这个版本是哪个事务改的”。读操作执行时InnoDB会生成一个Read View读视图它记录了当前系统里活跃事务的ID列表。通过比较行版本的事务ID和Read View里的信息InnoDB就能判断这行数据的某个版本对当前事务是否可见从而实现不同隔离级别下的快照读。拿默认的REPEATABLE READ可重复读隔离级别来说事务第一次执行SELECT时生成Read View之后整个事务期间都复用这个视图。这样一来事务内多次执行同一条查询看到的结果始终一致——这就是“可重复读”的实现原理也是很多人面试时被问到的“MVCC为什么能解决不可重复读”的答案。需要注意的是MVCC解决的是快照读的问题。对于SELECT ... FOR UPDATE这种加锁读InnoDB还是会走当前读读取最新已提交版本并且对相关记录加锁。理解这个区别对排查“为什么两个事务互相等待”非常关键。2.4 崩溃恢复redo log和doublewrite是如何兜底的InnoDB在数据安全上最值得称道的设计是WALWrite-Ahead Logging机制。简单说在对数据页进行修改之前先将修改操作以日志形式顺序写入redo log。redo log是磁盘上的顺序写速度比随机写快得多。即使数据库在数据页还没刷到磁盘时就崩溃了重启后也能通过redo log重放操作把数据恢复过来。我见过不少人对redo log存在一个误区以为它是为了“提速”才存在的。实际上redo log的本质是用顺序写换随机写——把昂贵的随机刷盘延后把崩溃恢复能力前置。这样做既保证了事务的持久性Durability又避免了每次提交都强制把脏页刷到磁盘导致的性能暴跌。还有个容易忽视的细节是doublewrite buffer双写缓冲。理论上有了redo log为什么还需要双写因为InnoDB的数据页一般是16KB而操作系统页大小通常是4KB刷盘时如果遇到断电等异常可能出现一个16KB的页只写了一部分即“页半写”这种物理损坏是redo log无法修复的——redo log记录的是逻辑操作不能重建一个物理损坏的页。doublewrite buffer会先把页的副本写入一个单独区域再真正刷盘如果发现页损坏就用副本进行恢复。注意MySQL 8.0.20以后doublewrite buffer默认从独立的dblwr文件存储。日常运维通常不用手动调整但如果你的存储设备本身具备原子写能力部分企业级SSD可以考虑关闭doublewrite以省下一部分写放大开销——这个决定需要充分评估不是生产环境默认推荐的做法。3. MyISAM非事务表锁引擎还有它的价值与局限3.1 MyISAM到底有哪些特性MyISAM曾是MySQL的默认引擎5.5之前至今仍以“查询快、占用空间小”著称。它的核心特性包括不支持事务、不支持外键、使用表级锁、索引和数据分开存储、支持全文索引、崩溃恢复能力很弱。从设计哲学上看MyISAM把“读性能优先”放在了“数据安全”前面。它没有redo log、没有MVCC所以读写模型非常简单——查询就是快速扫索引和数据文件写入就是加全表锁然后改文件。特性MyISAM事务支持不支持锁粒度表级锁索引结构非聚簇索引叶子节点存行地址MVCC不支持外键不支持全文索引支持崩溃恢复基本没有需要repair table数据存储.MYD数据文件 .MYI索引文件分离3.2 索引结构为什么MyISAM索引“瘦”MyISAM的索引也是B树但它是非聚簇的。索引文件.MYI和数据文件.MYD是分开的索引树的叶子节点存储的不是整行数据而是指向物理行数据的地址行指针。这意味着MyISAM执行一次查询路径是“索引树 → 叶子节点得到行地址 → 按地址访问数据文件”。对比InnoDB的聚簇索引MyISAM所有索引都是“二级索引”都需要额外的一次数据文件访问。从这点看MyISAM的主键索引其实并不天然比InnoDB快。那为什么在只读场景下MyISAM查询速度依然可观一方面是因为它的索引树更“紧凑”索引文件里存的只是键值和行指针没有InnoDB聚簇索引里完整行数据那么大体积同一页能缓存更多索引条目减少了磁盘IO另一方面MyISAM没有MVCC版本链也没有事务可见性判断读取路径非常短CPU开销更小。对大量全表扫描或纯查询场景这种简单结构反而有优势。3.3 为什么MyISAM在写入场景容易“翻车”MyISAM的写入劣势根子就在表级锁。不管是UPDATE还是INSERT都会对整个表加写锁其他连接的所有读写操作都得排队。在并发量小的场景下这不算问题可一旦写入请求增多性能会断崖式下降——不是单条写入慢而是整个表的吞吐被锁卡死。更麻烦的是MyISAM没有崩溃恢复机制。如果实例崩溃.MYD和.MYI文件可能不一致启动后需要手动执行REPAIR TABLE或myisamchk修复。这种修复在大表上非常耗时而且只能修复逻辑不一致问题遇到页损坏丢失数据的情况就无力回天了。我维护过一个数据仓库里面大量历史报表表用的是MyISAM。白天查询完全没问题可一旦深夜批处理往里面写入新数据所有查询都会被阻塞监控图上能看到一个明显的“锁等待尖刺”。后来把核心报表表切换成InnoDB锁等待问题才彻底消失。这个案例足以说明只读场景里MyISAM可以风光混合读写场景里它很容易变成资源瓶颈。3.4 现在还推荐用MyISAM吗我的建议是常规业务表一律别用MyISAM除非你有非常明确的理由。MySQL 5.6之后InnoDB补齐了全文索引能力MyISAM引以为傲的全文搜索优势也没了。而InnoDB的行锁、MVCC、崩溃恢复带来的收益是任何业务场景都需要的。如果你还在用MyISAM大概率是为了接手老系统或迁移前的过渡状态。一种仍有人使用的边缘场景是只读的归档/分析表数据导入一次后续只有SELECT不涉及高并发写入。这种情况下MyISAM的紧凑索引和全表扫描能力有一定价值。但即便在这种场景我也会先评估下InnoDB的压缩表和分区表因为同样的数据安全能力下InnoDB在8.0版本中的性能已经足够好。4. Memory引擎快是真的快但这些坑你必须知道4.1 Memory引擎的底层机制Memory引擎以前叫HEAP把数据全部存在内存里服务器重启后数据自动清空表结构保留。它最直观的特点就是“快”——因为没有磁盘IO读写路径极短。CREATE TABLE cache_table ( id INT PRIMARY KEY, value VARCHAR(100) ) ENGINE MEMORY;看到“数据丢失”四个字很多人第一反应是“这还能用吗”其实Memory引擎在特定场景下是有明确用武之地的比如临时表、缓存表、会话级中间结果。关键在于你把它当“缓存”而不是“数据”来用。Memory引擎的底层结构非常“朴素”表数据按行存放在内存数组中它的索引默认使用哈希索引也可以显式指定使用B-Tree索引。由于没有磁盘文件它也没有崩溃恢复的需求——崩溃之后数据本来就是该丢的。4.2 哈希索引与B-Tree索引Memory引擎特有的选择题Memory引擎最容易被忽视的点就在索引类型上。默认的哈希索引有非常强的适用条件只支持等值查询、IN不支持范围查询、、BETWEEN也不支持按索引顺序排序优化。如果你执行的是WHERE value foo哈希索引会直接计算哈希定位速度极快但如果是WHERE value foo那就只能全表扫描了。如果业务确实需要范围查询可以建索引时显式指定BTREECREATE TABLE cache_table ( id INT PRIMARY KEY, value VARCHAR(100), KEY idx_value USING BTREE (value) ) ENGINE MEMORY;但即便用了B-Tree索引Memory引擎仍然是全表锁的引擎——写入时整个表被锁住并发写入场景下优势会被抵消。对高并发缓存业务来说与其用Memory表自己做缓存不如直接用Redis或者引入本地缓存组件锁粒度、数据淘汰策略、持久化能力都更优。4.3 Memory引擎的几个经典陷阱第一个陷阱是max_heap_table_size限制。Memory表的大小由这个参数控制默认值在不同版本里可能只有16MB或64MB。一张表数据量超过阈值时会直接报The table is full错误。我接手过一个案例业务方用Memory表做短期统计结果缓存跑着跑着突然报错查了半天才发现是表大小触顶。所以使用前一定要先评估数据量并通过SET GLOBAL max_heap_table_size或session级别调整。第二个陷阱是变长字段的内存浪费。Memory引擎对VARCHAR的支持是按最大长度分配内存的也就是说一张表里一个VARCHAR(1000)即使只存了“hello”几个字符每条记录也会占用约1000字节的空间。这会大幅抬高表容量触顶风险也更浪费宝贵内存。建议在非必要情况下使用定长CHAR或缩短长度。第三个陷阱是数据易失性。实例重启、主备切换、甚至一次正常的MySQL重启Memory表的数据都会清空。如果业务逻辑没有“重新加载缓存数据”的兜底机制重启后出现缓存空缺一瞬间的查询压力可能直接打穿数据库。第四个陷阱是管理模式老化。Memory引擎本身没有被积极开发很多限制比如不支持TEXT/BLOB字段、不支持外键、全文索引一直存在。表级锁、内存扩容、数据淘汰策略都不如专业缓存系统完善在MySQL 8.0时代我的态度是Memory引擎可以学、可以用于临时表但线上核心业务不建议靠它扛流量。4.4 Memory引擎的适用场景和替代方案Memory引擎最合适的场景其实是两种一是会话级临时表用于存储连接私有的中间计算结果比如一次复杂查询中的多条中间数据集二是数据量可控的字典缓存表比如把几千行配置信息加载到内存表里频繁读取。如果你需要的是全局共享缓存、高性能读写、数据自动淘汰建议用Redis或Memcached取代Memory表。如果你需要的是SQL级别的临时结果可以优先考虑MySQL的临时表机制默认也支持磁盘临时表而不是手动建Memory表。提示MySQL优化器在执行复杂GROUP BY或ORDER BY时如果排序大小超过sort_buffer_size会自动使用临时表。在高版本MySQL中内部临时表已经支持从磁盘临时文件转内存临时表的策略取决于内部临时表引擎设置日常运维不推荐把内部临时表强制指定为Memory引擎因为大结果集会瞬间打爆内存。5. 引擎选型决策与切换实战5.1 选型判断的三个核心标准面对一张新表怎么确定用哪个引擎我的决策过程可以浓缩成三个问题第一这表需要事务吗如果需要ACID、需要回滚、需要数据一致性保证直接选InnoDB不用犹豫。绝大多数业务表订单、用户、库存、账户流水都属于这一类。第二读写比例是多少如果是纯粹的“一次写入、多次查询”且写入方是自己导入的批处理不涉及高并发在线写入可以考虑MyISAM或归档引擎ARCHIVE。但只要涉及在线混合读写InnoDB基本是唯一选择。第三数据是强持久化要求吗如果数据丢失会带来严重业务事故比如订单、支付记录引擎必须选InnoDB并配合合理的刷盘参数innodb_flush_log_at_trx_commit保证事务持久性。如果是可重建的缓存数据才谈得上考虑Memory这类内存型引擎。生产环境里我踩过的一个真实教训是有人为了“查询快”把账户流水表改成MyISAM结果某天一条UPDATE因为表锁阻塞了所有SELECT前端直接报超时。事后追查原因发现这条UPDATE只需要更新几行但MyISAM锁的是整表。这个案例再次验证了那句话——锁粒度决定了高并发下的写路径。5.2 修改引擎的三种实操方式方式一直接修改单张表。ALTER TABLE my_table ENGINE InnoDB;这是最常用的方式但注意大表执行时可能会锁表并且重建整表数据耗时很长。如果线上环境有主从复制建议在低峰期执行并关注从库延迟。方式二建表时指定引擎。CREATE TABLE orders ( id BIGINT PRIMARY KEY AUTO_INCREMENT, amount DECIMAL(10,2) ) ENGINE InnoDB;如果业务统一使用InnoDB这一步基本上是无感知的。方式三修改配置文件默认引擎。[mysqld] default-storage-engine InnoDB修改后记得重启MySQL否则不生效。5.3 从MyISAM切换到InnoDB的完整步骤和注意点如果要把一批存量表从MyISAM切到InnoDB我建议按下面的流程走先做评估查清楚哪些表还是MyISAM以及它们的数据量、索引数量、关联的外键约束。再逐表执行切换切换顺序建议从核心表开始先进行单张表切换并观察性能与锁等待情况。切换前一定备份最好用mysqldump或物理备份不能在没有任何回滚手段的情况下直接操作。-- 查看所有非InnoDB表 SELECT table_schema, table_name, engine FROM information_schema.tables WHERE engine InnoDB AND table_schema NOT IN (mysql, performance_schema, sys, information_schema);生成的修改语句可以这样批量拼接SELECT CONCAT(ALTER TABLE , table_schema, ., table_name, ENGINE InnoDB;) FROM information_schema.tables WHERE engine InnoDB AND table_schema NOT IN (mysql, performance_schema, sys, information_schema);实际切换时有一个高频坑表和索引的锁行为、自增锁行为、全文本索引行为都不一样。如果原表带有全文索引要确认MySQL版本支持InnoDB全文索引5.6。如果使用ALTER TABLE直接切换在低版本MySQL或大表场景中会锁住整张表导致业务只读窗口。谨慎的做法是使用pt-online-schema-change或gh-ost这类在线DDL工具它们通过创建影子表同步增量数据的方式把DDL对业务的影响降到最低。切换完成后还要关注几个参数innodb_buffer_pool_size是否够大、innodb_flush_log_at_trx_commit是否设置合理、是否存在大量碎裂的二级索引。MyISAM表切换成InnoDB后行锁替代表锁通常并发写入能力会有明显提升但如果Buffer Pool太小查询性能反而可能变差。5.4 日常巡检中如何发现引擎健康问题我平时巡检MySQL实例时会额外关注三类和引擎相关的问题第一非InnoDB表占比是否过高。常规业务库如果还有大量MyISAM表通常意味着老系统遗留技术债需要列入迁移计划。第二锁等待指标是否异常。通过SHOW ENGINE INNODB STATUS检查LATEST DETECTED DEADLOCK和LOCK WAIT部分可以定位到阻塞源头。而MyISAM引擎导致的写入阻塞往往表现为大量Waiting for table level lock状态。第三内存型表容量是否接近上限。使用SELECT table_name, data_length FROM information_schema.tables WHERE engine MEMORY配合max_heap_table_size来判断是否存在触顶风险。6. 常见问题与坑位实录6.1 常见问题速查表现象可能原因排查思路大表ALTER切换引擎耗时很长系统重建整表数据和索引评估表大小使用在线DDL工具低峰执行写入时大量查询卡死MyISAM表级锁确认表引擎优先切换InnoDBMemory表报“The table is full”数据量超过max_heap_table_size调大参数或改用Redis缓存实例重启后缓存数据消失Memory表数据易失确认业务是否有重建缓存逻辑UPDATE阻塞所有读未命中索引导致InnoDB行锁退化为大量记录锁利用EXPLAIN检查执行计划补索引MyISAM表损坏非正常关机/崩溃等执行REPAIR TABLE或myisamchk恢复Memory表范围查询奇慢哈希索引不支持范围查询改用BTREE索引或重新评估数据存储方案6.2 排查MyISAM表损坏与恢复的完整路径MyISAM损坏这个问题现在还有不少老系统会遇到。它的表现通常是Table xxx is marked as crashed and should be repaired或者Cant open file: xxx.MYI。遇到这种情况第一反应不是直接删表重来而是先备份原文件然后使用CHECK TABLE判断损坏范围CHECK TABLE your_table;如果确认损坏再执行修复REPAIR TABLE your_table;或者使用MyISAM自带的shell工具myisamchk需要先停止MySQL服务或至少确保表不被访问myisamchk --recover /var/lib/mysql/your_db/your_table需要特别提醒的是REPAIR TABLE只能修复索引与数据之间的逻辑不一致。如果数据页本身已经出现物理损坏比如IO层故障导致数据写入错乱修复也救不回已经丢失的数据。这也是为什么我一直强调MyISAM更适合归档类、可重建的表而绝不适合承载核心交易数据。6.3 面试里关于引擎的几个高频追问面试聊到这个话题面试官一般不会停在“InnoDB支持事务”这个层面。我整理几个高频追问每个都能展开聊很久第一个追问为什么InnoDB用自增主键最好答案核心在聚簇索引的页分裂问题。随机主键导致B树中间节点频繁分裂产生碎片和随机IO对写入性能伤害明显。第二个追问Memory引擎的哈希索引为什么只能等值查询因为哈希索引存储的是哈希值和行指针无法用于排序和范围扫描。B-Tree索引则因为有序性天然支持范围查询和ORDER BY优化。第三个追问INNODB的事务隔离级别怎么支撑MVCC可重复读默认使用快照读通过Read View复用实现事务内一致读读已提交则每次SELECT生成新的Read View。两者在使用同样的MVCC机制下行为差异就在Read View的生成时机。第四个追问主键索引和唯一索引的区别是什么主键索引是聚簇索引直接决定数据物理组织方式唯一索引只是约束值唯一不影响数据存放。在InnoDB中一张表只能有一个主键索引但可以有多个唯一索引。这些追问背后都指向同一个核心你能不能用“索引结构 → 锁行为 → 事务实现 → 选型取舍”这条链路把问题串起来。这也是这篇博文想给你留下的核心框架。6.4 一个从MyISAM切InnoDB的实战案例最后分享一个我处理过的案例某业务高峰期订单查询模块出现大量 “Waiting for table level lock”监控显示所有慢查询都是对一张用户订单表的SELECT。当时这张表约500万行引擎是MyISAM。表象上是“查询慢”但根因却是某个后台任务正在批量更新订单状态持有了整表的写锁所有查询只能排队等待。排查过程很简单先查SHOW PROCESSLIST发现大量会话状态是Waiting for table level lock再查看表引擎确认是MyISAM。解决思路是先止血让后台任务改在低峰期执行然后把订单表切换为InnoDB。切换后行锁让不同行的更新不再互相阻塞查询等待尖刺消失。这个案例说明很多时候所谓“慢查询”并不是SQL写得不好而是引擎的锁机制在并发场景下天然吃亏。MySQL的优化永远是从理解底层存储机制开始的。我个人这几年运维的最深体会是存储引擎不是“哪个好就用哪个”的选择题而是“你愿意在哪些维度做取舍”的判断题。对核心业务InnoDB几乎是不会错的选择对只读归档MyISAM可以保留但有必要评估风险对纯缓存需求Memory不如Redis。真正懂MySQL的人看一张表的结构和数据量基本就能判断这个表适合什么引擎、会有什么隐患。希望这篇文章能帮你建立起这种判断力。