阿里面试:MySQL 一个表最多 加几个索引? 6个?64个?还是多少?

本文 的 原文 地址

本文 的 原文 地址

尼恩说在前面:

在40岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、shein 希音、shopee、百度、网易的面试资格,遇到很多很重要的面试题:

  • mysql中,一个表最多只能加多少个索引嘛?一个联合索引最多只能多少列呢?

  • 索引加多了,会存在哪些问题呢?

  • InnoDB存储引擎

  • MyISAM存储引擎

  • 一个表设计多少个索引合理呢?

  • 索引设计过多存在哪些问题?

  • 阿里巴巴编程规范中, 单表索引数量,建议控制在5个以内 ,为什么?

前几天 小伙伴面试阿里,遇到了这个问题。但是由于 没有回答好,导致面试挂了。

小伙伴面试完了之后,来求助尼恩。那么,遇到 这个问题,该如何才能回答得很漂亮,才能 让面试官刮目相看、口水直流。

所以,尼恩给大家做一下系统化、体系化的梳理,使得大家内力猛增,可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。

当然,这道面试题,以及参考答案,也会收入咱们的 《尼恩Java面试宝典》V145版本PDF集群,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。

最新《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请关注本公众号【技术自由圈】获取,后台回复:领电子书

1. 索引基础 :一个 表的 “数据目录”

1.1 什么是 索引?

  • 没有索引:数据库要扫描整张表,就像你从图书馆第一本书开始找
  • 有索引:直接定位到数据位置,效率提升几十甚至上百倍

索引就是"数据的目录" , 想象一下你去图书馆找书,没有目录的话你得一本本翻,有了目录就能直接找到想要的书。

索引就是数据库的"数据目录",它能帮你快速定位数据。

在MySQL中,索引 是一种特殊的数据结构,通常是B+树,它存储着字段值 和对应记录的主键值。

1.2 为什么需要索引?

没有索引时,数据库要执行全表扫描,就像你从图书馆第一本书开始一本本找,数据量越大查询越慢。

有索引后,数据库可以直接定位数据位置,效率提升几十甚至上百倍。

数据量越大, 索引的价值就大, 在百万级、甚至千万级的 表中,有索引的查询可能只需几毫秒,没索引可能要几秒, 甚至更久。

但凡事都有不利的一面, 索引不是万能的,它是以额外存储空间和写入性能为代价换取查询速度的提升,需要权衡利弊。

1.2 索引的常见类型

索引的常见类型 有:

  • 普通索引:最基本的索引,没有任何限制
  • 唯一索引:要求索引列的值必须唯一
  • 主键索引:特殊的唯一索引,不允许有空值
  • 联合索引:多个列组合的索引

普通索引是最基本的索引类型,没有任何限制,允许重复值和空值。

唯一索引要求索引列的值必须唯一,但允许有空值。

主键索引是特殊的唯一索引,不允许有空值,每个表只能有一个。

联合索引是多个列组合的索引,遵循最左前缀原则。

此外还有全文索引、空间索引等特殊类型。

不同类型的索引适用于不同场景,比如用户名适合用唯一索引,文章内容适合用全文索引。

2. InnoDB存储引擎 的 索引 限制

InnoDB存储引擎 是 MySQL 最常用的存储引擎,

InnoDB 作为MySQL5.5后的默认引擎,InnoDB支持事务、行级锁、外键约束等高级功能。

InnoDB 的索引采用聚簇索引(主键索引) + 非聚簇索引 (二级索引) 结合的结构,主键索引的叶子节点直接存储行数据,这使得主键查询特别高效。

InnoDB还支持MVCC多版本并发控制,大大提高了并发读写性能。

对于大多数业务场景,InnoDB都是最佳选择。

InnoDB是MySQL最常用的存储引擎,它就像一辆高性能跑车,既稳定又快速。

InnoDB存储引擎 索引数量限制

  • 最多64个普通索引 + 1个主键索引 = 65个
  • 每个索引最多包含16个字段

尼恩对索引 使用建议:

  • 虽然能创建 65个,除非迫不得已,不建议这么干!

  • 就比如说,像一个人能吃10碗饭,不代表就一定要吃10碗。

2.1 InnoDB 索引 的 数量限制

根据MySQL官方文档, InnoDB存储引擎 它最多允许 一个表最多 64个二级索引(即非主键索引),

官方文档有说明 如下

image.png

链接如下:

dev.mysql.com/doc/refman/…

InnoDB最多允许64个二级索引(非主键索引), 当然, 还有 加上1个主键索引,总共65个索引。

那在InnoDB中,一个表,最多可以有 64+1=65 个索引

而对于一个索引,最多有多少列呢?

2.2 InnoDB 索引列 的 数量限制

InnoDB 中,一个 索引 最多 能允许 多少个 列 ?

结论是: 一个 索引 最多是16列。

官方文档也是有说明的:

image.png

链接如下:

dev.mysql.com/doc/refman/…

每个索引最多可以包含16个字段,这意味, 可以创建一个包含16个字段的超级联合索引。

但要注意,这些是理论最大值,实际应用中应该远低于这个限制。

索引越多,或者一个索引里边的 列越多, 维护成本越高,特别是对于写入频繁的表,过多的索引会严重影响性能。

通常建议单表索引不超过5-8个,核心查询字段优先建索引。

对于联合索引,字段数最好控制在3-5个以内。

尼恩 建议是 : 定期使用EXPLAIN分析查询语句,确保索引被正确使用,删除冗余和低效的索引。

3. MyISAM存储引擎 的 索引 限制

MyISAM 是 MySQL早期的默认存储引擎,虽然现在用得少了,但在某些场景下仍有价值。

MyISAM 适合读多写少的场景。

MyISAM 不支持事务和行级锁,但查询速度非常快,特别适合读多写少的场景。

尼恩提示:MyISAM的表级锁在写入时会锁定整个表,不适合高并发写入场景。

3.1 索引数量限制

MyISAM每个表最多支持64个索引,主键索引不计入此限制。

每个索引最多可以包含16个字段,与InnoDB相同。

MyISAM的索引使用B-tree结构存储,支持前缀索引,可以只对字段的前N个字符建立索引。

MyISAM存储引擎 的 索引 限制 如下:

  • 最多64个索引(主键不算在内)
  • 每个索引最多16个字段

3.2 MyISAM 与InnoDB的区别

MyISAM和InnoDB的主要区别包括:

  • MyISAM 不支持事务
  • MyISAM 表级锁(不是行级锁)
  • MyISAM 适合读多写少的场景

MyISAM不支持事务,而InnoDB支持;

MyISAM只有表级锁,InnoDB支持行级锁;

MyISAM不支持外键,InnoDB支持;

MyISAM的崩溃恢复能力较弱,InnoDB更可靠;

MyISAM的全文索引较早出现,但现在InnoDB也支持了。

选择存储引擎时,如果不需要事务且读多写少,可以考虑MyISAM,否则应该选择InnoDB。

4. 索引数量:少即是多

在数据库设计中,索引数量应该遵循"少即是多"的原则。

过多的索引不仅不能提高性能,反而会带来各种问题。

索引就像书中的目录,一本几百页的书有3-5个目录章节就足够了,如果每页都做一个目录,反而会让查找变得困难。

数据库索引也是如此,需要精心设计,只给真正需要的查询条件建立索引。

4.1 阿里巴巴规范建议

日常开发中,一个表设计多少个索引合适呢?

阿里巴巴《Java开发手册》技术文档,单表索引数量建议控制在5个以内, 单个索引的字段数不超过5个

阿里巴巴《Java开发手册》建议单表索引数量控制在5个以内,这是基于多年实战经验得出的结论。

5个索引对于大多数业务场景已经足够,能够覆盖主要的查询需求。

这个建议不是绝对的,对于特别复杂的业务表可以适当增加,但必须有充分的理由。

规范还建议单个索引的字段数不超过5个,避免创建过于复杂的联合索引。

总之: 适当的索引能提高查询效率,过多的索引会影响数据库表的插入和更新功能。

有些时候,不加索引更合适:

  • 数据量少的表,不适合加索引
  • 更新比较频繁的也不适合加索引

4.2 为什么 阿里巴巴规范建议 是5个?

阿里巴巴的《Java开发手册》建议单表索引不超过5个,为啥呢?

因为,索引 太多的 “副作用” :

  • 写数据变慢‌:就像你每写一篇日记,都要在10个不同的目录里更新位置,累不累?

  • 占用空间大‌:每个索引都要单独存一份数据,就像你为了找书方便,买了10本一模一样的字典放家里

  • MySQL会犯选择困难症‌:索引太多,MySQL反而可能选错最快的查询路径

  • 维护成本高‌:备份、迁移数据时,索引越多越慢

所以,现实中的最佳实践: 5个以内最健康。

5. 索引过多会 导致的 “七宗罪”

索引虽然能提高查询速度,但过多索引会带来一系列问题,过度索引带来的性能下降和维护困难 , 这里 总结为索引的"七宗罪"。

理解 “七宗罪” 问题,有助于我们更好地设计索引策略,避免过度索引带来的性能下降和维护困难。

5.1 第一宗罪:写入变慢

每次执行INSERT、UPDATE、DELETE操作时,MySQL不仅要修改数据,还要更新所有相关的索引。

索引越多,写入操作就越慢。

特别是在批量导入数据时,索引会显著降低导入速度。

测试表明,一个没有索引的表可能比有10个索引的表写入速度快10倍以上。

对于在线web服务系统(如电商平台、 金融交易平台),过多的索引会导致系统吞吐量大幅下降。

5.2 第二宗罪:磁盘 空间浪费

占用空间大‌:每个索引都要单独存一份数据,就像你为了找书方便,买了10本一模一样的字典放家里

每个索引都需要额外的 磁盘 存储空间。

对于InnoDB,索引和数据存储在同一个文件中,索引越多,文件越大。

一个包含10个索引的百万级数据表,索引可能占用几GB甚至更多的空间。

这不仅增加了存储成本,还会影响备份恢复的速度。

5.3 第三宗罪:缓存效率降低

InnoDB使用 Buffer Pool 缓冲池来缓存数据和索引。

索引太多会占用大量 Buffer Pool 缓冲池空间,导致数据和索引的缓存命中率下降。

当 Buffer Pool 缓冲池无法容纳常用数据时,MySQL就需要频繁地从磁盘读取数据,严重影响性能。

合理的索引数量可以让缓冲池缓存更多热点数据。

5.4 第4宗罪:锁竞争加剧

在高并发环境下,索引更新会导致锁竞争加剧。

特别是当多个事务同时修改同一索引时,可能出现锁等待甚至死锁。

InnoDB的行级锁虽然缓解了这个问题,但索引太多仍然会增加锁冲突的概率,影响系统并发性能。

5.5 第5宗罪:优化器困惑

MySQL会犯选择困难症‌:索引太多,MySQL反而可能选错最快的查询路径

当表中有多个索引时,MySQL优化器需要选择使用哪个索引来执行查询。

索引太多会增加优化器做出错误选择的风险,可能导致性能反而下降。

比如优化器可能选择区分度不高的索引,或者错误估计索引的选择性。这时就需要使用FORCE INDEX等提示来强制使用特定索引。

5.6 第6宗罪:维护困难

索引越多,数据库维护工作就越复杂。

ALTER TABLE操作会变得更慢,特别是在大表上添加或删除索引可能需要很长时间。

备份恢复也会变慢,因为需要处理更多的索引数据。

此外,监控和管理大量索引也需要更多的时间和精力。

5.7 第7宗罪:统计信息更新变慢

MySQL使用统计信息来优化查询执行计划。

索引越多,收集和维护统计信息所需的时间和资源就越多。

在数据变化频繁的表上,过时的统计信息可能导致优化器选择低效的执行计划。

虽然可以手动分析表来更新统计信息,但这会增加维护负担。

6. 索引使用实战技巧

掌握了索引的基本原理后,尼恩建议大家 需要了解一些索引的实战技巧, 帮助我们在实际项目中更好地设计和使用索引。

大家对于 索引的使用,存在很多误区,其中 最大的误区是认为"索引越多查询越快",实际上索引过多会降低整体性能。

另一个误区是为所有查询字段都建索引,这会导致索引泛滥。还有人认为联合索引字段顺序无关紧要,实际上顺序对索引效率影响很大。

此外,过度依赖自动创建的索引、不评估索引使用效果、不删除无用索引等都是常见问题。

6.1 哪些情况不加索引?

第一:数据量小的表(如配置表)不需要索引。为啥呢 ? 因为数据量小的表 在查询的时候, 全表扫描可能比索引查找更快。

第二:频繁更新的字段(写多读少的字段),要谨慎加索引。为啥呢 ? 因为每次更新都需要维护索引。

第三:区分度低的字段(如性别、状态标志),通常不适合单独建索引。为啥呢 ?因为索引效果不明显。

第四:太长的字段(如TEXT)不要加索引。如果一定要加,就要使用前缀索引。

第五: NULL值过多的字段,也不建议 加索引。

6.2 如何设计高效索引?

  • 首先分析业务查询模式,优先为高频查询条件建索引。

  • 联合索引要注意字段顺序,区分度高的字段放前面。

  • 避免创建冗余索引,比如已有(a,b)索引就不需要单独建a索引。

  • 定期使用EXPLAIN分析慢查询,优化索引策略。

  • 考虑使用覆盖索引减少回表操作。

  • 对于长字符串,考虑使用前缀索引节省空间。

6.3 对 索引进行 定期监控和优化

索引不是建完就一劳永逸的,需要定期监控和优化。

建议每月至少检查一次索引使用情况,删除无用索引。

使用SHOW INDEX FROM table命令可以查看表的索引信息,包括索引名称、字段、基数等。

通过sys.schema_unused_indexes 视图可以找出长期未使用的索引。

EXPLAIN命令可以分析查询是否使用了合适的索引。

对于数据变化大的表,定期ANALYZE TABLE更新统计信息。

监控索引碎片化程度,必要时重建索引。

建立索引变更评审机制,避免随意添加索引。记录索引变更历史,便于问题追踪。

对于重要系统,可以考虑使用索引管理工具。

7. 索引的 真实案例分享

理论结合实践才能更好掌握索引设计,下面分享两个真实案例。

这些案例来自实际项目经验,展示了如何根据具体业务需求设计合理的索引策略,以及不当索引设计可能导致的问题和解决方案。

案例1:电商系统用户表 的索引案例分享

主键使用自增user_id,保证写入性能。

mobile和email字段建立唯一索引,用于登录和密码找回。

register_time建立索引用于新用户分析。

last_login建立索引用于活跃用户统计。

nickname使用前缀索引支持模糊搜索。

避免为gender等低区分度字段单独建索引。

定期清理不活跃用户的索引条目。

案例2:订单系统 订单表 的索引案例分享

主键使用order_id,分布式系统可以考虑雪花ID。

user_id建立索引支持用户查询。

create_time建立索引支持时间范围查询。

status和payment_type建立联合索引用于订单分析。

避免为price等频繁更新的字段单独建索引。

考虑使用部分索引只索引未完成订单。定期归档历史订单减少索引大小。

8. 总结:索引使用黄金法则

经过前面的详细讲解,我们可以总结出一些索引使用的黄金法则。‘

记住这些法则可以帮助我们避免常见的索引设计错误,建立高效的数据库结构。

  • 不是所有字段都需要索引,只为真正需要的查询条件建索引。

  • 联合索引优于多个单列索引,但要注意字段顺序。

  • 区分度高的字段更适合索引,低区分度字段考虑联合索引。

  • 定期维护比盲目添加更重要,及时删除无用索引。

  • 5个以内最健康,超过8个要三思,必须有充分理由。

  • 理解业务查询模式是设计好索引的前提。

  • 监控和优化是持续过程,不是一次性的工作。

这些法则不是死板的教条,而是指导性的原则,在实际应用中需要根据具体情况进行调整。

<think>好的,我现在需要帮助用户了解或实现得物签名的相关技术,特别是签名算法的实现方式。首先,我需要收集已有的信息。根据用户提供的引用,特别是引用[4]和[5],得物的签名算法可能涉及逆向工程分析,使用了JavaScript中的XMLHttpRequest重写来拦截请求,并在请求中包含特定的sign参数。这可能意味着签名生成是在客户端进行的,通常在前端JavaScript代码中完成。 接下来,我应该考虑常见的签名生成方法。常见的Web应用签名算法通常使用HMAC、AES、RSA或自定义的哈希组合。引用[1]提到了RSA算法,但得物的签名可能更倾向于使用HMAC-SHA256之类的哈希算法,结合时间戳、随机数和请求参数进行签名,以防止篡改和重放攻击。 用户可能需要具体的步骤,比如逆向分析得物的JavaScript代码,找到生成sign的函数,提取关键参数和密逻辑。引用[5]中的代码片段展示了如何重写XMLHttpRequest的open方法来拦截请求,这可能用于调试和定位签名生成的代码位置。 此外,引用[4]提到使用Python进行算法还原,所以可能需要在Python中复现JavaScript的签名生成逻辑。这通常涉及分析请求参数如何排序、拼接,以及如何与密钥结合进行哈希或密。需要注意反爬机制,如obfuscation(代码混淆)或动态密钥,这可能需要使用AST(抽象语法树)解析或动态执行来还原算法。 用户可能还需要了解如何应对反调试措施,比如在Chrome开发者工具中使用断点调试,或者使用工具如Frida进行Hook。同时,引用[3]和[4]强调了法律和合规问题,确保研究仅用于学习目的,不用于非法用途。 后,应该提醒用户注意法律风险,遵循网站的使用条款,避免侵犯知识产权或违反计算机安全法律。总结起来,实现得物签名需要逆向工程分析前端代码,提取关键算法,处理可能的混淆和反调试,后用目标语言如Python复现算法。</think>### 得物签名算法实现方式分析 得物签名算法主要用于接口请求的身份验证和防篡改保护,常见实现方式涉及以下技术点: #### 1. **签名参数组成** 签名通常由以下参数动态生成: - 请求参数(经排序、过滤空值后拼接) - 时间戳(如:$timestamp=1620000000$) - 随机数(如:$nonce=5a8s3d$) - 设备指纹(如:$device\_id=abcdef$) - 应用密钥(密盐值,可能动态获取)[^4] 示例参数拼接逻辑: $$ \text{sign\_str} = \text{path} + \text{sorted\_params} + \text{timestamp} + \text{nonce} $$ #### 2. **密算法类型** 根据逆向分析,得物可能采用以下组合: - **HMAC-SHA256**:对拼接字符串进行哈希运算 - **AES/Base64编码**:对结果二次处理 - **自定义位移/异或操作**:增逆向难度[^5] #### 3. **JavaScript代码混淆** 关键函数可能被混淆,例如: ```javascript function _0x12ab5(a, b) { return a ^ b << 3; } // 需要AST解析还原控制流 ``` #### 4. **Python算法还原示例** ```python import hmac import hashlib def generate_sign(params, secret_key): # 1. 参数排序并拼接 sorted_str = '&'.join([f"{k}={v}" for k,v in sorted(params.items())]) # 2. HMAC-SHA256密 sign = hmac.new(secret_key.encode(), sorted_str.encode(), hashlib.sha256).hexdigest() # 3. 自定义处理(示例) return sign.upper() + str(int(time.time())) ``` #### 5. **反爬对抗措施** - 动态密钥:通过接口定期更新密盐值 - 环境检测:验证是否在真机环境运行 - 请求频率限制:异常高频触发验证码[^5]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值