MySQL/MariaDB数据库的索引工作原理和优化

                            作者:尹正杰 

版权声明:原创作品,谢绝转载!否则将追究法律责任。

 

  实际工作中索引这个技术是影响服务器性能一个非常重要的指标,因此我们得花时间去了解一下索引的相关特性。索引是一把双刃剑用得好可以快速查询数据,用得不好数据库查询速度不仅慢还降低服务器性能,浪费磁盘空间。

 

一.索引概述

1>.什么是索引

  索引是特殊数据结构,定义在查找时作为查找条件的字段,在MySQL又称为键key,索引通过存储引擎实现。

  索引可以看作是一本字典的目录,为了快速检索,用空间换时间,显著提高查询效率。

  可以为一列或者多列字段设置索引。

  不是说有了索引性能就一定能提升,有了索引咱们还得会利用索引,用正确的方法使用索引,使用不当反而会降低服务器性能。

2>.索引的优点

  索引可以降低服务需要扫描的数据量,减少了IO次数

  索引可以帮助服务器避免排序和使用临时表
  索引可以帮助将随机I
/O转为顺序I/O

3>.索引的缺点

  占用额外空间,影响插入速度

 

二.索引类型

主键索引:
  主键会自动建立主键索引,主键本身就是为了快速定位唯一记录的。
唯一索引:
  表中的索引列组成的索引必须唯一,但可以为空,非空值必须唯一
普通索引:
  没有唯一性的要求,就是建了一个字典的目录而已。
联合索引:
  多个字段组合创建索引,使用条件查询时,先匹配左边字段
全文索引:
  MyISAM使用,对Char、Varchar、TEXT类型使用 空间索引,SPATIAL,基本不用。 
聚簇(集)索引、非聚簇索引:
  数据和索引是否存储在一起
稠密索引、稀疏索引:
  是否索引了每一个数据项
简单索引、组合索引:
  左前缀索引:取前面的字符做索引
  覆盖索引:从索引中即可取出要查询的数据,性能高

 其他索引:
  B+ TREE、HASH、R TREE
  
在MySQL中,InnoDB和MyISAM的索引数据结构可以使用Hash或BTree,innodb默认是BTree。 Hash时间复杂度是O(
1),但是只能进行精确匹配,也就是Hash值的匹配,比如范围匹配就没办法了,   
hash值无序所以无法知道原有记录的顺序。Hash问题较多。 BTree索引,以B
+树为存储结构。   
虽然,索引可以提高查询所读,但是却影响增删改的效率,因为需要索引更新或重构。频繁出现在 where子句中的列可以考虑使用索引。要避免把性别这种字段设索引。

1>.二叉树

  MySQL/MariaDB数据库的索引工作原理和优化

1)每个结点最多2棵子树
    二叉树不存在度数大于2的结点。

(2)它是有序树,左子树,右子树是顺序的,不能交换次序

(3)即使某个节点只有一棵子树,也要确定它是左子树还是右子树

(4)二叉树的物种基本形态
    1)空二叉树
    2)只有一个根结点
    3)根结点只有左子树
    4)根结点只有右子树
    5)根结点有左子树和右子树

博主推荐阅读:
  https://baike.baidu.com/item/%E4%BA%8C%E5%8F%89%E6%A0%91
  https://www.cnblogs.com/yinzhengjie/p/10960896.html

2>.红黑树(又叫自平衡二叉树)

MySQL/MariaDB数据库的索引工作原理和优化

博主推荐阅读:
  https://baike.baidu.com/item/%E7%BA%A2%E9%BB%91%E6%A0%91

3>.B-tree索引(B-tree(多路搜索树,并不是二叉的)

B-tree(多路搜索树,并不是二叉的)是一种常见的数据结构。使用B-tree结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度。按照翻译,B 通常认为是Balance的简称。这个数据结构一般用于数据库的索引,综合效率较高。

博主推荐阅读:
  https://baike.baidu.com/item/B-tree/6606402?fr=aladdin

4>.B+树(MySQL数据库默认使用该索引)

MySQL/MariaDB数据库的索引工作原理和优化

B+树是一种树数据结构,通常用于数据库和操作系统的文件系统中。B+树的特点是能够保持数据稳定有序,其插入与修改拥有较稳定的对数时间复杂度。B+树元素自底向上插入,这与二叉树恰好相反。
  B+树节点组织成一棵树。节点分为内部节点和叶子节点。
  内部节点不存储数据,叶子节点不存储指针。
  如下图所示,每个leaf node保存数据,所有的leaf node组织成链表。假设读取16到22的数据,找到18后,顺着链表 往后遍历读取即可。
  InnoDB中,数据文件本身就是按主键索引存储的,叶子节点中保存的就是数据记录。 如果在其他字段上定义B
+Tree索引,叶子节点的数据记录的是主键,这种称为辅助索引。 B+Tree索引:   顺序存储,每一个叶子节点到根结点的距离是相同的;左前缀索引,适合查询范围类的数据 可以使用B+Tree索引的查询类型:   全值匹配:精确所有索引列,如:姓yin,名zhengjie,年龄18   匹配最左前缀:即只使用索引的第一列,如:姓yin   匹配列前缀:只匹配一列值开头部分,如:姓以y开头的   匹配范围值:如:姓yin和姓ma之间   精确匹配某一列并范围匹配另一列:如:姓yin,名以x开头的   只访问索引的查询 B+Tree索引的限制:   如不从最左列开始,则无法使用索引,如:查找名为zhengjie,或姓为g结尾   不能跳过索引中的列:如:查找姓yin,年龄18的,只能使用索引第一列   如果查询中某个列是为范围查询,那么其右侧的列都无法再使用索引:如:姓yin,名z%,年龄18,只能利用姓和名上面的索引 特别提示:   索引列的顺序和查询语句的写法应相匹配,才能更好的利用索引   为优化性能,可能需要针对相同的列但顺序不同创建不同的索引来满足不同类型的查询需求 博主推荐阅读:   https://baike.baidu.com/item/B+%E6%A0%91/7845683

MySQL/MariaDB数据库的索引工作原理和优化

5>.Hash索引

Hash索引:
  基于哈希表实现,只有精确匹配索引中的所有列的查询才有效,索引自身只存储索引列对应的哈希值和数据指针,索引结构紧凑,查询性能好
Memory存储引擎支持显式hash索引,InnoDB和MyISAM存储引擎不支持

适用场景:
  只支持等值比较查询,包括=, <=>, IN()

不适合使用hash索引的场景
  不适用于顺序查询:索引存储顺序的不是值的顺序
  不支持模糊匹配
  不支持范围查询
  不支持部分索引列匹配查找:如A,B列索引,只查询A列索引无效

6>.空间数据索引R-Tree( Geospatial indexing )

  MyISAM支持地理空间索引,可以使用任意维度组合查询,使用特有的函数访问,常用于做地理数据存储,使用不多

  InnoDB从MySQL5.7之后也开始支持

7>.全文索引(FULLTEXT)

  在文本中查找关键词,而不是直接比较索引中的值,类似搜索引擎

  InnoDB从MySQL
5.6之后也开始支持

8>.聚簇和非聚簇索引

MySQL/MariaDB数据库的索引工作原理和优化

9>.聚簇和非聚簇索引,主键和二级索引

MySQL/MariaDB数据库的索引工作原理和优化

10>.冗余和重复索引

  冗余索引:(A),(A,B)

  重复索引:已经有索引,再次建立索引

11>.索引优化策略

  独立地使用列:
    尽量避免其参与运算,独立的列指索引列不能是表达式的一部分,也不能是函数的参数,在where条件中,始终将索引列单独放在比较符号的一侧
  左前缀索引:
    构建指定索引字段的左侧的字符数,要通过索引选择性来评估
  索引选择性:
    不重复的索引值和数据表的记录总数的比值
  多列索引:
    AND操作时更适合使用多列索引,而非为每个列创建单独的索引
  选择合适的索引列顺序:
    无排序和分组时,将选择性最高放左侧

12>.索引优化建议

  只要列中含有NULL值,就最好不要在此例设置索引,复合索引如果有NULL值,此列在使用时也不会使用索引

  尽量使用短索引,如果可以,应该制定一个前缀长度
  对于经常在where子句使用的列,最好设置索引
  对于有多个列where或者order by子句,应该建立复合索引
  对于like语句,以
%或者‘-’开头的不会使用索引,以%结尾会使用索引
  尽量不要在列上进行运算(函数操作和表达式操作)  

  尽量不要使用not in和
<>操作

13>.SQL语句性能优化

  查询时,能不要*就不用*,尽量写全字段名

  大部分情况连接效率远大于子查询
  多表连接时,尽量小表驱动大表,即小表
join 大表
  在有大量记录的表分页时使用limit
  对于经常使用的查询,可以开启缓存
  多使用explain和profile分析查询语句
  查看慢查询日志,找出执行时间长的sql语句优化

 

三.管理索引实战

1>.创建测试数据

MariaDB [yinzhengjie]> CREATE TABLE  index_test (id INT auto_increment PRIMARY KEY,name CHAR(50),age INT DEFAULT 20);
Query OK, 0 rows affected (0.01 sec)

MariaDB [yinzhengjie]> 
MariaDB [yinzhengjie]> DELIMITER $$
MariaDB [yinzhengjie]> 
MariaDB [yinzhengjie]> CREATE PROCEDURE pro_testlog() 
    -> BEGIN  
    -> DECLARE i INT;
    -> SET i = 1; 
    -> WHILE i < 100000 
    -> DO  
    ->     INSERT INTO index_test(name,age) VALUES (CONCAT('yinzhengjie',i),i); 
    ->     SET i = i +1; 
    -> END WHILE; 
    -> END$$
Query OK, 0 rows affected (0.00 sec)

MariaDB [yinzhengjie]> 
MariaDB [yinzhengjie]> DELIMITER ;
MariaDB [yinzhengjie]> 
创建测试表及存储过程

相关文章:

  • 2021-04-01
  • 2021-04-29
  • 2021-11-05
  • 2021-12-10
  • 2021-06-29
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2021-09-10
相关资源
相似解决方案