MySQL索引(九)

一、索引介绍

1.1 什么是索引

索引就好比一本书的目录,它会让你更快的找到内容。

让获取的数据更有目的性,从而提高数据库检索数据的性能。

分为以下四种:

  • BTREE:B+树索引(基本上都是使用此索引)
  • HASH:HASH索引
  • FULLTEXT:全文索引
  • RTREE:R树索引

树形结构(B树:B树、B+树、B*树),

B树索引由多个层次构成:‘根’,‘枝’,‘叶’,它建立在表的列上

stu(id, name, age)

假如说,在id列上建索引

  A. 对id列的值,进行自动排序,把这些值有规律的存放到各个叶子节点

  B. 并且叶子节点还会存储整行数据的指针信息

  C. 生成上层枝节点,存储每个对应叶子节点最小值和叶子节点指针

  D. 生成根节点,存储每个枝节点的最小值以及对应的存储指针

  以上是B树索引的基本构成

  E. 对于B+树索引结构,对于范围查询有了更好的优化,叶子节点还会记录相邻叶子节点指针

  F. 对于B*树索引结构,枝节点还会记录相领枝节点的指针情况

B+树图:

1.2 主键和索引的区别

索引:索引好比是一本书的目录,可以快速的通过页码找到你需要的那一页。惟一地标识一行。
主键:做为数据库表唯一行标识,作为一个可以被外键有效引用的对象。
索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。索引可以大大提高MySQL的检索速度。
数据库有两种查询方式,一个全表扫描,条件匹配。一个是索引。
主键是特殊的索引,主键是索引,索引不一定是主键,索引可以是多列,主键只能是一列。

二、索引执行计划管理

基于特点的一些分类:

  1. 主键索引(聚集索引 cluseter indexes):parmary key(创建主键后自动生成的,最符合B+ 树的)
  2. 唯一键:唯一键索引(都是唯一值的列)
  3. 普通键:辅助索引(sec indexex)

优先使用主键索引,查询的时候还要基于主键索引进行查询。

三、添加、查询、删除索引

-- 添加一张表
mysql> create table stu (id int not null auto_increment primary key,name varchar(20),age tinyint,gender enum(‘m‘,‘f‘),telnum varchar(12),qq varchar(20));
Query OK, 0 rows affected (0.02 sec)

-- 把name列设置为普通索引,idx_name为key的名字
mysql> alter table stu add index idx_name(name);
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

-- 查询索引
mysql> desc stu;
+--------+---------------+------+-----+---------+----------------+
| Field  | Type          | Null | Key | Default | Extra          |
+--------+---------------+------+-----+---------+----------------+
| id     | int(11)       | NO   | PRI | NULL    | auto_increment |
| name   | varchar(20)   | YES  | MUL | NULL    |                |
| age    | tinyint(4)    | YES  |     | NULL    |                |
| gender | enum(‘m‘,‘f‘) | YES  |     | NULL    |                |
| telnum | varchar(12)   | YES  |     | NULL    |                |
| qq     | varchar(20)   | YES  |     | NULL    |                |
+--------+---------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)

mysql> show index from stu;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| stu   |          0 | PRIMARY  |            1 | id          | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |
| stu   |          1 | idx_name |            1 | name        | A         |           0 |     NULL | NULL   | YES  | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.00 sec)

mysql> show index from stu\G
*************************** 1. row ***************************
        Table: stu
   Non_unique: 0
     Key_name: PRIMARY
 Seq_in_index: 1
  Column_name: id
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null:
   Index_type: BTREE
      Comment:
Index_comment:
*************************** 2. row ***************************
        Table: stu
   Non_unique: 1
     Key_name: idx_name
 Seq_in_index: 1
  Column_name: name
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
2 rows in set (0.00 sec)

-- 删除索引
mysql> alter table stu drop key idx_name;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from stu;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| stu   |          0 | PRIMARY  |            1 | id          | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)

-- key就是索引的意思,PRI就是主键,MUL就是普通的索引,UNQ、UNI 是唯一键

四、创建表的时候创建自增主键

CREATE TABLE `stu` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `age` tinyint(4) DEFAULT NULL,
  `gender` enum(‘m‘,‘f‘) DEFAULT NULL,
  `telnum` varchar(12) DEFAULT NULL,
  `qq` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

如果当时没有创建,后面可以增加

mysql> CREATE TABLE `stu_test` (
    ->   `id` int(11) NOT NULL,
    ->   `name` varchar(20) DEFAULT NULL
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.23 sec)

mysql> desc stu_test;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   |     | NULL    |       |
| name  | varchar(20) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

mysql> alter table stu_test change id id int(11) primary key not null auto_increment;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc stu_test;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

五、唯一索引

内容唯一,但不是主键

可以统计一下有没有重复值,用去重后的行数,和总行数做个比较,如果不一样,说明有重复的值。

-- 添加telnum为唯一键索引
alter table stu add UNIQUE key uni_tel(telnum);

-- 统计总行数
select count(*) from webdb.t1;
-- telnum列去重之后还剩多少行
SELECT count(distinct telnum) from webdb.t1;

还可以判断是不是唯一索引,最简单的方法是建一建试试,如果建不上 说明有重复的。

六、前缀索引和联合索引

如果字符较长的时候,可以使用前缀索引

-- 根据字段的前10个字符建立索引,名称为index_note
alter table stu add note varchar(200);
alter table stu add index index_note(note(10));

联合索引

多个字段建立一个索引

条件:a(女生) and b(身高165) and c(身材好)

Index(a,b,c)

特点:前缀生效特性。

a,ab,abc,ac  可以走索引或者部分走索引

原则:把最常用来作为条件查询的列放在前面。

mysql> alter table stu add money int;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql> alter table stu add index idx_dup(gender,age,money);
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql> show index from stu;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| stu   |          0 | PRIMARY  |            1 | id          | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |
| stu   |          0 | uni_tel  |            1 | telnum      | A         |           0 |     NULL | NULL   | YES  | BTREE      |         |               |
| stu   |          1 | idx_dup  |            1 | gender      | A         |           0 |     NULL | NULL   | YES  | BTREE      |         |               |
| stu   |          1 | idx_dup  |            2 | age         | A         |           0 |     NULL | NULL   | YES  | BTREE      |         |               |
| stu   |          1 | idx_dup  |            3 | money       | A         |           0 |     NULL | NULL   | YES  | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
5 rows in set (0.00 sec)

七、explain 命令分析

MySQL中的执行计划,只分为两种。都是优化器决定的

全表扫描:

  一般在线上业务系统,要避免全表扫描

索引扫描:

  将要获取的数据,变得更有目的性。

通过explain命令来 获取优化器选择后的执行计划,并不输出后面的语句结果。

mysql> explain select id,name from t1 where name=‘andy‘;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | t1    | ALL  | NULL          | NULL | NULL    | NULL |    2 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

-- type 表示的是使用的是全表扫描还是索引扫描
-- type 类型如下:ALL、index、range、ref、eq_ref、const、system、Null
-- 从左到右,性能越来越好,我们在使用索引是,最底应达到range-- key_len值越小越好-- rows值越小越好

ALL 全表扫描

index:Full index scan,index与ALL区别为index类型只遍历索引树

range:索引范围扫描,对索引的扫描开始于某一点,返回匹配值域的行。显而易见的索引范围扫描是带有between或者where子句里带有<,>查询。

where条件后 > < >= <= in or between and   like ‘m%‘

不等于是不走索引的!= 、<>、like ‘%m%‘

此句性能略差

可改写为

ref:使用非唯一索引扫描或者唯一索引的前缀扫描,返回匹配某个单独值的记录行

eq_ref:类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者unique key作为关键条件。

A join B

on A.sid=b.sid

const、system:当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类方法访问。

如:将主键置于where列表中,MySQL就能将该查询转换为一个常量。

NULL:MySQL在优化过程中分解语句,执行时甚至不用访问表过索引。

例如:从一个索引列里选取最小值可通过单独索引查找完成

如果出现以上附加信息,请检查order by,group by,distince,join条件列上有没有合理的索引。(联合索引)

单列索引也不会避免filesort的出现

如果想优化,必须创建联合索引。

会发现,下面有两个索引,最后走的新创建的dup_codepogo

但是基于countcode有两个索引,需要删除一个,否则会影响优化器的算法。

Possible_key只有一个了,里面的extra正常了,只要不是filesort就正常。

八、建立索引的原则(运维规范)

数据库索引的设计原则:

为了使索引的使用效率更高,在创建索引时,必须考虑在哪些字段上创建索引和创建什么类型的索引,那么索引设计原因又是怎样的呢?

  1. 选择唯一性索引
  • 唯一性索引的值是唯一的,可以更快速的通过该索引来确定某条记录
  • 例如:学生表中学号是具有唯一性的字段。为该字段建立唯一性索引可以很快的确定某个学生的信息,如果使用姓名的话,可能存在同名现象,从而降低查询速度。
  • 主键索引和唯一索引,在查询中使用的效率最高的。

  注意:如果重复值较多,可以考虑采用联合索引

   2.为经常需要排序、分组和联合操作的字段建立索引

  • 经常需要order by、group by、distinct和union等操作的字段,排序操作会浪费很多时间。
  • 如果为其建立索引,可以有效地避免排序操作。

   3.为常作为查询条件的字段建立索引

  • 如果某个字段经常用来做查询条件,那么该字段查询的速度会影响整个表的查询速度。因此为这样的字段建立索引,可以提高整个表的查询速度。
  • 经常查询
  • 列值的重复值少

   4.尽量使用前缀来索引

  • 如果索引字段的值很长,最好使用值的前缀来索引。
  • 例如:TEXT和BLOG类型的字段,进行全文检索会很浪费时间。如果只检索字段前面的若干字符,这样可以提高检索速度。

――――以上重点关注――――以下是能保护则保证的―――――

  1. 限制索引的数目
  • 索引的数目不是越多越好。每个索引都需要占用磁盘空间,索引越多,需要占用的磁盘就越大,修改表时,对索引的重构和和更新很麻烦。越多的索引,会使更新表变得很浪费时间

   2.删除不再使用,或者很少使用索引

  • 表中的数据被大量更新,或者数据的使用方式被改变后,原有的一些索引可能不再需要。数据库管理员应当定期找出这些索引,将它们删除,从而减少索引对更新操作的影响。

――――不走索引的情况---------(开发规范)

重点关注:

  1.没有查询条件,或者查询条件没有建立索引

-- 全表扫描
select * from t1;

-- 工具生成,和全表扫描是一样的
select * from t1 where 1=1; 

  在线上业务数据库中,特别是数据量比较大的表,是没有全表扫描这种需求的。

  A.对用户查看是非常痛苦的。

  B.对服务器来讲是毁灭性的

  例外:数据处理分析的业务,一般也不用mysql了

select * from t1;
-- SQL改写成以下语句
-- 需要在price列上建立索引
select * from t1 ORDER BY price limit 10;

  2.查询结果集是原表中的大部分数据,应该是25%以上。

  查询的结果集,超过了总数行数25%,优化器觉得没必要走索引了。

  如果业务允许,可以使用limit控制

  怎么改写?

  结合业务判断,有没有更好的方式。如果没有更好的改写方案,尽量不要在mysql存放这个数据了,放到redis中。

  3.索引本身失效,统计数据不真实

  索引有自我维护能力。

  对于表内容变化比较频繁的情况下,有可能会出现索引失败。

  4.查询条件使用函数在索引列上,或者对索引进行运算。运算符包括(+ - * / ! 等)

-- 错误的
select * from test where id-1=9;

--正确的
select * from test where id=10;

  5.隐式转换导致索引失效,这一点应当引起重视,也是开发中常犯的错误。

  这样会导航不索引失效,错误的例子

  隐式的把数字转换成字符串

  6.<>  、not in 不走索引

  7.like ‘%a‘ 百分号在最前面不走索引

  %linux%类的搜索需求,可以使用elasticsearch

  8. 单独引用复合索引里非第一位置的索引列。

  复合索引index(a,b,c)

  where a

  where a b

  where a b c

  保会走a的部分索引

  where a c

  where a c b

  不走索引的:

  任何where条件列a不在第一条件列的情况不走索引

原文地址:https://www.cnblogs.com/cyleon/p/11555915.html

时间: 2024-10-30 14:15:31

MySQL索引(九)的相关文章

MySQL— 索引

目录 一.索引 二.索引类型 三.索引种类 四.操作索引 五.创建索引的时机 六.命中索引 七.其它注意事项 八.LIMIT分页 九.执行计划 十.慢查询日志 一.索引 MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度. 打个比方,如果合理的设计且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是一个人力三轮车. 索引分单列索引和组合索引.单列索引,即一个索引只包含单个列,一个表可以有多个单列索引,但这不是组合索引.组合索引

mysql:索引原理与慢查询优化

一 介绍 二 索引的原理 三 索引的数据结构 三 MySQL索引管理 四 测试索引 五 正确使用索引 六 查询优化神器-explain 七 慢查询优化的基本步骤 八 慢日志管理 九 参考博客 一 介绍 为何要有索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,因此对查询语句的优化显然是重中之重.说起加速查询,就不得不提到索引了. 什么是索引? 索引在MySQL中也叫做"键&quo

mysql索引原理与查询快慢

=========索引原理与慢查询======= 阅读目录 -     一.介绍 -     二.索引的原理 -     三.索引的数据结构 -     四.聚集索引与辅助索引 -     五.MySQL索引管理 -     六.测试索引 -     七.正确使用索引 -     八.联合索引与覆盖索引 -     九.查询优化神器-explain -     十.慢查询优化的步骤 -     十一.慢日志管理 一.介绍 为何要有索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般

mysql索引原理与查询优化

阅读目录 一 介绍 二 索引的原理 三 索引的数据结构 四 聚集索引与辅助索引 五 MySQL索引管理 六 测试索引 七 正确使用索引 八 联合索引与覆盖索引 九 查询优化神器-explain 十 慢查询优化的基本步骤 十一 慢日志管理 一 介绍 为何要有索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,因此对查询语句的优化显然是重中之重.说起加速查询,就不得不提到索引了. 什么

数据库优化(二)—— MySQL索引优化

目录 MySQL的索引优化 一.MySQL 5.7的初始化配置 二.MySQL配置文件 1.配置 2.配置文件作用 三.多实例 1.创建相关的目录 2.创建实例的配置文件 3.初始化 4.授权 5.启动实例 6.查看启动状况 7.测试 8.配置启动脚本 9.开机自启 10.设定mysql密码 11.忘记密码 四.数据类型 1.整型 2.字符串类型 3.时间类型 规范 五.索引 1.索引作用 2.索引种类 3.Btree 分类 4.聚集索引和辅助索引的对比 六.MySQL索引管理 1.创建索引(辅

MySQL索引基本应用[转]

原文地址:http://www.php100.com/html/webkaifa/database/Mysql/2010/0409/4279.html 索引是快速搜索的关键.MySQL索引的建立对于MySQL的高效运行是很重要的.下面介绍几种常见的MySQL索引类型. 在数据库表中,对字段建立索引可以大大提高查询速度.假如我们创建了一个 mytable表: CREATE TABLE mytable(   ID INT NOT NULL,    username VARCHAR(16) NOT N

深入浅出分析MySQL索引设计背后的数据结构

在我们公司的DB规范中,明确规定: 1.建表语句必须明确指定主键 2.无特殊情况,主键必须单调递增 对于这项规定,很多研发小伙伴不理解.本文就来深入简出地分析MySQL索引设计背后的数据结构和算法,从而可以帮你释疑如下问题: 1.为什么innodb表需要主键? 2.为什么建议innodb表主键是单调递增? 3.为什么不建议innodb表主键设置过长? B-tree(多路搜索树,并不是二叉的)是一种常见的数据结构.使用B-tree结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度.B通常

mysql索引介绍

在数据表中对字段建立索引将大大提高查询的速度: 例如:select * from mytable where username='admin' 如果在列username上建立了索引,只需要一次就可以找到该记录 一.mysql索引的类型: 1.普通索引 创建:create index indexname on mytable(username) 删除:drop index [indexname] on mytable 2.唯一索引 特点:索引列值必须唯一,但允许有null值 创建:create u

mysql索引总结----mysql 索引类型以及创建

关于MySQL索引的好处,如果正确合理设计并且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是一个人力三轮车.对于没有索引的表,单表查询可能几十万数据就是瓶颈,而通常大型网站单日就可能会产生几十万甚至几百万的数据,没有索引查询会变的非常缓慢.还是以WordPress来说,其多个数据表都会对经常被查询的字段添加索引,比如wp_comments表中针对5个字段设计了BTREE索引. 一个简单的对比测试 以我去年测试的数据作为一个简单示例,20多条数据源随机生成200万条

MySQL索引

mysql索引  注意:创建索引的基本原则   索引要建在使用比较多的字段上   尽量不要在相同值比较多的列建立索引,比如性别.年龄等字段   对于经常进行数据存取的列不要建立索引   对于有外键引用的表,在主键和外键上建立索引   1.普通索引 索引创建的三种方式===== 主键是一种特殊索引 表已创建  ===help create index; create index ipaddr_idx on test(ipaddr); mysql> create index ipaddr_idx o