sql效率优化通过索引

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sql效率优化通过索引相关的知识,希望对你有一定的参考价值。

将一张数据表唯一索引中的部分字段建个非唯一索引,对于查询的效率是否会有影响。例如表test,有a,b,c,d,e,f,g共7个字段,a,b,c三个字段组成唯一索引,再将a,b建个非唯一索引,查询的效率会提高么

要看索引字段的顺序
如果a+b+c是唯一索引,那么建再a+b索引,只会减慢修改表时的效率,对查询没有帮助。
如果建的是b+c或是c,而且查询条件中也就只有b和c就有可能提高效率。
只要记得索引中字段是有顺序的,查询时的条件如果没有索引的第一个字段,则不会再使用索引。
当然,SQL使不使用索引也跟表的行大小、数据量的实际大小以及重复数据的分布情况有关系,如果sqlserver分析出来扫描全表所需的时间比使用索引还快的话,就不会再使用索引了。
参考技术A : I have a lovely bedroom.  我有一间漂亮的卧室 .There is a big bed in my room.有一个大床在我的房间. 参考技术B 1. 执行计划中明明有使用到索引,为什么执行还是这么慢?

2. 执行计划中显示扫描行数为 644,为什么 slow log 中显示 100 多万行?
a. 我们先看执行计划,选择的索引 “INDX_BIOM_ELOCK_TASK3(TASK_ID)”。结合 sql 来看,因为有 "ORDER BY TASK_ID DESC" 子句,排序通常很慢,如果使用了文件排序性能会更差,优化器选择这个索引避免了排序。
那为什么不选 possible_keys:INDX_BIOM_ELOCK_TASK 呢?原因也很简单,TASK_DATE 字段区分度太低了,走这个索引需要扫描的行数很大,而且还要进行额外的排序,优化器综合判断代价更大,所以就不选这个索引了。不过如果我们强制选择这个索引(用 force index 语法),会看到 SQL 执行速度更快少于 10s,那是因为优化器基于代价的原则并不等价于执行速度的快慢;
b. 再看执行计划中的 type:index,"index" 代表 “全索引扫描”,其实和全表扫描差不多,只是扫描的时候是按照索引次序进行而不是行,主要优点就是避免了排序,但是开销仍然非常大。
Extra:Using where 也意味着扫描完索引后还需要回表进行筛选。一般来说,得保证 type 至少达到 range 级别,最好能达到 ref。
在第 2 点中提到的“慢日志记录Rows_examined: 1161559,看起来是全表扫描”,这里更正为“全索引扫描”,扫描行数确实等于表的行数;
c. 关于执行计划中:“rows:644”,其实这个只是估算值,并不准确,我们分析慢 SQL 时判断准确的扫描行数应该以 slow log 中的 Rows_examined 为准。
4. 优化建议:添加组合索引 IDX_REL_DEVID_TASK_ID(REL_DEVID,TASK_ID)

优化过程:
TASK_DATE 字段存在索引,但是选择度很低,优化器不会走这个索引,建议后续可以删除这个索引:
select count(*),count(distinct TASK_DATE) from T_BIOMA_ELOCK_TASK;+------------+---------------------------+| count(*) | count(distinct TASK_DATE) |+------------+---------------------------+| 1161559 | 223 |+------------+---------------------------+

在这个 sql 中 REL_DEVID 字段从命名上看选择度较高,通过下面 sql 来检验确实如此:
select count(*),count(distinct REL_DEVID) from T_BIOMA_ELOCK_TASK;+----------+---------------------------+| count(*) | count(distinct REL_DEVID) |+----------+---------------------------+| 1161559 | 62235 |+----------+---------------------------+

由于有排序,所以得把 task_id 也加入到新建的索引中,REL_DEVID,task_id 组合选择度 100%:
select count(*),count(distinct REL_DEVID,task_id) from T_BIOMA_ELOCK_TASK;+----------+-----------------------------------+| count(*) | count(distinct REL_DEVID,task_id) |+----------+-----------------------------------+| 1161559 | 1161559 |+----------+-----------------------------------+

在测试环境添加 REL_DEVID,TASK_ID 组合索引,测试 sql 性能:alter table T_BIOMA_ELOCK_TASK add index idx_REL_DEVID_TASK_ID(REL_DEVID,TASK_ID);
添加索引后执行计划:
这里还要注意一点“隐式转换”:REL_DEVID 字段数据类型为 varchar,需要在 sql 中加引号:AND T.REL_DEVID = 000000025xxx >> AND T.REL_DEVID = '000000025xxx'

执行时间从 10s+ 降到 毫秒级别:
1 row in set (0.00 sec)
结论
一个典型的 order by 查询的优化,添加更合适的索引可以避免性能问题:执行计划使用索引并不意味着就能执行快。

sql优化---- 索引

---
title: 不懂SQL优化?那你就OUT了(二) 

-- 索引(一)

date: 2018-10-27
categories: 数据库优化
---

要想让一个较慢的select ... where语句执行效率更快,我们应首先检查是否能增加一个索引。不同表之间的引用通常通过索引来完成。你可以使用explain语句(上一篇已介绍)来确定select语句是否使用索引,使用了哪些索引。

索引

索引是一种特殊的文件,它们包含着对数据表里所有记录的引用指针。

它是对数据库表中一列或多列的值进行排序的一种结构

简单理解就是:

数据库索引好比是一本书前面的目录,能够加快数据库的查询速度.

数据库索引就是为了提高表的搜索效率而对某些字段中的值建立的目录。

为什么要使用索引

创建索引可以大大提高系统的性能

1. 通过创建唯一索引,可以保证数据库表中每一行数据的唯一性。

2. 可以大大加快数据的检索速度,这也是创建索引的最主要的原因。

3. 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。

4. 显著减少查询中分组和排序的时间。

5. 通过使用索引,可以在查询的过程中,使用优化器,提高系统的性能

索引的分类

索引的类型大体上可分为:

1. 普通索引 
2. 唯一索引 
3. 主键索引
4. 全文索引。

普通索引

普通索引有分为:单列索引 和 多列索引

 1. 单列索引:就是一个索引只包含单个列,一个表可以有多个单列索引。

 2. 多列索引:也称组合索引,即一个索引包含多个列。

创建普通索引的语法

查看某张表的索引:show index from 表名;

创建普通索引: 

  1.  create index 索引名 on 表名(表中加索引的列名)
  2.  alter table 表名 add index  索引名 (表中加索引的列) 
  3.  create table 表名(
         列名 列的数据类型 列的约束,
          index 索引名(表中加索引的列)
      )

创建多列索引:

  1.  create index 索引名 on 表名(表中加索引的列1,表中加索引的列2,...)
  2.  alter table 表名 add index  索引名 (表中加索引的列1,表中加索引的列2,...) 
  3.  create table 表名(
          列名 列的数据类型 列的约束,
          index 索引名(表中加索引的列1,表中加索引的列2,...)
      )

删除某张表的索引:

 drop index 索引名 ON 表名;

唯一索引

它与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。

如果是组合索引,则列值的组合必须唯一

创建唯一索引语法

与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。

如果是组合索引,则列值的组合必须唯一.

语法:

  1.  create unique index 索引名 on 表名(表中加索引的列)
  2.  alter table 表名 add  unique index  索引名 (表中加索引的列) 
  3.  create table 表名(
              列名 列的数据类型 列的约束,
              unique index 索引名(表中加索引的列)
          )

主键索引

它是一种特殊的唯一索引,不允许有空值。

创建主键索引的语法

语法:

  1.  alter table 表名 add  primary key(列名)
  2.  create table 表名(
          列名1 列的数据类型 列的约束(primary key),
          列名2 列的数据类型 列的约束
      )

全文索引

现在的互联网上,很多网站都提供了全文搜索(全文检索)功能,浏览者可以通过输入关键字或者是短语来搜索特定的资料。

通常的做法是通过 select 查询的 like 语句来进行搜索,这一办法存在搜索不够精确、以及效率非常低下的缺点。

mysql 提供了一个全文索引功能,也就是把字段设置上fullText索引属性,然后通过select的match against语句进行查找。

mysql 支持全文索引和搜索功能,但是 fullText 索引仅能用于 myisam 引擎(数据库引擎以后在介绍)的表。

myisam 引擎支持全文检索(full text index),查询效率高。但是有局限,不支持事务和外键。

创建全文索引的语法

语法:

  1.Create  fulltext index 索引名  on  表名(表中加索引的列)
  2.alter table  表名  add fulltext index 索引名(表中加索引的列)
  3. create table 表名(
        列名 列的数据类型 列的约束,
        fulltext 索引名(表中加索引的列)
        )

案列

首先创建一个测试表: t_studentInfo

  create table t_studentInfo(
     -- 学生编号
     studentId int primary key auto_increment,  -- 创建了唯一索引(主键)
     -- 学生姓名
     studentName varchar(20)  
     -- 学生年龄 
     studentAge int,
     -- 家庭住址
     studentAddress varchar(255)
  )engine=myisam,default charset=utf8

使用 存储过程添加 1000万条数据

  DELIMITER $  
  
  CREATE PROCEDURE pro_datas()
  
  BEGIN
  
    DECLARE  num INT;
    
    DECLARE  age INT;
    
    DECLARE result INT;
    
    DECLARE address VARCHAR(25);
    
    SET num:=1;
    
    WHILE num <= 10000000 DO   
    
        SET age:= 18+CEIL(RAND()*10);
         
        SET result:=CEIL(RAND()*100);
        
        IF result < 25 THEN
        
        SET address:="成都市";
        
        ELSEIF result<50 THEN
        
        SET address:="绵阳市";
        
        ELSEIF result<75 THEN
        
        SET  address:="昆明市";
        
        ELSE 
        
        SET  address:="贵阳市" ;
        
        END IF; 
    
        INSERT INTO t_studentInfo(studentName,studentAge,studentAddress) VALUES(CONCAT(\'学生\',num),age,address);   
        
        SET num=num+1;  
       
    END WHILE;  
  
  END $

在执行

 CALL pro_datas();  

执行时间:

 

添加1000万条(在myisam引擎)数据花费了大约6分钟。

执行sql :

 select * from t_studentInfo where studentName="学生1024"

执行结果:

 

使用explain查看sql语句执行计划

 

从执行计划中可以看到,该查询未使用索引,而是进行了全表扫描(type=all),并且扫描了1000万条数据,效率低下。

现在为表的学生姓名列添加索引

 

我们看到添加时间大约4分钟,建索引的过程会全表扫描,逐条建索引,当然慢了。

现在再次执行

 select * from t_studentInfo where studentName="学生1024"

执行时间:

 

发现查询效率快了很多。

查看添加索引后的执行计划

 

可以从执行计划中看到,此查询使用索引(type=ref),使用了 idx_studentName 索引,并且只扫描了一条数据,效率甚高。

总结

索引的主要作用就是: 加快数据库的查询效率。






以上是关于sql效率优化通过索引的主要内容,如果未能解决你的问题,请参考以下文章

MySQL(十六)索引优化:索引失效的情况分析

sql优化---- 索引

Mysql explain

Mysql调优-4通过索引进行优化

sql 优化之8个尽量

SQL查询语句优化的实用方法