定义
索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。
索引的数据结构
二叉树
如果列是自增的,那么不建议使用二叉树,因为二叉树会链化。
红黑树(二叉平衡树)
早期MySQL层使用红黑树作为索引的数据结构。
Concurrent Hashmap底层就是红黑树。
如果数据量大的话,红黑树的高度会很大,效率仍然低。
B-Tree
B-Tree叶节点具有相同的深度,叶节点的指针为空。
所有索引元素不重复,节点中的数据索引从左到右递增排列。
B+Tree
MysqL以该数据结构存储索引。
非叶子节点不存储data,只存储索引(冗余)。叶子节点包含所有索引字段。叶子节点用指针连接,提高区间的访问性能。
BTree和B+Tree的区别
BTree,叶子节点之间没有指针而B+Tree有,不支持范围查找。
BTree的非叶子节点不存储数据,只存储冗余的索引数据。这样B+Tree可以在存储2000万左右数据的情况下只有三层,寻址快。
Hash结构
对索引的key进行一次hash计算就可以定位到数据存储的位置。
索引的类型
聚集索引(聚簇索引)
聚集索引clustered index也叫聚簇索引,聚集索引的表中数据行的物理顺序与列值(一般是主键的那一列)的逻辑顺序相同,一个表中只能拥有一个聚集索引。
索引文件和数据文件在同一个文件,如InnoDB存储引擎类型的表。
聚集索引数据读取快,因为数据和索引在一起,磁盘io少。
问题1:为什么建议InnoDB表必须建主键,且推荐使用整形的自增主键?
如果不建索引,那么MySQL会自动找一个不重复的列,作为唯一索引组织数据。如果没有不重复的列,MySQL会创建一个不重复的隐藏列作为唯一索引来组织数据。
问题2:为什么非主键索引结构叶子节点存储的是主键值?(一致性和节省存储空间)
3)聚簇索引的适用场景
包含大量非重复值的列。使用下列运算符返回一个范围值的查询:BETWEEN、>、>=、< 和 <=。被连续访问的列。返回大型结果集的查询。经常被使用联接或 GROUP BY 子句的查询访问的列;一般来说,这些是外键列。对 ORDER BY 或 GROUP BY 子句中指定的列进行索引,可以使 SQL Server 不必对数据进行排序,因为这些行已经排序。这样可以提高查询性能。OLTP型的应用程序,这些程序要求进行非常快速的单行查找(一般通过主键)。应在主键上创建聚集索引。
聚集索引不适用的场景:
频繁更改的列 这将导致整行移动,因为 SQL Server 必须按物理顺序保留行中的数据值。这一点要特别注意,因为在大数据量事务处理系统中数据是易失的
非聚集索引
索引文件和数据文件不在同一个文件,如M有ISAM存储引擎类型的表。
聚集索引数据读取稍慢,因为数据和索引不在一起,磁盘io多。
Hash索引
对索引的key进行一次hash计算就可以定位到数据的存储位置。
很多时候hash索引比b+树索引更高效。
hash索引仅支持“=”,“in”等,不支持范围查找。
联合索引
一张表不建议创建太多的索引,因为每个索引都需要一个索引树。
索引为何使得查询变快?
建立了索引的数据,就是通过事先排好序,从而在查找时可以应用二分查找来提高查询效率。这也解释了为什么索引应当尽可能的建立在主键这样的字段上,因为主键必须是唯一的,根据这样的字段生成的二叉查找树的效率无疑是最高的。
为什么索引不能建立的太多?
如果一个表中所有字段的索引很大,也会导致性能下降。如果一个索引和一个表一样长,那么它将再次成为一个需要检查的开销。这就好比字典的目录非常详细,但是其长度已经和所有的文字一样长,这个时候目录本身的效率就大大下降了。
索引有弊端吗?
肯定是有的,索引可以提高查询读取性能,而它将降低写入性能。当有索引时,如果更改一条记录,或者在数据库中插入一条新的记录,它将执行两个写入操作(一个操作是写入记录本身,另一个操作是将更新索引)。因此,在定义索引时,必须牢记以下几点:
-
索引表中的每个字段将降低写入性能。
-
建议使用表中的唯一值为字段编制索引。
-
在关系数据库中充当外键的字段必须建立索引,因为它们有助于跨多个表进行复杂查询。
-
索引还使用磁盘空间,因此在选择要索引的字段时要小心。
简历索引的最佳实践
1)业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引。
2)多表关联系时,需要join的字段数据类型要保持一致。多表关联查询时保证被关联的字段需要有索引。
3)在varchar字段上建立索引时,必须指定索引长度,没必要对全字段建立索引。
没走索引有可能是哪些原因?
1)查询数据不走左匹配。
2)查询字段使用函数运算。
3)查询没有使用联合索引最左边的列。
4)条件中用or,即使其中有条件带索引,也不会使用索引查询,这就是查询尽量不要用or的原因,用in吧。