目录一索引结构1. B-Tree平衡多路搜索树2.BTree3.通过BTree来索引4.通过Hash来索引二语法1. 创建索引的基础语法2. 不同类型的索引创建语法3. 复合索引多列索引语法4. 索引选项指定长度与排序方式5. 删除索引的语法6. 查看索引的语法7. 索引在查询语句中的使用隐式语法8. 修改表时添加索引综合语法9. 索引的约束与注意事项语法层面需了解三性能分析1.查询频次① 查看各类 SQL 执行频次命令② 查询频次对索引设计的决策指导2. 慢查询日志① 启用与核心参数配置② 慢查询日志的分析方法③ 慢查询日志对索引优化的指导意义3. show profiles① 启用与查看② 深度剖析特定 SQL③ 性能调优的危险信号4. explain执行计划① 使用语法② 核心返回字段及分析意义四使用规则1. 最左前缀法则最左匹配原则① 核心规则解析② 范围查询导致右侧索引失效③ 索引列上的各种“骚操作”导致失效2. 索引失效的常见场景① 违反最左前缀法则② 联合索引中范围查询右侧的列失效③ 在索引列上进行运算或函数操作④ 存在隐式类型转换⑤ 模糊查询时通配符 % 在开头⑥ 使用 OR 连接条件时缺失索引⑦ 估计全表扫描比索引快数据区分度低五、 索引的设计原则1. 核心针对性原则2. 数量与空间控制原则3. 业务防错与优化原则索引就像是一本书的目录对于数据库来说它有以下三大作用极大地加快数据库检索的速度。显著降低数据的排序Order By和分组Group By成本将“随机 I/O”变成“顺序 I/O”但是应用它还是有缺点的。牺牲了’增删改‘的速度。MySQL不仅要更新数据本身还要同步去维护和调整对应的索引树占用了额外的物理空间。它本身也是一种数据要写入磁盘文件的当数据量多的时候也算是一笔硬件成本。一索引结构先了解索引的结构。在 MySQL尤其是最常用的 InnoDB 存储引擎中索引的底层结构绝大多数都是 BTreeB树。但是我们可以先了解一下简单的Btree。注可以在这个网站上动态地来看添加数据时是什么样的。1. B-Tree平衡多路搜索树B-tree是一种数据结构。一个 阶数为 m 的 B-Tree 满足每个节点最多有 m 个子节点。除根节点外每个非叶子节点至少有 ⌈m/2⌉ 个子节点。根节点至少有 2 个子节点除非树只有一个节点。所有叶子节点位于同一层完全平衡。向一个5阶B-Tree依次添加1、2、3、4时它们按顺序放在同一个节点里此时节点有4个数刚好满员。再添加5时因为5比4大会放到4的右边此时节点有5个数超过了5阶规定的上限最多4个于是将中间的那个数即3向上提出来成为父节点3左边的数1、2形成一个左子节点3右边的数4、5形成一个右子节点。如下是存储了1-10的B-Tree2.BTree和B-Tree大致相同只不过提上去的那个中间数字依旧会存储到子节点中也就是说最底层的叶子节点会包含完整数据。上层的父节点仅仅是用来做导航的。同时左子节点和右子节点还会拉起一条双向链表。3.通过BTree来索引在 MySQL 中特别是最核心的 InnoDB 存储引擎BTree 的应用可以说是精妙绝伦。它并不是把索引孤立地存在某个地方而是直接用 BTree 结构把你的数据表组织了起来。先了解下索引的分类包括聚簇索引和二级索引。在 InnoDB 中表中的数据行本身就是存放在 BTree 的叶子节点上的。这棵树被称为聚簇索引Clustered Index。假设我们有一张用户表主键是 id还有 name 和 age 字段。这棵聚簇索引树的结构如下非叶子节点只存主键 id 的值和指向下一层页的指针比如id 1~10 往左走id 11~20 往右走。 叶子节点最底层存放的是整行完整的数据包含 id, name, age。而二级索引通常和聚簇索引不一样。非叶子节点存的是 name 的值和指针。 叶子节点最底层存的是 name 的值 对应的主键 id。它没有完整的行数据也就是说通过二级索引得到主键最后还要通过聚簇索引回表查询。但是不一定会回表查询有时候会覆盖索引。比如说我表里面的name已经有索引了。然后我只需要id和名字这两列。那么我在查name这个索引的时候就已经有了name和id了这就不需要去走第一颗主键树了。就会直接把结果返回。4.通过Hash来索引在数据库索引中除了我们前面大篇幅讲的 BTree另一种重要的索引结构就是 Hash 索引哈希索引。1. Hash 索引是怎么工作的它的底层结构实际上就是一个哈希表Hash Table。当你在表的某个字段比如name上建立了 Hash 索引MySQL 会对每一行的name值计算一个 Hash 值比如“张三”算出来是 9527。在内存中MySQL 会维护一个哈希表把 Hash 值 9527 指向对应的数据行磁盘地址指针。当你执行SELECT * FROM users WHERE name 张三;时MySQL 瞬间算出“张三”的 Hash 值是 9527然后直接在哈希表中定位到数据行的地址直接去拿数据。2. Hash 索引的“天花板”优势等值查询快到飞起如果只论等值查询用、IN、查特定的某个人或某个值Hash 索引的时间复杂度是O ( 1 ) O(1)O(1)。这意味着无论你的表里有一万条数据还是一千万条数据它基本上只需要 1 次定位就能找到数据。在这一点上需要 3~4 次磁盘 I/O 的 BTree 在它面前也只能甘拜下风。既然 Hash 索引这么快为什么 InnoDB 存储引擎的默认索引结构依然是 BTree 呢因为 Hash 索引的缺点和它的优点一样突出。致命伤无法进行范围查询Hash 算法算出来的值是无序的。比如“年龄 18”的 Hash 值可能是 4321“年龄 19”的 Hash 值可能是 1102。它们在哈希表里的位置天各一方。如果你执行 WHERE age 18Hash 索引就彻底废了因为它没办法在哈希表里顺着往下找只能苦哈哈地去全表扫描。无法用于排序Order By同理因为哈希表本身是无序的当你要求 ORDER BY age 时Hash 索引完全帮不上忙MySQL 必须在内存里重新进行文件排序Filesort。不支持联合索引的“最左匹配原则”联合索引是把多个字段拼在一起算 Hash 值。例如你对 (name, age) 建立 Hash 索引算的是它们整体的 Hash 值。如果你查询时只用了 WHERE name ‘张三’由于缺少 age算不出整体的 Hash 值索引直接失效。哈希碰撞Collision问题如果两个不同的名字刚好算出了同一个 Hash 值这就叫哈希碰撞。此时哈希表里对应的位置会拉起一条链表MySQL 得顺着链表一个一个去比对如果碰撞严重查询效率会断崖式下跌。二语法MySQL 中索引的语法从简单到复杂主要包括创建索引、删除索引、查看索引以及索引在查询中的使用方式。1. 创建索引的基础语法最简单的建表时直接定义索引CREATETABLEuser(idINTPRIMARYKEY,-- 主键索引自动创建nameVARCHAR(50),ageINT,INDEXidx_name(name)-- 普通索引);为已有表添加索引CREATEINDEXidx_nameONuser(name);或者使用ALTER TABLE语句ALTERTABLEuserADDINDEXidx_name(name);2. 不同类型的索引创建语法唯一索引UNIQUE要求索引列的值不能重复允许 NULL但只能有一个 NULLCREATEUNIQUEINDEXidx_emailONuser(email);主键索引PRIMARY KEY一种特殊的唯一索引不允许 NULL一张表只能有一个ALTERTABLEuserADDPRIMARYKEY(id);全文索引FULLTEXT用于全文检索对CHAR、VARCHAR、TEXT列有效CREATEFULLTEXTINDEXidx_contentONarticle(content);空间索引SPATIAL用于地理数据要求列类型为GEOMETRY等CREATESPATIALINDEXidx_locationONplace(location);3. 复合索引多列索引语法按多列建立索引遵循最左前缀原则CREATEINDEXidx_name_ageONuser(name,age);查询时如果条件用到name或者name age都能使用该索引但仅用age则无法使用。4. 索引选项指定长度与排序方式前缀索引只索引列的前 N 个字符可节省空间对长字符串很有用CREATEINDEXidx_name_prefixONuser(name(10));指定排序方向MySQL 8.0 起支持降序索引之前只支持升序CREATEINDEXidx_age_descONuser(ageDESC);5. 删除索引的语法-- 通过索引名删除DROPINDEXidx_nameONuser;-- 使用 ALTER TABLE 删除ALTERTABLEuserDROPINDEXidx_name;-- 删除主键索引ALTERTABLEuserDROPPRIMARYKEY;6. 查看索引的语法-- 查看表中所有索引SHOWINDEXFROMuser;-- 更详细的信息包括索引类型、基数等SHOWINDEXFROMuser\G;-- 垂直显示-- 使用 information_schema 查询SELECT*FROMinformation_schema.STATISTICSWHEREtable_nameuser;7. 索引在查询语句中的使用隐式语法虽然索引是用CREATE INDEX建的但查询时自动使用不必在SELECT中写任何索引关键字。例如-- 假设 name 上有索引下面这条查询会自动使用该索引SELECT*FROMuserWHEREname张三;但也可以强制指定索引不推荐主要用于测试或特定优化场景SELECT*FROMuserFORCEINDEX(idx_name)WHEREname张三;8. 修改表时添加索引综合语法-- 可以在一句 ALTER TABLE 中添加多个索引ALTERTABLEuserADDINDEXidx_name(name),ADDUNIQUEINDEXidx_email(email),ADDFULLTEXTINDEXidx_bio(bio);9. 索引的约束与注意事项语法层面需了解索引命名可省略MySQL 会自动生成建议自定义有意义的名字如idx_列名。索引长度限制InnoDB 引擎单索引最大长度为 3072 字节取决于行格式。索引与存储引擎全文索引和空间索引在 MyISAM 和 InnoDB 上的支持度不同。显示使用索引的语法USE INDEX建议和IGNORE INDEX忽略SELECT*FROMuserUSEINDEX(idx_name)WHEREname李四;SELECT*FROMuserIGNOREINDEX(idx_name)WHEREname王五;以上语法从建表时创建到查询时使用由易到难涵盖了 MySQL 索引最常用的操作。实际开发中最常用的是CREATE INDEX和ALTER TABLE ADD INDEX两种方式。三性能分析可以通过以下方法来分析当前数据库的性能。1.查询频次通过查看数据库全局或当前会话的各种操作频次可以清晰地分析出当前数据库是以主导查询读密集型还是以主对增删改写密集型为主从而决定索引的优化重心。① 查看各类 SQL 执行频次命令在 MySQL 客户端中可以使用如下命令查询全局各类 SQL 的累计执行次数。该命令通常使用LIKE匹配七个字符长_占位符的统计项SHOWGLOBALSTATUSLIKECom_______;执行后其核心返回指标及性能分析意义如下Com_select查询SELECT操作的次数。核心指标。若该值远大于其他项说明系统为“读多写少”建立和优化索引的收益最高。Com_insert插入INSERT操作的次数。若该值过高说明写入频繁此时建索引应保持克制避免过多的索引拖慢写入性能。Com_update更新UPDATE操作的次数。频繁更新的字段不适合建索引因为每次更新都会触发索引树的重新调整。Com_delete删除DELETE操作的次数。频繁删除会导致索引页产生碎片空洞后续需考虑配合OPTIMIZE TABLE整理。注意以上参数是从数据库启动开始刷新的累计值。如需查看当前会话的频次可将GLOBAL替换为SESSION。② 查询频次对索引设计的决策指导读密集型Com_select占比大如 80%应全力以赴优化索引。因为写操作极少维护索引所带来的性能损耗在庞大的读收益面前微不足道。写密集型Com_insert/Com_update占比大索引设计应遵循“精准、精简”原则。优先建立能覆盖多条件的联合索引来替代多个单列索引尽量用最少的索引树去满足最高频的查询。2. 慢查询日志慢查询日志Slow Query Log是 MySQL 提供的一种用来记录执行时间超过指定阈值以及扫描行数过多的 SQL 语句的日志。它是定位系统性能瓶颈、精准抓取需要优化索引的 SQL 的核心工具。① 启用与核心参数配置慢查询日志默认是关闭的通常需要在开发测试环境或排查问题时开启。可以通过以下命令查看和临时修改相关配置参数若想永久生效需修改my.cnf配置文件-- 查看慢查询日志是否开启以及日志文件路径SHOWVARIABLESLIKEslow_query_log%;-- 开启慢查询日志1为开启0为关闭SETGLOBALslow_query_log1;-- 查看并设置慢查询的时间阈值单位秒支持微秒。此处设置为执行超过1秒则记录SHOWVARIABLESLIKElong_query_time;SETGLOBALlong_query_time1;-- 开启记录没有使用索引的查询可选SETGLOBALlog_queries_not_using_indexes1;② 慢查询日志的分析方法当系统运行一段时间后慢查询日志文件中会堆积大量的文本数据。直接查看原始日志效率较低生产环境中通常采用以下两种方式进行分析**自带工具mysqldumpslow**MySQL 官方提供的命令行工具可以对慢查询日志进行分类汇总、排序和去重。# 按照执行次数(c)排序显示前10条最慢的 SQLmysqldumpslow-sc-t10/var/log/mysql/mysql-slow.log# 按照返回记录数(r)排序查找高频返回大量数据的 SQLmysqldumpslow-sr-t10/var/log/mysql/mysql-slow.log第三方可视化分析在实际生产中更倾向于使用 **Percona Toolkit 中的pt-query-digest**工具或者将日志接入Prometheus Grafana / ELK监控看板实现慢 SQL 的直观发现与告警。③ 慢查询日志对索引优化的指导意义通过慢查询日志抓出目标 SQL 后应配合EXPLAIN执行计划进行深度剖析。通常优化的常规路径为未走索引若日志中显示Rows_examined扫描行数很大但Rows_sent返回行数很小且未命中索引则应针对WHERE或JOIN的字段建立相应索引。索引失效若已经建了索引SQL 依然出现在慢日志中需排查是否存在隐式类型转换、模糊查询开头带%等导致索引失效的操作。基数过大若字段区分度极低如状态字段即使建了索引也会被 MySQL 优化器放弃此时应考虑重构业务逻辑或引入缓存。3. show profilesshow profiles是 MySQL 提供的一种用来剖析当前线程中 SQL 语句生命周期和资源消耗的性能分析工具。它可以精准地测量出一条 SQL 在执行过程中各个阶段如权限检查、开表、优化、清空数据、发送数据等分别消耗了多少时间。注意在 MySQL 5.7 及更高版本中show profiles已被标记为废弃Deprecated官方建议使用更强大的Performance Schema性能schema进行替代。但由于其使用简单在日常快速排查中仍被广泛使用。① 启用与查看该工具默认是关闭的开启后会记录当前会话最近发起的 15 条默认值SQL 的执行分析。-- 查看 show profiles 是否开启SELECThave_profiling;SHOWVARIABLESLIKEprofiling;-- 开启 profilingSETprofiling1;-- 执行你的 SQL 语句用于测试SELECT*FROMusersWHEREage18;-- 查看最近执行的 SQL 列表及其总耗时获取 Query_IDSHOWPROFILES;② 深度剖析特定 SQL拿到SHOW PROFILES返回的Query_ID后可以针对某一条 SQL 进行全方位的资源消耗拆解-- 查看指定 Query_ID 的每个执行阶段的具体耗时SHOWPROFILEFORQUERY1;-- 查看指定 SQL 阶段消耗的 CPU 资源SHOWPROFILE CPUFORQUERY1;-- 查看指定 SQL 阶段消耗的磁盘 I/O 资源SHOWPROFILE IOFORQUERY1;③ 性能调优的危险信号在SHOW PROFILE的结果中如果以下阶段的耗时过长通常意味着 SQL 存在严重的性能问题Converting HEAP to MyISAM查询结果太大内存临时表不够用正在将数据复制到磁盘上的临时表中。急需优化查询或索引Creating tmp table正在创建临时表通常由于复杂的GROUP BY或DISTINCT导致。Copying to tmp table on disk正在把内存中的临时表数据复制到磁盘。Locked被锁住了正在等待锁释放。4. explain执行计划explain是 MySQL 性能优化中最核心、最常用的利器。在任意SELECT、DELETE、UPDATE或INSERT语句前加上EXPLAIN关键字MySQL 优化器就会模拟执行该 SQL并返回一条执行计划。通过它我们可以直接看到 SQL 底层是否使用了索引、使用了哪个索引、扫描了多少行数据等关键信息。① 使用语法EXPLAINSELECT*FROMusersWHEREname张三;② 核心返回字段及分析意义执行EXPLAIN后会返回一个表格其中最核心的考量指标如下列名 (Column)含义专家级调优关注点type访问类型/连接类型最核心指标。性能从好到差依次为systemconsteq_refrefrangeindexALL。•const/ref命中唯一索引或普通索引。•range索引范围扫描如BETWEEN、。•index全索引树扫描虽然走了索引但遍历了整棵树。•ALL全表扫描性能最差必须优化。生产环境通常要求至少达到range级别力争ref。possible_keys可能会用到的索引提示有哪些索引可以用来加速该查询。key实际使用的索引如果为NULL则说明没有使用索引。如果此列有值说明成功命中了该索引。key_len实际使用索引的字节长度联合索引中通过该值可以计算出到底命中了哪几个字段。在不损失精确度的情况下该值越小越好。rows预估需要扫描的行数这是一个估计值。数值越小意味着需要读取的磁盘数据页越少性能越好。filtered过滤后留下的记录比例返回结果的行数占读取行数的百分比。值越大说明索引过滤的效果越精准。Extra额外附加信息关键辅助指标。常见提示包括•Using index使用了覆盖索引不需要回表性能极高。•Using index condition使用了索引下推ICP优化。•Using filesort使用了文件排序未利用索引排序性能较差需优化。•Using temporary使用了临时表常见于未加索引的GROUP BY性能极差。四使用规则使用explain和show profiles可以看到每条sql执行的效率可以利用他们来看有索引和没索引的区别。1. 最左前缀法则最左匹配原则最左前缀法则Most-Left Prefix Rule是联合索引组合索引在实际查询中能否生效的核心判断依据。联合索引在底层 BTree 中是按照创建时从左到右的字段顺序进行全局排序的。只有当左边的列值完全相同时才会对右边的列值进行排序。因此查询时必须从索引的最左列开始并且不能跳过中间的列否则索引将部分或完全失效。① 核心规则解析假设我们在表上建立了一个三列的联合索引idx_user_pro (name, age, city)其底层排序逻辑是先按name排序在name相同的情况下再按age排序在age也相同的情况下最后按city排序。基于此逻辑不同查询条件的命中情况如下完全匹配全额命中-- 完美触发索引三个字段都在索引树中实现精准定位EXPLAINSELECT*FROMusersWHEREname张三ANDage18ANDcity北京;部分匹配满足最左前缀-- 命中 name 和 age。因为从最左侧连续匹配未发生断档EXPLAINSELECT*FROMusersWHEREname张三ANDage18;-- 仅命中 name。最左列存在但 age 断档导致 city 无法使用索引EXPLAINSELECT*FROMusersWHEREname张三ANDcity北京;完全失效丢失最左前缀-- 索引完全失效因为缺少最左列 name右侧的 age 和 city 在全局上是无序的只能走全表扫描EXPLAINSELECT*FROMusersWHEREage18ANDcity北京; 专家提示位置无关性下面这条 SQL 依然可以完全命中联合索引EXPLAINSELECT*FROMusersWHEREage18ANDcity北京ANDname张三;这里的“最左”指的是是否存在而不是在 SQL 语句中的书写顺序。MySQL 的查询优化器Optimizer非常聪明它会在执行前自动颠倒条件顺序使其去匹配联合索引。② 范围查询导致右侧索引失效最左前缀法则中还有一个高频翻车场景在联合索引中如果出现了范围查询如,,BETWEEN,LIKE xx%则该范围列右侧的索引字段将全部失效。右侧失效示例-- 此时索引仅命中了 name 和 age 两个字段city 索引失效-- 原因age 变成了范围在多个不同 age 的结果集里city 的排列不再具有整体全局有序性EXPLAINSELECT*FROMusersWHEREname张三ANDage18ANDcity北京;优化规避方案在业务逻辑允许的情况下尽量使用大于等于或小于等于。在 MySQL 5.7 之后如果是等值边界右侧的索引有概率能继续复用即常说的业务等值下推。③ 索引列上的各种“骚操作”导致失效除了最左前缀没拉满在字段上进行以下操作也会导致联合索引甚至单列索引直接报废对索引列进行函数或表达式计算WHERE YEAR(birthday) 2026应改为范围查询WHERE birthday BETWEEN...隐式类型转换WHERE phone 13800000000若 phone 是VARCHAR类型传入数字会导致全表扫描模糊查询前缀带 %WHERE name LIKE %三前缀未知无法在 BTree 树中导航但LIKE 张%可以走索引除了违反以上的最左前缀法则会失效的情况还有一些可能的原因。2. 索引失效的常见场景在实际开发中即使为字段建立了索引如果 SQL 语句书写不当也会导致 MySQL 优化器放弃走索引而选择全表扫描typeALL。以下是生产环境中最常见的 7 种索引失效场景① 违反最左前缀法则对于联合索引如果查询条件中缺失了索引的最左列或者跳过了中间的列会导致右侧的索引字段全部失效。失效示例联合索引为(a, b, c)查询条件为WHERE b 1 AND c 2缺失最左列a索引完全失效。② 联合索引中范围查询右侧的列失效在联合索引中如果某个字段使用了范围查询如,,NOT IN,LIKE等那么该字段右侧的所有索引列都将无法用于建立检索。失效示例联合索引为(name, age, city)查询条件为WHERE name 张三 AND age 18 AND city 北京。此时name和age走索引但city失效。③ 在索引列上进行运算或函数操作对索引列进行任何数学运算、拼接或使用内置函数都会破坏 BTree 中索引值的原有顺序导致优化器无法在树结构中进行二分查找。错误写法WHERE age 1 19;错误写法WHERE SUBSTRING(name, 1, 2) 张三;正确改写WHERE age 19 - 1;将运算移至等号右侧的常量④ 存在隐式类型转换当索引列的字段类型与传入的查询参数类型不一致时MySQL 会在底层自动调用函数进行转换从而导致索引失效。这种情况最常发生在字符串VARCHAR与数字INT的比对上。错误写法WHERE phone 13800000000;假设phone在数据库中是VARCHAR类型传入数字会导致全表扫描正确写法WHERE phone 13800000000;⑤ 模糊查询时通配符%在开头BTree 索引是按照字符从左到右的顺序建立索引树的。如果通配符%放在开头意味着前缀字符完全未知MySQL 无法在索引树中向下导航。失效示例WHERE name LIKE %三;全表扫描生效示例WHERE name LIKE 张%;可以正常走索引范围扫描range⑥ 使用OR连接条件时缺失索引在使用OR连接多个条件时必须要求OR两边的所有字段都建立了索引否则整个查询的索引都会失效。失效示例WHERE id 1 OR age 18;主键id有索引但age没有索引导致整体走全表扫描⑦ 估计全表扫描比索引快数据区分度低MySQL 优化器在执行 SQL 前会进行成本计算。如果查询的数据量占全表数据的比例过大通常在 20%~30% 以上或者字段的区分度极低如性别、状态字段优化器会认为“先读索引树、再频繁回表”的开销远大于直接全表扫描从而主动放弃索引。典型场景WHERE status 1;假设表中 90% 的数据status都等于 1此时即使有索引也不会触发。五、 索引的设计原则在实际开发中索引并不是建得越多越好。为了在提升查询效率与降低维护成本之间取得最佳平衡设计索引时应遵循以下核心原则1. 核心针对性原则高频查询优先优先为经常出现在WHERE子句、JOIN关联条件、ORDER BY排序以及GROUP BY分组中的字段建立索引。高区分度优先选择字段值重复率低、区分度高的列作为索引如手机号、用户ID。联合索引的设计要求字段基数Cardinality越大越要往左边放。计算公式区分度 表中不同值的数量 表总行数 \text{区分度} \frac{\text{表中不同值的数量}}{\text{表总行数}}区分度表总行数表中不同值的数量​该值越接近 1说明越适合建索引。尽量避免低区分度列诸如“性别男/女”、“状态0/1”这类只有少数几种取值的字段不适合单独建立索引因为即使建了MySQL 优化器也大概率会放弃它而走全表扫描。2. 数量与空间控制原则控制单表索引数量一张表的索引数量通常建议控制在5 个以内。过多的索引会严重拖慢INSERT、UPDATE、DELETE的速度并挤占大量的磁盘空间。联合索引代单列索引如果多个字段经常组合出现优先建立一个联合索引而不是针对每个字段各建一个单列索引。联合索引能够极大地减少表中的索引树数量。短索引前缀索引原则对于VARCHAR(255)或TEXT等较长的字符串字段如果需要建索引不应整个字段去建而是指定前缀长度如取前 10 个字符。这能显著降低索引树的大小提升内存利用率。3. 业务防错与优化原则利用唯一约束业务上具有唯一性特征的字段如身份证号、订单号必须建立唯一索引UNIQUE。这不仅能加速查询还能在数据库底层提供强制的业务幂等性保障。力求覆盖索引在设计联合索引时尽量让索引包含SELECT需要返回的字段。一旦实现覆盖索引MySQL 就能直接在二级索引树上返回数据彻底免除“回表”操作性能会发生质的飞跃。慎用频繁更新列若某个字段的业务修改极其频繁如用户的步数、账户余额、点击量不建议为其建立索引否则每次更新都会导致 BTree 频繁发生页分裂和节点重组。