vlambda博客
学习文章列表

数据库优化 -索引-避免全表扫描

定义

索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。

1当表中有大量记录时,若要对表进行查询,第一种搜索信息方式是全表搜索,是将所有记录一一取出,和查询条件进行一一对比,然后返回满足条件的记录,这样做会消耗大量时间,并造成大量磁盘I/O操作;
2
3为了加快查询,就是在表中建立索引,然后在索引中找到符合查询条件的索引值,最后通过保存在索引中的ROWID(相当于页码)快速找到表中对应的记录。

网上有这样一个玩笑:

合理的设计且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是一个人力三轮车。

  • 创建索引时,你需要确保该索引是应用在 SQL 查询语句的条件(一般作为 WHERE 子句的条件)。

  • 实际上,索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录。


优缺点

  • 优点

  • 大大提高了查询速度,提升用户体验

  • 缺点

  • 大大提高了查询速度,更新表时,MySQL不仅要保存数据,还要保存一下索引文件。

  • 建立索引会占用磁盘空间的索引文件。


索引的分类

普通索引

  • 基本的索引,它没有任何限制。

唯一索引

  • 索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。

    单列索引

  • 即一个索引只包含单个列,一个表可以有多个单列索引,但这不是组合索引。

    组合索引

  • 即一个索引包含多个列。


使用

查看

1SHOW INDEX FROM table_name;

创建

创建表的时候

普通单列索引
1-- 索引新建
2CREATE TABLE mytable(  
3    ID INT NOT NULL,   
4    username VARCHAR(16NOT NULL,  
5    INDEX indexName (username(length))  -- length: 指定前缀的长度,每列值的前length个字符为索引
6);  
7-- 大部分的索引前面一部分的长度就能够有很好的区分。 通过减小索引长度,这样能够减小索引文件的大小,能够加快数据的insert。

点这里知道    →   如何选出合适的索引长度????

“索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为20的索引,区分度会高达90%” --《阿里开发手册》

普通唯一索引
1-- 唯一索引新建
2CREATE TABLE mytable(  
3    ID INT NOT NULL,   
4    username VARCHAR(16NOT NULL,  
5    UNIQUE index indexName (username(12))  --在新建的时候加上 UNIQUE 关键字即可,后期增加只可以加在没有重复的列上
6); 
组合索引
1-- 组合索引新建
2CREATE TABLE mytable(  
3    ID INT NOT NULL,   
4    username VARCHAR(16NOT NULL,
5    userpass VARCHAR(16NOT NULL,
6    index indexName (username(12),userpass(12))  
7); 
组合唯一索引
1-- 唯一组合索引新建
2CREATE TABLE mytable(  
3    ID INT NOT NULL,   
4    username VARCHAR(16NOT NULL,
5    userpass VARCHAR(16NOT NULL,
6    UNIQUE index indexName (username(12),userpass(12))  
7); 

创建完成后增加

直接创建
1-- 创建普通单列索引
2CREATE INDEX indexName on mytable (col_name(10));
3-- 创建单列唯一索引
4CREATE UNIQUE INDEX indexName on mytable (col_name(10));
5-- 创建普通组合索引
6CREATE INDEX indexName on mytable (col_name_one(10),col_name_two(10));
7-- 创建组合唯一索引
8CREATE UNIQUE INDEX indexName on mytable (col_name_one(10),col_name_two(10));
通过修改表结构创建
1-- 添加一个主键,这意味着索引值必须是唯一的,且不能为NULL。
2ALTER TABLE table_name ADD PRIMARY KEY (col_name)
3-- 通过ALTER创建
4ALTER TABLE table_name ADD INDEX index_name(col_name);

删除

DROP

1DROP INDEX index_name ON table_name; 

ALTER

1ALTER TABLE table_name DROP INDEX index_name;

修改

在 [MySQL]() 中修改索引可以通过删除原索引,再根据需要创建一个同名的索引,从而实现修改索引的操作。

索引的类型

index ---- 普通索引,数据可以重复
fulltext ---- 全文索引,用来对大表的文本域(char,varchar,text)进行索引
unique ---- 唯一索引,要求所有记录都唯一
primary key ---- 主键索引,也就是在唯一索引的基础上相应的列必须为主键

索引的创建原则

  1. 尽量减少like,但不是绝对不可用,”xxxx%” 是可以用到索引的

  2. 表的主键、外键必须有索引

  3. 谁的区分度更高同值的最少),谁建索引,区分度的公式是count(distinct字段))/count(*)

  4. 单表数据太少,不适合建索引

  5. where,order by ,group by 等过滤时,后面的字段最好加上索引

  6. 如果既有单字段索引,又有这几个字段上的联合索引,一般可以删除联合索引;

  7. 联合索引的建立需要进行仔细分析;尽量考虑用单字段索引代替:

  8. 联合索引:

  • mysql 从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。

  • 例如索引是key index(a,b,c). 可以支持 a|a,b|a,b,c 3种组合进行查找,但不支持 b,c 进行查找。

  • 当最左侧字段是常量引用时,索引就十分有效。

  1. 前缀索引:

  • 有时候需要索引很长的字符列,这会让索引变得大且慢。

  • 通常可以索引开始的部分字符,这样可以大大节约索引空间,从而提高索引效率。

  • 其缺点是不能用于ORDER BY和GROUP BY操作,也不能用于覆盖索引 Covering index即当索引本身包含查询所需全部数据时,不再访问数据文件本身)。

  1. NULL会导致索引形同虚设


什么时候会索引失效——造成全表扫描

  • 使用模糊查询 % 在右边:like “ %xxx ”

  • 使用不等、不包含的时候:not in , !=,<>

  • 对列进行函数运算的情况:where md5(password) = “xxxx”

  • 有字段作条件使用 OR连接的时候:WHERE index=1 OR A=10

  • 查询存了数值的字符串类型字段(如身份证号),查询时记得不要丢掉值的引号,否则无法用到该字段相关索引,反之则没关系

一个高质量的SQL要避免不规范的写法