- 聚簇索引(主键索引):一个表只能有一个聚簇索引,对应表的数据存储方式 , 即数据按照聚簇索引来排序和存储,叶节点存储了完整的数据行 。在使用聚簇索引进行查找时,只需查找一次聚簇索引就能找到需要的数据行 。
- 非聚簇索引(辅助索引):一个表可以有多个非聚簇索引,节点存储了完整的索引和指向数据行信息(指针或主键) 。查询时需要查找两次索引,第一次查询索引信息,第二次查找数据行 。

文章插图
这种先查辅助索引再查主键索引的行为 , 我们称之为“回表” 。
看一个回表的例子:
table: id, category, publisher, status, title
index: idx_categity(category,status)
查询语句:select * from tb_news where category = 2 and publisher = 14
执行逻辑如图所示:

文章插图
- 索引中存在 category 列,category = 2 的过滤在引擎层完成,返回数据的主键 。
- 引擎完成 category = 2 过滤后,需要 publisher 和全部数据,所以进行回表操作 。
- 从主键索引表中获取全部数据,在内存中执行 publisher = 14 的过滤 。
- 将满足条件的数据放入到 Result 中进行返回 。
一般情况下 , 回表的性能损失还是可接受的 , 可以在发现问题后进行处理 。可将更多精力放在提升研发效率上 。(2)高性能查询基于 B+Tree 数据结构的特点,在以下场景可以高效使用索引:
- 全值匹配:与索引中的所有列进行匹配;
- 匹配最左前缀:并非与索引中的所有列进行匹配,从索引左侧进行匹配 。
- 匹配列前缀:匹配某一列的开头部分(like ‘aaa%’) 。
- 匹配范围值: 大于、等于、小于等 。
- 精确匹配列然后范围匹配:先精确匹配 , 然后进行范围匹配 。
- 只访问索引查询:如果索引中存在查询所需所有数据,就没有必要追溯原数据 。
- 支持查询中的order by、group by:order by、group by 与 where 条件组合,如果符合最左匹配,及可提升性能 。
- 不是从最左列开始查询 , 无法使用索引 。
- 不能跳过索引中的列对后面的列进行查询 。
- 如果索引使用范围查询,则后面所有列无法使用索引进行优化 。
在了解 MySQL B+Tree 的内部实现之后,可以推导出一套规范,来对查询性能进行保障 。原则
- 仅使用 MySQL 的单表查询,避免多表 Join 引入的性能问题(多表查询解决方案见:内存Join) 。
- 每个查询,必须有对应的索引对性能进行保障,也就是所有的查询必须走索引 。
- 谨慎处理入参和返回值 。
- 对入参进行严格验证,避免因为参数丢失或参数过多造成的性能问题 。
- 对返回值进行验证,避免一次性返回过多数据操作性能问题 。
- 统一使用 Query Object 模式,对入参进行封装,以便接口的升级和扩展 。
- 每一组查询 , 可以存在: get(单条返回值)、list(多条返回值)、count(统计计数)、page(分页)开头的多个方法,操作后面紧跟 By + 维度 。
推荐阅读
- DDD死党:内存Join——将复用和扩展用到极致
- DDD 必备架构--六边形架构
- 解密DDD:高内聚对象组的维护之道
- 什么是基友什么是死党 什么是基友
- 死党是什么关系 基友是什么关系
- 死党是和闺蜜的意思一样吗知乎 死党是和闺蜜的意思一样吗
- DDD实战 - Repository模式的妙用
- 为什么从 MVC 到 DDD,架构的本质是什么?
- DDD 中关于应用架构的那些事
- 基于DDD的微服务落地
