Mysql索引

作者: 游牧族人 | 来源:发表于2018-08-19 19:01 被阅读168次
    一、索引的分类

    1. 普通索引
    最基本的索引类型。

    (1.1)
    创建:
    CREATE INDEX index_name ON table_name(column1, column2, ...)
    ALTER TABLE table_name ADD INDEX index_name (column1, column2, ...)
    修改(mysql 5.7+):
    ALTER TABLE table_name RENAME INDEX old_index_name TO new_index_name
    删除:
    DROP INDEX index_name ON table_name
    ALTER TABLE table_name DROP INDEX index_name
    

    2. 唯一索引
    唯一的,不可重复的索引。

    (1.2)
    创建:
    CREATE UNIQUE INDEX index_name ON table_name(column1, column2, ...)
    ALTER TABLE table_name ADD UNIQUE index_name(column1, column2, ...)
    修改(mysql 5.7+):
    ALTER TABLE table_name RENAME INDEX old_index_name TO new_index_name
    删除:
    DROP INDEX index_name ON table_name
    ALTER TABLE table_name DROP INDEX index_name
    

    3. 主键索引
    是一种唯一性索引,但是他的字段必须指定为 PRIMARY KEY。

    (1.3)
    创建:
    ALTER TABLE table_name ADD PRIMARY KEY(column1, column2, ...)
    主键索引无法用 CREATE 语句创建。
    删除:
    ALTER TABLE table_name DROP PRIMARY KEY
    若是主键是自增的,那么要先取消主键的自增。
    一个数据表只能有一个主键。
    

    4.全文索引
    支持值的全文查找,适用于内容较多的字段上。

    (1.4)
    创建:
    CREATE FULLTEXT INDEX index_name ON table_name(column1, column2, ...)
    ALTER TABLE table_name ADD FULLTEXT(column1, column2, ...)
    删除:
    DROP INDEX index_name ON table_name
    ALTER TABLE table_name DROP INDEX index_name
    

    查看索引

    查看索引
    SHOW INDEX FROM table_name
    SHOW KEYS FROM table_name
    
    数据信息:
    Table              表名
    Non_unique         是否为唯一索引
    Key_name           索引名称
    Seq_in_index       索引列序列号
    Column_name        列名称
    Collation          列在索引中存放的方式
                       'A' 升序
                       'NULL' 无分类
    Cardinality        索引中唯一值数目的估计值 表连接查询时数值越大效率越高
    Sub_part           此列是否部分编入索引 
                       若是部分编入则显示编入的索引字符数
                       若是全部编入则显示 NULL
    Packed             指示关键字是如何进行压缩的  若没有被压缩则显示 NULL
    NULL               
    Index_type         索引类型(BTREE | FULLTEXT | HASH | RTREE)
    Comment            
    Index_Comment
    
    二、索引再分类

    1. 聚簇索引
    聚簇索引在一个数据表中只能有一个,一般是根据主键建立聚簇索引。聚簇索引的数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据一定也是相邻地存放在磁盘上的。聚簇索引要比非聚簇索引查询效率高很多。
    2. 非聚簇索引
    非聚簇索引在一个数据表中可以有任意个,非聚簇索引的数据的物理顺序和索引顺序是不一致的。

    区别与联系

    1. 聚簇索引在一个数据表中只能含有一个,非聚簇索引在一个数据表中可以含有多个。
    2. 聚簇索引数据物理顺序和逻辑顺序是一致的,非聚簇索引的物理顺序和逻辑顺序不是一致的。
    3. 聚簇索引的叶子节点就是数据节点,而非聚簇索引的叶子节点仍然是索引节点,只不过存在着指向对应数据块的指针。
    4. 当我们查询聚簇索引时,可以直接定位到数据节点并获取到数据信息。当我们查询非聚簇索引时不会直接定位到数据节点,而是定位到聚簇索引上然后根据聚簇索引再次定位到数据节点。
    三、索引实现方式

    B树
    B树的结构特点 [m阶]:

    1. 根节点至少有两个孩子。
    2. 每个中间节点都包含着 k-1 个元素和 k 个孩子 (m/2 <= k <= m)。
    3. 每个叶子节点都包含着 k-1 个元素 (m/2 <= k <= m)。
    4. 所有的叶子节点都位于同一层。
    5. 每个节点中的元素从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域分划。
    一颗B树

    B树的性能优势:
    降低了树的高度进而减少了磁盘的IO操作。

    B+树 [Mysql一般以B+树作为索引数据结构]
    B+树结构特点:

    1. 若B+树的树度为m,则节点指针上限为2m+1。
    2. 非叶子节点不存储数据,只存储节点指针。所有数据都存储在叶子节点之中
    3. 叶子节点之间通过顺序指针进行连接。
    一颗B+树

    B+树的性能优势:

    1. 由于B+树中间节点不存储数据,只存储节点指针,因此一个磁盘页(中间节点)可以容纳更多的节点指针,降低树的高度,进而减少数据IO次数。
    2. 因为B+树每次查询数据必须进入到叶子节点,因此查找性能比较稳定。
    3. 由于B+树的叶子节点之间存在指针连接,因此对于数据的范围查找不需要进行中序遍历,直接叶子节点指针遍历就好,查询效率更高。
    四、索引性能分析

    由于索引数据量大,不能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上。从磁盘上读取索引文件就要涉及到磁盘的IO操作,所以当IO次数越少我们的索引效率就会越高。索引的实现就是要尽可能的减少磁盘IO操作。
    根据B-Tree的定义,可知检索一次最多需要访问h个节点。数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。为了达到这个目的,在实际实现B-Tree还需要使用如下技巧:
    每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个node只需一次I/O。
    B-Tree中一次检索最多需要h-1次I/O(根节点常驻内存),渐进复杂度为O(h)=O(logdN)O(h)=O(logdN)。一般实际应用中,出度d是非常大的数字,通常超过100,因此h非常小。
    综上所述,用B-Tree作为索引结构效率是非常高的。
    而红黑树这种结构,h明显要深的多。由于逻辑上很近的节点(父子)物理上可能很远,无法利用局部性,所以红黑树的I/O渐进复杂度也为O(h),效率明显比B-Tree差很多。

    五、索引使用和优化

    1. 最左前缀原理与相关优化
    现在有一张数据表 artical

    id title date content
    ... ... ... ...
    ... ... ... ...

    建立联合索引:

    sql >> CREATE INDEX pri_index ON artical (id,title,date);
    
    • 全列匹配查询:
    sql >> SELECT * FROM artical 
           WHERE id = 1024 AND title = "Index Story" AND date = "2018-08-19" ;
    

    理论上索引是对顺序敏感的,但是Mysql查询优化器会自动调整where子句的条件以使用适合的索引。因此下面的sql语句也是效率很高的全列匹配查询:

    sql >> SELECT * FROM artical 
           WHERE date = "2018-08-19" AND id = 1024 AND  title = "Index Story" ;
    
    • 最左前缀匹配查询:
    sql >> SELECT * FROM artical WHERE id = 1024;
    

    这种查询仅仅用到了索引的第一列,剩余两列没有用到。

    sql >> SELECT * FROM artical WHERE id = 1024 AND date = "2018-08-19" ;
    

    这种情况虽然出现了联合索引中的两个索引,但是由于中间的title索引未使用因此无法与左前缀连接,因此查询也是仅仅使用到了id索引,而date数据的条件筛选未用索引,使用的是普通where子句查询。

    sql >> SELECT * FROM artical WHERE date = "2018-08-19" ;
    

    查询条件没有指定索引的第一列,显然这样的查询方式没有用到索引。

    • 范围查询索引使用
    sql >> SELECT * FROM artical WHERE id < 1024 AND title = "Index Story" ;
    

    范围列可以用到索引(必须是最左前缀),但是范围列后面的列无法用到索引。同时,索引只能用于一个范围列,如果查询过程中使用到了两个范围列则无法同时使用索引。

    • 函数或表达式索引
    sql >> SELECT * FROM artical where id -1 = 1024 ;
    

    在查询语句中索引列含有函数或表达式时索引无效。
    2. 索引选择
    索引的建立可以加快数据信息的查询速度,但是索引也会消耗内存空间,因此索引的建立需要进行考虑,并不是哪个字段需要查询就为哪个字段建立索引,索引并不是越多越好。

    1. 当表的数据量较少时不需要建立索引,直接全表查询的效率也不慢。
    2. 当表的字段不经常查询但是却经常增加或删除时不需要建立索引。因为数据库对于索引的维护成本就会很高。
    3. 当一个字段有很多个重复数据时不需要建立索引。例如性别列。
    4. 当我们为字段建立索引时,若字段的长度很长,我们可以考虑建立前缀索引。

    [参考:http://blog.codinglabs.org/articles/theory-of-mysql-index.html]

    相关文章

      网友评论

        本文标题:Mysql索引

        本文链接:https://www.haomeiwen.com/subject/phyfiftx.html