一、聚族索引的构造
聚簇索引并不是一种单独的索引类型,而是一种数据存储方式。具体的细节依赖于其实现方式,但InnoDB的聚族索引实际上在同一个结构中保存了B-Tree索引和数据行。当表有聚族索引时,它的数据行存放在索引的叶子页中。术语“聚族”表示数据行和相邻的键值紧凑的存储在一起。因为无法同时把数据行放在两个不同的地方,所以一个表只能有一个聚族索引。
因为是存储引擎负责实现索引,因此不是所有的存储引擎都支持聚族索引。这里我们主要关注InnoDB,但是这里讨论的原理对于任何支持聚族索引的存储引擎都是适用的。
下面展示了聚族索引中的记录是如何存放的。注意到,叶子页包含了行的全部数据,但是节点页只包含了索引列。
在InnoDB中通过主键聚集数据,这也就是说上图中“被索引的列”就是主键列。如果没有定义主键,InnoDB会选择一个唯一的非空索引代替。如果没有这样的索引,InnoDB会隐式定义一个主键来作为聚族索引。InnoDB只聚集在同一个页面中的记录。包含相邻键的页面可能会相距甚远。
聚族主键可能对性能有帮助,但也可能导致严重的性能问题。所以需要仔细的考虑聚族索引,尤其是将表的引擎从InnoDB改成其他引擎的时候。
二、聚族索引的优点
- 可以把相关数据保存在一起。例如实现电子邮件时,可以根据用户ID来聚集数据,这样只需要从磁盘读取少数的数据页就能获取某个用户的全部邮件。如果没有使用聚族索引,则每封邮件都可能导致一次磁盘I/O;
- 数据访问更快。聚族索引将索引和数据保存在同一个B-Tree中,因此从聚族索引中获取数据通常比在非聚族索引中查找更快。
- 使用覆盖索引扫描的查询可以直接使用节点中的主键值。
三、聚族索引的缺点
- 聚簇数据最大限度的提高了I/O密集型应用的性能,但如果数据全部都放在内存中,则访问的顺序就没有那么重要了,聚簇索引也就没有那么优势了;
- 插入速度严重依赖于插入顺序。按照主键的顺序插入是加载数据到InnoDB表中速度最快的方式。但如果不是按照主键顺序加载数据,那么在加载完成后最好使用OPTIMIZE TABLE命令重新组织一下表。
- 更新聚簇索引列的代价很高,因为会强制InnoDB将每个被更新的行移动到新的位置。
- 基于聚簇索引的表在插入新行,或者主键被更新导致需要移动行的时候,可能面临“页分裂”的问题。当行的主键值要求必须将这一行插入到某个已满的页中时,存储引擎会将该页分裂成两个页面来容纳该行,这就是一次分裂操作。页分裂会导致表占用更多的磁盘空间。
- 聚簇索引可能导致全表扫描变慢,尤其是行比较稀疏,或者由于页分裂导致数据存储不连续的时候。
- 二级索引(非聚簇索引)可能比想象的要更大,因为在二级索引的叶子节点包含了引用行的主键列。
- 二级索引访问需要两次索引查找,而不是一次。
备注:有关二级索引需要两次索引查找的问题?答案在于二级索引中保存的“行指针”的实质。要记住,二级索引叶子节点保存的不是指向行的物理位置的指针,而是行的主键值。这意味着通过二级索引查找行,存储引擎需要找到二级索引的叶子节点获得对应的主键值,然后根据这个值去聚簇索引中查找到对应的行。这里做了重复的工作:两次B-Tree查找而不是一次。对于InnoDB,自适应哈希索引能够减少这样的重复工作。
四、InnoDB和MyISAM的数据分布对比
聚簇索引和非聚簇索引的数据分布有区别,以及对应的主键索引和二级索引的数据分布也有区别。
1、MyISAM的主键索引和二级索引
MyISAM的数据分布非常简单,MyISAM按照数据插入的顺序存储在磁盘上。在行的旁边显示了行号,从0开始递增。因为行是定长的,所以MyISAM可以从表的开头跳过所需的字节找到需要的行。这种分布方式很容易创建索引。并且,MyISAM中主键索引和其他索引在结构上没有什么不同。主键索引就是一个名为primary的唯一非空索引。如下图:
1、MyISAM数据行分布
2、MyISAM的主键分布
3、MyISAM上的其他索引分布
2、InnoDB的主键索引和二级索引
InnoDB的数据分布,因为InnoDB支持聚簇索引,索引使用非常不同的方式存储这样的数据,如下图:
仔细查看,会注意到该图显示了整个表,而不是只有索引。因为在InnoDB中,聚簇索引“就是”表,所以不像MyISAM那样需要独立的行存储。聚簇索引的每个叶子节点都包含了主键值、事务ID、用于事务和MVCC的回滚指针以及所有的剩余列。如果主键是一个列前缀索引,InnoDB也会包含完整的主键列和剩下的其他列。
还有一点和MyISAM的不同是,InnoDB的二级索引和聚簇索引很不相同。InnoDB二级索引的叶子节点中存储的不是“行指针”,而是主键值,并以此作为指向行的“指针”。这样的策略减少了当出现航移动或者数据页分裂时二级索引的维护工作。使用主键值当作指针会让二级索引占用更多的空间,换来的好处是,InnoDB在移动行时无需更新二级索引中的这个“指针”。下图就是InnoDB的二级索引:
3、MyISAM和InnoDB的对比
五、在InnoDB表中按主键顺序插入行
如果正在使用InnoDB表并且没有什么数据需要聚集,那么可以定义一个代理键作为主键,这种主键的数据应该和应用无关,最简单的方法是使用auto_increment自增列。这样可以保证数据行是按照顺序写入,对于根据主键做关联操作的性能也会更好。
最好避免随机的聚簇索引,特别对于I/O密集型的应用。例如,从性能的角度考虑,使用UUID作为聚簇索引会很糟糕:它使得聚簇索引的插入变得完全随机,这是最坏的情况,使得数据没有任何聚集特性。通过测试,向UUID主键插入行不仅花费的时间更长,而且索引占用的空间也更大。这一方面是由于主键字段更长,另一方面毫无疑问是由于页分裂和碎片导致的。
这是由于当主键的值是顺序的,则InnoDB把每一条记录都存储在上一条记录的后面。当达到页的最大填充因子时(InnoDB默认的最大填充因子是页大小的15/16,留出的部分空间用于以后修改),下一条记录就会写入新的页中。一旦数据按照这样顺序的方式加载,主键页就会近似于被顺序的记录填满,这也是所期望的结果。
而当采用UUID的聚簇索引的表插入数据,因为新行的主键值不一定比之前的插入值大,所以InnoDB无法简单的总是把新行插入到索引的最后,而是需要为新的行寻找合适的位置----通常是已有数据的中间位置----并且分配空间。这会增加很多额外的工作,并导致数据分布不够优化。下面是总结的一些缺点:
- 写入目标页可能已经刷到磁盘上并从缓存中移除,或者是还没有被加载到缓存中,InnoDB在插入之前不得不先找到并从磁盘读取目标页到内存中,这将导致大量的随机I/O;
- 因为写入是乱序的,InnoDB不得不频繁的做页分裂操作,以便为新的行分配空间。页分裂会导致移动大量数据,一次插入最少需要修改三个页而不是一个页。
- 由于频繁的页分裂,页会变得稀疏并被不规则的填充,所以最终数据会有碎片。
- 把这些随机值载入到聚簇索引以后,需要做一次optimize table来重建表并优化页的填充。
注意:顺序主键也有缺点:对于高并发工作负载,在InnoDB中按主键顺序插入可能会造成明显的争用。主键的上界会成为“热点”。因为所有的插入都发生在这里,所以并发插入可能导致间隙锁竞争。另一个热点可能是auto_increment锁机制;如果遇到这个问题,则可能需要考虑重新设计表或者应用,或者更改innodb_autonc_lock_mode配置。
相关推荐
1、聚集索引 表数据按照索引的顺序来存储的,也就是说索引项的顺序与表中记录的物理顺序一致。对于聚集索引,叶子结点即存储了真实的数据行,不再有另外单独的数据页。 在一张表上最多只能创建一个聚集索引,因为...
##### 聚簇索引详解 聚簇索引(Clustered Index)是一种特殊的索引形式,其中主索引文件和数据文件实际上是同一个文件。这意味着聚簇索引的叶子节点直接包含了数据本身,而不是指向数据的指针。这种设计使得数据...
#### 二、聚簇索引详解 ##### 2.1 聚簇索引的特点 - **唯一性**:每个表最多只能有一个聚簇索引。 - **数据排序**:聚簇索引会按照索引键的值来对数据进行排序。 - **物理顺序**:由于聚簇索引确定了表中数据的...
- **非聚簇索引**:非主键索引是非聚簇索引,它们并不决定表中数据的物理存储顺序。 ##### 2.4 插入与删除 - **插入操作**:当向B+树中插入新的关键字时,如果当前节点已满,则需要进行分裂操作。B+树的分裂操作只...
- 创建聚簇索引前应避免创建非聚簇索引,因为聚簇索引会改变数据的物理排序。 2. **非聚簇索引**: - 非聚簇索引的结构独立于数据行,每个索引项包含指向数据行的指针。 - 默认情况下,创建索引时为非聚簇索引。...
- 缺点:如果表中没有合适的聚簇索引,InnoDB会选择一个合适的列自动创建一个隐藏的聚簇索引。 **非聚簇索引(Non-Clustered Index):** - 非聚簇索引的索引顺序与数据的物理排列顺序无关。 - 叶子节点包含了指向...
- **非聚簇索引(Nonclustered Index)**:非聚簇索引不改变数据的实际存储位置,而是通过索引表间接指向实际数据行。这种方式对于单行查询非常高效,因为它只需找到特定键值即可返回结果。 ##### 2.2 B树结构 B树是...
**Oracle索引详解** Oracle索引是数据库管理系统中用于提高查询效率的重要数据结构。它的工作原理类似于书籍的目录,允许数据库系统快速定位到所需的数据行,而无需扫描整个表。索引的存在使得对大量数据的查找、...
2. **非聚簇索引**:非聚簇索引不改变表中数据的实际存储顺序,而是单独创建一个索引结构,其中包含索引键和指向实际数据行的指针。每个表可以有多个非聚簇索引。这种索引在进行单行查询时效果很好。 #### 四、索引...
索引结构优化可以通过调整索引的结构来提高查询性能,例如,使用聚簇索引可以提高查询性能,但需要注意的是,聚簇索引也需要占用更多的存储空间。 索引使用优化可以通过合理地使用索引来提高查询性能,例如,使用...
2. **非聚簇索引(Nonclustered Index)**:这种索引不改变数据的物理顺序,而是创建一个指向数据行的索引。一个表可以有多个非聚簇索引。非聚簇索引适用于需要快速查找特定值的情况。 3. **唯一索引(Unique Index)**...
* 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。 * 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低...
文章目录慢查询慢查询配置慢查询解读慢查询工具mysqldumpslowpt_query_digest索引聚簇索引跟非聚簇索引聚簇索引非聚簇索引:覆盖索引(Covering Index)总结:重点执行计划执行计划详解重点 MySQL优化参考 ...
5. **非聚簇索引**:与聚簇索引相对应,它们将索引和数据分开存储。 ##### 1.1.3 基础语法 MySQL提供了多种方法来创建、查看和删除索引: - **查看索引**: ```sql SHOW INDEX FROM table_name \G ``` - **...
实验中使用T-SQL语句为`Course`表创建了名为`Course_Index`的惟一非聚簇索引,关键字为`Course_id`,采用降序排列,并设置了填充因子为80%,以减少页分裂的发生。 - **复合索引**:由多个列组成的索引,适用于多条件...
InnoDB存储引擎中的索引分为聚簇索引(Clustered Index)和非聚簇索引(Secondary Index,也称为辅助索引或二级索引)。聚簇索引是基于主键构建的,其特点是数据行与索引存储在一起,也就是说,主键索引的叶子节点...
4. InnoDB的聚簇索引尤其受益,因为二级索引包含了主键值,如果二级索引能覆盖查询,可以避免对主键索引的额外查询。 使用覆盖索引时需要注意,`SELECT`语句不应包含`*`,而应明确列出需要的列,以避免创建不必要的...
9. 聚簇索引和非聚簇索引的区别:聚簇索引是指索引和数据存储在一起的索引,而非聚簇索引是指索引和数据存储分离的索引。 10. MyISAM 和 InnoDB 实现 B+ 树索引的区别:MyISAM 和 InnoDB 都实现了 B+ 树索引,但是...