什么样的列适合建索引?
适合创建索引的列:主键、频繁进行范围检索的列、时常进行多表连接的列、数据量大的表,数据差异大的列。
索引优缺点
索引是数据库中用于提高数据检索性能的排好序的数据结构。它类似于书籍的目录,通过建立特定的数据结构将列或多个列的值与它们在数据表中对应的行关联起来,以加快查询速度。
索引的优点包括:
- 提高查询性能:索引可以加快数据库查找数据的速度,通过快速定位到符合查询条件的数据行,减少了数据库进行全表扫描的开销,从而显著提高查询效率。
- 唯一性约束:通过在索引上设置唯一性约束,可以确保数据的唯一性,防止重复数据的插入。
然而,索引也有一些缺点:
- 占用存储空间:索引通常需要占用一定的磁盘空间。过多的索引可能会增加存储成本。
- 索引维护的开销:当对数据表进行插入、更新或删除操作时,索引也需要进行相应的维护操作,这可能导致数据写入的性能下降,更新缓慢。
索引失效的情况
索引失效是指在使用索引进行查询时,索引无法发挥作用,导致查询性能下降。常见的导致索引失效的情况有以下几种:
- 不满足索引列顺序:如果查询条件中的列顺序与索引列的顺序不一致,索引可能无法被使用。例如,一个联合索引(A, B),如果查询条件只包含了B列而没有A列,那么这个索引就无法被利用。
- 使用函数或表达式:当查询条件中对索引列应用了函数、数学运算、类型转换等操作时,索引可能无法被使用。因为索引的创建是基于原始列值的,无法直接使用函数计算后的结果进行索引匹配。
- 字符串比较问题:对于字符串类型的索引列,使用了不符合索引规则的比较方式。
- 数据类型不匹配:当查询条件的数据类型与索引列的数据类型不匹配时,索引可能无法被使用。尤其是在进行隐式数据类型转换、不同字符集的比较或编码问题时,需要特别留意。
- 数据量过小:当表中的数据量较小时,MySQL可能会选择全表扫描而非使用索引,因为全表扫描的成本较低。这种情况下,索引可能无法发挥作用。
- 使用了NOT、<>、OR等非优化的逻辑操作符:这些逻辑操作符在查询条件中的使用会导致索引失效,因为它们无法充分利用索引的特性。
聚簇索引和非聚簇索引
1) 聚簇索引(聚集索引)
聚簇索引就是按照每张表的主键构造一颗B+树,同时叶子节点中存放的就是整张表的行记录数据,也将聚集索引的叶子节点称为数据页。这个特性决定了索引组织表中数据也是索引的一部分,每张表只能拥有一个聚簇索引。
Innodb通过主键聚集数据,如果没有定义主键,innodb会选择非空的唯一索引代替。如果没有这样的索引,innodb会隐式的定义一个主键来作为聚簇索引。
2) 聚簇索引的优缺点
优点:
1.数据访问更快,因为聚簇索引将索引和数据保存在同一个B+树中,因此从聚簇索引中获取数据比非聚簇索引更快。
2.聚簇索引对于主键的排序查找和范围查找速度非常快。
缺点:
1.插入速度严重依赖于插入顺序,按照主键的顺序插入是最快的方式,否则将会出现页分裂,严重影响性能。因此,对于InnoDB表,我们一般都会定义一个自增的ID列为主键。
2.更新主键的代价很高,因为将会导致被更新的行移动。因此,对于InnoDB表,我们一般定义主键为不可更新。
3.二级索引访问需要两次索引查找,第一次找到主键值,第二次根据主键值找到行数据。
3) 辅助索引(非聚簇索引)
在聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找。辅助索引叶子节点存储的不再是行的物理位置,而是主键值。通过辅助索引首先找到的是主键值,再通过主键值找到数据行的数据页,再通过数据页中的Page Directory找到数据行。
Innodb辅助索引的叶子节点并不包含行记录的全部数据,叶子节点除了包含键值外,还包含了相应行数据的聚簇索引键。
辅助索引的存在不影响数据在聚簇索引中的组织,所以一张表可以有多个辅助索引。在innodb中有时也称辅助索引为二级索引。
创建索引的原则
1.适合索引的是出现在where子句的列,或者连接子句中指定的列。
2.基数较小的表,索引效果较差,没有必要在此列建立索引。
3.使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度,这样能够节省大量索引空间,如果搜索词超过索引前缀长度,则使用索引排除不匹配的行,然后检查其余行是否可能匹配。
4.不要过度索引。索引需要额外的磁盘空间,并降低写操作的性能。在修改表内容的时候,索引会进行更新甚至重构,索引列越多,这个时间越长。所以只需要保持需要的索引有利于条件查询就行了。
5.定义有外键的数据列一定要建立索引。
6.更新频繁字段不适合创建索引。
7.若是不能有效区分数据的列不适合做索引(状态字段)
8.尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。
9.对于那些查询中很少涉及的列,重复值比较多的列不要建立索引。
10.对于定义为text、image和bit的数据类型的列不要建立索引。
创建索引是一个需要根据实际情况不断调整和优化的过程,合理的索引设计可以显著提升数据库的性能。
MySql的索引结构是什么样的,聚簇索引和非聚簇索引区别
二叉树=>AVL树=>红黑树=>B-树=>B+树
二叉树,左<根<右 检索快 AVL树 树中任意节点的子树的高度差最大是1;
红黑树,1.每个节点都是红or黑 2.根节点是黑 3.每个叶子节点都是黑色 4.红色节点的父子节点都必须是黑的 5.从任一个节点到叶子节点的所有路径都包含相同的黑色结点
B-树,1.B-树的每个非叶子节点的子节点个数不超过阶数 2.所有叶子节点都在同一层 3.所有叶子节点关键字按照递增排序
B+树,1.非叶子节点不存数据,只进行数据索引。2.所有数据都放在叶子节点中。 3.每个叶子节点都存在相邻叶子节点的指针。4.叶子节点按照本身关键字从大到小排序。
聚簇索引 就是数据和索引是在一起的。
MyISAM使用的是非聚簇索引 ,树的子节点上的data不是数据本身,而是数据存放的地址。InnoDB采用的是聚簇索引,树的
叶子节点上的data就是数据本身。
聚簇索引的数据物理存放顺序和索引顺序是一致的,所以一个表当中只能有一个聚簇索引,而非聚簇索引可以有多个。
InnoDB中,如果表定义了PK,那PK就是聚簇索引。如果没有PK,就会找第一个非空的unique列作为聚簇索引。否则,
InnoDB会创建一个隐藏的row-id作为聚簇索引。
B+树索引和Hash索引
B树索引(B-Tree) 默认使用的索引结构
优点:
- 效率:B树索引提供了对数据的快速访问,特别是对于范围查询非常有效。
- 自平衡:B树是一种自平衡的树结构,可以保持数据有序,从而使得数据的插入和删除操作都能保持对数时间复杂度。
- 聚簇索引:在InnoDB存储引擎中,数据行的存储是按照主键顺序进行的,这使得聚簇索引(Clustered Index)非常高效。
- 顺序访问:B树索引支持顺序访问,适合于执行需要按索引顺序进行数据检索的查询。
缺点:
- 更新成本:对于经常进行数据更新的表,维护B树索引可能需要更多的开销,因为每次更新可能都需要调整树结构。
- 空间占用:相比于哈希索引,B树索引可能会占用更多的存储空间。
哈希索引(Hash)
优点:
- 快速访问 :哈希索引在等值查询(如
=
或IN
)中非常快,可以达到常数时间复杂度O(1)。 - 简单高效:哈希索引结构简单,对于点查询非常高效。
缺点:
- 不支持范围查询:哈希索引不支持范围扫描,这限制了它在需要范围数据检索的查询中的使用。
- 哈希冲突:哈希索引需要解决哈希冲突问题,这可能会影响性能。
- 数据无序 :哈希索引不保证数据的顺序,因此对于需要索引顺序的查询(如
ORDER BY
)不适用。
索引类型和性能
- 普通索引(INDEX) :
- 这是最基本的索引类型,没有唯一性的限制,允许重复的索引值和NULL值。
- 唯一索引(UNIQUE INDEX) :
- 唯一索引要求索引列的值必须唯一,但允许有空值(NULL)。如果是组合索引,则组合的列值必须唯一。
- 主键索引(PRIMARY KEY) :
- 主键索引是一种特殊的唯一索引,它不仅要求索引列的值唯一,而且不允许有空值。每个表只能有一个主键索引。
- 组合索引(COMPOSITE INDEX) :
- 组合索引,也称为多列索引,是在一个表的多个列上创建的索引。它允许根据多个列的值进行数据检索,提高查询效率。
- 全文索引(FULLTEXT INDEX) :
- 主要用于对文本内容进行全文搜索,如对CHAR、VARCHAR或TEXT列进行搜索。
- 空间索引(SPATIAL INDEX) :
- 用于地理空间数据类型,以支持地理空间数据存储和查询。
- 外键索引(FOREIGN KEY) :
- 用于在两个表之间建立链接,确保引用的数据的完整性和准确性。
- 辅助索引(SECONDARY INDEX) :
- InnoDB存储引擎中,除了聚簇索引之外的所有索引都被称为辅助索引。
性能方面,索引可以显著提高查询速度,但也会带来一些性能考虑:
- 查询性能:索引可以快速定位到数据,减少查询时间,尤其是对于大型数据集。
- 更新性能:索引可能会降低数据的插入、删除和更新操作的速度,因为每次变动都需要同步索引。
- 存储空间:索引会占用额外的磁盘空间,尤其是当索引列包含大量数据时。
- 维护开销:随着数据的变动,索引需要维护,这可能会消耗额外的资源。
覆盖索引和回表
如果只需要在一颗索引树上就可以获取SQL所需要的所有列,就不需要再回表查询,这样查询速度就可以更快。
实现索引覆盖最简单的方式就是将要查询的字段,全部建立到联合索引当中。
user(PK id, name ,sex)
select count(name) from user; -->在name上建立索引
select id,name,sex from user; -->在name上的索引升级成为(name,sex)的联合索引