mysql-索引

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

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

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

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

上面都在说使用索引的好处,但过多的使用索引将会造成滥用。因此索引也会有它的缺点:虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。

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

二、索引类型

Mysql目前主要有以下几种索引类型:FULLTEXT,HASH,BTREE,RTREE。
1. FULLTEXT

即为全文索引,目前只有MyISAM引擎支持。其可以在CREATE TABLE ,ALTER TABLE ,CREATE INDEX 使用,不过目前只有 CHAR、VARCHAR ,TEXT 列上可以创建全文索引。

全文索引并不是和MyISAM一起诞生的,它的出现是为了解决WHERE name LIKE “%word%"这类针对文本的模糊查询效率较低的问题。
2. HASH

由于HASH的唯一(几乎100%的唯一)及类似键值对的形式,很适合作为索引。

HASH索引可以一次定位,不需要像树形索引那样逐层查找,因此具有极高的效率。但是,这种高效是有条件的,即只在“=”和“in”条件下高效,对于范围查询、排序及组合索引仍然效率不高。
3. BTREE

BTREE索引就是一种将索引值按一定的算法,存入一个树形的数据结构中(二叉树),每次查询都是从树的入口root开始,依次遍历node,获取leaf。这是MySQL里默认和最常用的索引类型。
 

三、索引种类

    普通索引:仅加速查询

    唯一索引:加速查询 + 列值唯一(可以有null)

    主键索引:加速查询 + 列值唯一(不可以有null)+ 表中只有一个

    组合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并

    全文索引:对文本的内容进行分词,进行搜索

ps.

索引合并,使用多个单列索引组合搜索
覆盖索引,select的数据列只用从索引中就能够取得,不必读取数据行,换句话说查询列要被所建的索引覆盖
四、操作索引
1. 创建索引

1
    
--创建普通索引CREATE INDEX index_name ON table_name(col_name);--创建唯一索引CREATE UNIQUE INDEX index_name ON table_name(col_name);--创建普通组合索引CREATE INDEX index_name ON table_name(col_name_1,col_name_2);--创建唯一组合索引CREATE UNIQUE INDEX index_name ON table_name(col_name_1,col_name_2);

2. 通过修改表结构创建索引

1
    
ALTER TABLE table_name ADD INDEX index_name(col_name);

3. 创建表时直接指定索引

1
2
3
    
CREATE TABLE table_name (
    ID INT NOT NULL,col_name VARCHAR (16) NOT NULL,INDEX index_name (col_name)
);

4. 删除索引

1
    
--直接删除索引DROP INDEX index_name ON table_name;--修改表结构删除索引ALTER TABLE table_name DROP INDEX index_name;

5. 其它相关命令

1
2
3
4
5
6
7
8
9
10
    
- 查看表结构
    desc table_name;
 - 查看生成表的SQL
    show create table table_name;
 - 查看索引
    show index from  table_name;
 - 查看执行时间
    set profiling = 1;
    SQL...
    show profiles;

五、创建索引的时机

到这里我们已经学会了建立索引,那么我们需要在什么情况下建立索引呢?一般来说,在WHERE和JOIN中出现的列需要建立索引,但也不完全如此,因为MySQL只对<,<=,=,>,>=,BETWEEN,IN,以及某些时候的LIKE才会使用索引。例如:

1
    
SELECT t.Name  FROM mytable_t LEFT JOIN mytable_m ON t.Name=m.username WHERE m.age=20 AND m.city='郑州' ;

此时就需要对city和age建立索引,由于mytable_m表的userame也出现在了JOIN子句中,也有对它建立索引的必要。

刚才提到只有某些时候的LIKE才需建立索引。因为在以通配符%和_开头作查询时,MySQL不会使用索引。
六、命中索引

数据库表中添加索引后确实会让查询速度起飞,但前提必须是正确的使用索引来查询,如果以错误的方式使用,则即使建立索引也会不奏效。
即使建立索引,索引也不会生效:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    
- like '%xx'    select * from tb1 where name like '%cn';- 使用函数
    select * from tb1 where reverse(name) = 'wupeiqi';- or    select * from tb1 where nid = 1 or email = 'seven@live.com';
    特别的:当or条件中有未建立索引的列才失效,以下会走索引
            select * from tb1 where nid = 1 or name = 'seven';
            select * from tb1 where nid = 1 or email = 'seven@live.com' and name = 'alex'- 类型不一致
    如果列是字符串类型,传入条件是必须用引号引起来,不然...
    select * from tb1 where name = 999;- !=    select * from tb1 where name != 'alex'    特别的:如果是主键,则还是会走索引
        select * from tb1 where nid != 123- >    select * from tb1 where name > 'alex'    特别的:如果是主键或索引是整数类型,则还是会走索引
        select * from tb1 where nid > 123        select * from tb1 where num > 123- order by    select email from tb1 order by name desc;
    当根据索引排序时候,选择的映射如果不是索引,则不走索引
    特别的:如果对主键排序,则还是走索引:
        select * from tb1 order by nid desc;
 - 组合索引最左前缀
    如果组合索引为:(name,email)
    name and email       -- 使用索引    name                 -- 使用索引    email                -- 不使用索引

七、其它注意事项

1
    
- 避免使用select *- count(1)或count(列) 代替 count(*)- 创建表时尽量时 char 代替 varchar- 表的字段顺序固定长度的字段优先- 组合索引代替多个单列索引(经常使用多个条件查询时)- 尽量使用短索引- 使用连接(JOIN)来代替子查询(Sub-Queries)- 连表时注意条件类型需一致- 索引散列值(重复多)不适合建索引,例:性别不适合

八、LIMIT分页

若需求是每页显示10条数据,如何建立分页?

我们可以先使用LIMIT尝试:

1
    
--第一页SELECT * FROM table_name LIMIT 0,10;--第二页SELECT * FROM table_name LIMIT 10,10;--第三页SELECT * FROM table_name LIMIT 20,10;

但是这样做有如下弊端:

    每一条select语句都会从1遍历至当前位置,若跳转到第100页,则会遍历1000条记录

    若记录的id不连续,则会出错

改善:

若已知每页的max_id和min_id,则可以通过主键索引来快速定位:

1
    
--下一页SELECT * FROM table_name WHERE id in (SELECT id FROM table_name WHERE id > max_id LIMIT 10);--上一页SELECT * FROM table_name WHERE id in (SELECT id FROM table_name WHERE id < min_id ORDER BY id DESC LIMIT 10);--当前页之后的某一页SELECT * FROM table_name WHERE id in (SELECT id FROM (SELECT id FROM (SELECT id FROM table_name WHERE id < min_id ORDER BY id desc LIMIT (页数差*10)) AS N ORDER BY N.id ASC LIMIT 10) AS P ORDER BY P.id ASC);--当前页之前的某一页SELECT * FROM table_name WHERE id in (SELECT id FROM (SELECT id FROM (SELECT id FROM table_name WHERE id > max_id LIMIT (页数差*10)) AS N ORDER BY N.id DESC LIMIT 10) AS P) ORDER BY id ASC;

九、执行计划

explain + 查询SQL - 用于显示SQL执行信息参数,根据参考信息可以进行SQL优化

1
    
mysql> explain select * from tb2;+----+-------------+-------+------+---------------+------+---------+------+------+-------+| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |+----+-------------+-------+------+---------------+------+---------+------+------+-------+|  1 | SIMPLE      | tb2   | ALL  | NULL          | NULL | NULL    | NULL |    2 | NULL  |+----+-------------+-------+------+---------------+------+---------+------+------+-------+1 row in set (0.00 sec)

1
2

    
id查询顺序标识
            如:mysql> explain select * from (select nid,name from tb1 where nid < 10) as B;+----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+| id | select_type | table      | type  | possible_keys | key     | key_len | ref  | rows | Extra       |+----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+|  1 | PRIMARY     | <derived2> | ALL   | NULL          | NULL    | NULL    | NULL |    9 | NULL        ||  2 | DERIVED     | tb1        | range | PRIMARY       | PRIMARY | 8       | NULL |    9 | Using where |+----+-------------+------------+-------+---------------+---------+---------+------+------+-------------+        特别的:如果使用union连接其值可能为null
 
 
    select_type
        查询类型
            SIMPLE          简单查询PRIMARY         最外层查询
            SUBQUERY        映射为子查询
            DERIVED         子查询UNION           联合UNION RESULT    使用联合的结果
            ...table正在访问的表名
 
 
    type
        查询时的访问方式,性能:all < index < range < index_merge < ref_or_null < ref < eq_ref < system/constALL             全表扫描,对于数据表从头到尾找一遍select * from tb1;
                            特别的:如果有limit限制,则找到之后就不再继续向下扫描                                   select * from tb1 where email = 'seven@live.com'   select * from tb1 where email = 'seven@live.com' limit 1;
                                   虽然上述两个语句都会进行全表扫描,第二句使用了limit,则找到一个后就不再继续扫描。INDEX           全索引扫描,对索引从头到尾找一遍select nid from tb1;
 
            RANGE          对索引列进行范围查找select *  from tb1 where name < 'alex';
                            PS:between andin>   >=  <   <=  操作
                                注意:!= 和 > 符号
 
 
            INDEX_MERGE     合并索引,使用多个单列索引搜索select *  from tb1 where name = 'alex' or nid in (11,22,33);
 
            REF             根据索引查找一个或多个值select *  from tb1 where name = 'seven';
 
            EQ_REF          连接时使用primary key 或 unique类型select tb2.nid,tb1.name from tb2 left join tb1 on tb2.nid = tb1.nid;
 
 
 
            CONST           常量
                            表最多有一个匹配行,因为仅有一行,在这行的列值可被优化器剩余部分认为是常数,const表很快,因为它们只读取一次。select nid from tb1 where nid = 2 ;
 
            SYSTEM          系统
                            表仅有一行(=系统表)。这是const联接类型的一个特例。select * from (select nid from tb1 where nid = 1) as A;
    possible_keys
        可能使用的索引key真实使用的
 
    key_len
        MySQL中使用索引字节长度
 
    rows
        mysql估计为了找到所需的行而要读取的行数 ------ 只是预估值extra
        该列包含MySQL解决查询的详细信息
        “Using index”
            此值表示mysql将使用覆盖索引,以避免访问表。不要把覆盖索引和index访问类型弄混了。
        “Using where”
            这意味着mysql服务器将在存储引擎检索行后再进行过滤,许多where条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带where子句的查询都会显示“Using where”。有时“Using where”的出现就是一个暗示:查询可受益于不同的索引。
        “Using temporary”
            这意味着mysql在对查询结果排序时会使用一个临时表。
        “Using filesort”
            这意味着mysql会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。mysql有两种文件排序算法,这两种排序方式都可以在内存或者磁盘上完成,explain不会告诉你mysql将使用哪一种文件排序,也不会告诉你排序会在内存里还是磁盘上完成。
        “Range checked for each record(index map: N)”
            这个意味着没有好用的索引,新的索引将在联接的每一行上重新估算,N是显示在possible_keys列中索引的位图,并且是冗余的。

上表详解

十、慢查询日志

MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中。long_query_time的默认值为10,意思是运行10S以上的语句。默认情况下,MySQLl数据库并不启动慢查询日志,需要我们手动来设置这个参数,当然,如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定的性能影响。慢查询日志支持将日志记录写入文件,也支持将日志记录写入数据库表。
1. 查看慢日志参数:

1
    
--查询配置命令show variables like '%query%';--当前配置参数binlog_rows_query_log_events    OFFft_query_expansion_limit    20have_query_cache    YES--时间限制,超过此时间,则记录long_query_time    10.000000query_alloc_block_size    8192query_cache_limit    1048576query_cache_min_res_unit    4096query_cache_size    1048576query_cache_type    OFFquery_cache_wlock_invalidate    OFFquery_prealloc_size    8192--是否开启慢日志记录slow_query_log    OFF--日志文件slow_query_log_file    D:\Program Files (x86)\mysql-5.7.18-winx64\data\Jack-slow.log--

2. 修改当前配置

1
    
set global 变量名 = 值;--例如,修改时间限制为20slong_query_time = 20;

ps.也可以直接打开慢日志配置文件进行修改,但必须重启服务才能生效
3. 查看MySQL慢日志

1
    
mysqldumpslow -s at -a  /usr/local/var/mysql/MacBook-Pro-3-slow.log

1
2
3
4
5
6
7
8
9
10
11
12
13
    
"""--verbose    版本--debug      调试--help       帮助 -v           版本-d           调试模式-s ORDER     排序方式
             what to sort by (al, at, ar, c, l, r, t), 'at' is default              al: average lock time
              ar: average rows sent
              at: average query time
               c: count               l: lock time
               r: rows sent
               t: query time-r           反转顺序,默认文件倒序拍。reverse the sort order (largest last instead of first)-t NUM       显示前N条just show the top n queries-a           不要将SQL中数字转换成N,字符串转换成S。don't abstract all numbers to N and strings to 'S'-n NUM       abstract numbers with at least n digits within names
-g PATTERN   正则匹配;grep: only consider stmts that include this string
-h HOSTNAME  mysql机器名或者IP;hostname of db server for *-slow.log filename (can be wildcard),
             default is '*', i.e. match all
-i NAME      name of server instance (if using mysql.server startup script)
-l           总时间中不减去锁定时间;don't subtract lock time from total time
 

 

1 初识索引  

  索引在MySQL中也叫是一种“键”,是存储引擎用于快速找到记录的一种数据结构 —— 排好序的快速查找数据结构

  数据本身之外,数据库还维护着一个满足特定查找算法的数据结构,这些数据结构以某种方式指向数据,这样就可以在这些数据结构的基础上实现高级查找算法,这种数据结构就是索引。

  索引对于良好的性能非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发重要。索引优化应该是对查询性能优化最有效的手段了。索引能够轻易将查询性能提高好几个数量级。

  索引相当于字典的音序表,如果要查某个字,如果不使用音序表,则需要从几百页中逐页去查。

2 索引的原理

  索引的目的在于提高查询效率,与我们查阅图书所用的目录是一个道理:先定位到章,然后定位到该章下的一个小节,然后找到页数。相似的例子还有:查字典,查火车车次,飞机航班等

  索引的原理:通过不断地缩小想要获取数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,也就是说,有了这种索引机制,我们可以总是用同一种查找方式来锁定数据。

  索引的本质:实际上是一张表,该表保存了主键和索引字段,并指向实体表的记录,所以索引列也是要占用空间的一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往以文件形式存储在硬盘上。

优势

  (1)类似大学图书馆建书目索引,提高数据检索效率,降低数据库的IO成本

  (2)通过索引列对数据进行排序,降低数据排序成本,降低了CPU的消耗

劣势

  (1)虽然索引大大提高了查询速度,同时却会降低更新表(增删改)的速度。因为更新表时,MySQL不仅要不存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息。

  (2)索引只是提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立优秀的索引,或优化查询语句(需要不断调整优化)。

3 MySQL索引

  3.1 索引分类

复制代码

#### 常用索引 ####

#1、单值索引:即一个索引只包含单个列,一个表可以有多个单列索引

#2、唯一索引:索引列的值必须唯一,但允许有空值
    -主键索引PRIMARY KEY:加速查找+约束(不为空、不能重复)
    -唯一索引UNIQUE:加速查找+约束(不能重复)

#3、联合索引:即一个索引包含多个列
    -PRIMARY KEY(id,name):联合主键索引
    -UNIQUE(id,name):联合唯一索引
    -INDEX(id,name):联合普通索引

复制代码

#4、组合索引(最左前缀匹配)

#5、覆盖索引

  3.2  基本语法

(1)建表时添加索引

  建表同时建立单索引

CREATE TABLE t_user1(id INT ,
userName VARCHAR(20),
PASSWORD VARCHAR(20),
INDEX (userName) #关键字INDEX
);

  建表同时建立唯一索引(可以是单或多)

CREATE TABLE t_user2(id INT ,
userName VARCHAR(20),
PASSWORD VARCHAR(20),
UNIQUE INDEX index_userName(userName) #关键字UNIQUE和INDEX
);

  建表同时建立联合索引

CREATE TABLE t_user3(id INT ,
userName VARCHAR(20),
PASSWORD VARCHAR(20),
INDEX index_userName_password(userName,PASSWORD)
);

(2)给已存在表添加索引

复制代码

-- 单列索引
CREATE INDEX index_userName ON t_user(userName);
-- 唯一索引
CREATE UNIQUE INDEX index_userName ON t_user(userName);
-- 联合索引
CREATE INDEX index_userName_password ON t_user(userName,PASSWORD);

复制代码

(3)删除索引

DROP INDEX index_userName ON t_user;
DROP INDEX index_userName_password ON t_user;

  3.3  MySQL常见瓶颈

    •  CPU:CPU在饱和的时候一般发生在数据装入在内存或从磁盘上读取数据时候
    •  IO:磁盘I/O瓶颈发生在装入数据远大于内存容量时
    •  服务器硬件的性能瓶颈:top,free,iostat和vmstat来查看系统的性能状态

4 正确使用索引

4.1 哪些情况需要创建索引

  • 主键自动建立唯一索引
  • 频繁作为查询的条件的字段应该创建索引
  • 查询中与其他表关联的字段,外键关系建立索引
  • 单间/组合索引的选择问题,who?(在高并发下倾向创建组合索引)
  • 查询中排序的字段,排序字段若通过索引去访问将大大提高排序的速度
  • 查询中统计或者分组字段
  • 哪些字段可以建索引? 一般都where、order by 或者 group by 后面的字段。

4.2 哪些情况不要创建索引

  • Where条件里用不到的字段不创建索引
  • 表记录太少
  • 修改性能(频繁更新的字段)远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的,因为每次更新不单单是更新了记录还会更新索引,加重IO负担)
  • 数据重复且分布平均的表字段,因此应该只为经常查询和经常排序的数据列建立索引。注意,如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。
  • 对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。
  • 对于那些在查询中很少使用或者参考的列不应该创建索引

and/or工作原理

4.3 mysql索引失效case及优化:

复制代码

1,全值匹配我最爱  
-- 【optimizer会对查询顺序自动进行优化调整】

2,最佳左前缀法则  【带头大哥不能死,中间兄弟不能断】
--   如果索引了多例,要遵守最左前缀法则。指的是查询从索引的最左前列开始并且不跳过索引中的列。

3,索引列少计算     
-- 不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描

4,范围之后全失效  
-- 存储引擎不能使用索引中范围条件右边的列

5,覆盖索引代替select * 
-- 尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少select*

6,少用 is null或is not null
-- is null,is not null 也无法使用索引

7,少用!=或<>
-- mysql在使用不等于(!=或者<>)的时候无法使用索引会导致全表扫描

8,少用or
-- 少用or,用它连接时会索引失效【查看上边and/or 工作原理】

9,like %放右边
-- 【like以通配符开头('%abc...')mysql索引失效会变成全表扫描操作】
-- 【放左边是all,连带他本身全失效】
-- 【可用覆盖索引(varchar为380失效)或主键索引】

10,varchar类型要加''单引号,切记!!!
-- 【不加会计算-自动转型】
-- 【导致行锁升级为表锁】

11,使用连接(JOIN)来代替子查询(Sub-Queries)

12,使用count(1)

复制代码

5 查询优化神器-explain

5.1 是什么 —— 查看执行计划

  使用EXPLAIN关键字可以模拟优化器执行SQL语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是结构的性能瓶颈

  优化语句基本上都是在优化rows。具体用法和字段含义可以参考官网 explain-output

5.2 能干嘛

  • 表的读取顺序
  • 数据读取操作的操作类型
  • 哪些索引可以使用
  • 哪些索引被实际使用
  • 表之间的引用
  • 每张表有多少行被优化器查询
  • 索引长度

5.3  执行计划包含的信息

Id

Select_type

Table

Type

Possible_keys

Key

Key_len

Ref

Rows

Extra

【详解】

复制代码

【1】id :select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序
-- id相同,执行顺序由上至下
-- id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
-- id相同不同,同时存在

【2】select_type:查询的类型,主要用于区别普通查询、联合查询、子查询等的复杂查询
-- SIMPLE:简单的select查询,查询中不包含子查询或者UNION
-- PRIMARY:查询中若包含任何复杂的子部分,最外层查询则被标记为
-- SUBQUERY:在SELECT或者WHERE列表中包含了子查询
-- DERIVED:在FROM列表中包含的子查询被标记为DERIVED(衍生)
MySQL会递归执行这些子查询,把结果放在临时表里。
-- UNION:若第二个SELECT出现在UNION之后,则被标记为UNION;
若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED
-- UNION RESULT:从UNION表获取结果的SELECT

【3】table:显示这一行的数据是关于哪张表的

【4】type:显示查询使用了何种类型,从最好到最差依次是:-- system>const>eq_ref>ref>range>index>ALL
    -- system:表只有一行记录(等于系统表),这是const类型的特例,平时不会出现,这个也可以忽略不计
    -- const:表示通过索引一次就找到了,const用于比较primary key或者unique索引。因为只匹配一行数据,所以很快。如将主键至于where列表中,MySQL就能将该查询转换为一个常量
    -- eq_ref:唯一性索引,对于每个索引键,表中只有一条记录与之匹配,常见于主键或唯一索引扫描
    -- ref:非唯一索引扫描,返回匹配某个单独值的所有行。
        本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体
    -- range:只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引
       一般就是在你的where语句中出现了between、<、>、in等的查询这种范围扫描索引扫描比全表扫描要好,因为他只需要开始索引的某一点,而结束语另一点,不用扫描全部索引。
    -- index:Full Index Scan,index与ALL区别为index类型只遍历索引树。
        这通常比ALL快,因为索引文件通常比数据文件小。(也就是说虽然all和index都是读全表,但index是从索引中读取的,而all是从硬盘中读的)
    -- all:FullTable Scan,将遍历全表以找到匹配的行

【5】possible_keys:显示可能应用在这张表中的索引,一个或多个。
--  查询涉及的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用

【6】key:实际使用的索引。如果为null则没有使用索引
-- 查询中若使用了覆盖索引,则索引和查询的select字段重叠(USING index)

【7】key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。在不损失精确性的情况下,长度越短越好
-- key_len显示的值为索引最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的

【8】ref:显示索引那一列被使用了,如果可能的话,是一个常数。那些列或常量被用于查找索引列上的值

【9】rows:根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数

【10】Extra:包含不适合在其他列中显示但十分重要的额外信息
-- Using filesort(不好):说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。MySQL中无法利用索引完成排序操作成为“文件排序”

-- Using temporary:使用了临时表保存中间结果,MySQL在对查询结果排序时使用临时表。常见于排序order by 和分组查询 group by

-- Using where:表明使用了where过滤

-- USING index:表示相应的select操作中使用了覆盖索引(Coveing Index),避免访问了表的数据行,效率不错!
    -- 如果同时出现using where,表明索引被用来执行索引键值的查找;
    -- 如果没有同时出现using where,表面索引用来读取数据而非执行查找动作。     

复制代码

【type类型说明】:

  从最好到最差依次是:system>const>eq_ref>ref>range>index>ALL

  一般来说,得保证查询只是达到range级别,最好达到ref

6 慢查询优化的基本步骤

复制代码

# 0.先运行看看是否真的很慢,注意设置SQL_NO_CACHE
# 1.where条件单表查,锁定最小返回记录表。这句话的意思是把查询语句的where都应用到表中返回的记录数最小的表开始查起,单表每个字段分别查询,看哪个字段的区分度最高
# 2.explain查看执行计划,是否与1预期一致(从锁定记录较少的表开始查询)
# 3.order by limit 形式的sql语句让排序的表优先查
# 4.了解业务方使用场景
# 5.加索引时参照建索引的几大原则
# 6.观察结果,不符合预期继续从0分析

复制代码

7  MySQL锁机制

7.1  锁的分类

  (1)从数据操作的类型(读、写)分

  • 读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响
  • 写锁(排它锁):当前写操作没有完成前,它会阻断其他写锁和读锁。
  • 悲观锁:
    •  总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。
    • 传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。
  • 乐观锁:
    •  总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。
    • 乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。

  (2)从对数据操作的颗粒度

  • 表锁
  • 行锁

7.2  表锁(MyISAM)—— 偏读

 特点:偏向MyISAM存储引擎,开销小,加锁快,无死锁,锁定粒度大,发生锁冲突的概率最高,并发最低

7.3  行锁(InnoDB)—— 偏写

特点:偏向InnoDB存储引擎,开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

-- InnoDB与MyISAM的最大不同有两点:
一是支持事务(TRANSACTION);
二是采用了行级锁

7.4  页锁(了解即可)

  开销和加锁时间界于表锁和行锁之间:会出现死锁;

       锁定粒度界于表锁和行锁之间,并发度一般。

7.5 优化建议

  • 尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁
  • 合理设计索引,尽量缩小锁的范围
  • 尽可能较少检索条件,避免间隙锁
  • 尽量控制事务大小,减少锁定资源量和时间长度
  • 尽可能低级别事务隔离

8 慢查询日志

  查看是否开启及如何开启:

-- 默认:
SHOW VARIABLES LIKE '%slow_query_log%'

-- 开启:
set global slow_query_log = 1

复制代码

# 慢日志
  - 执行时间 > 10
  - 未命中索引
  - 日志文件路径
            
        配置:
            - 内存
                show variables like '%query%';
                show variables like '%queries%';
                set global 变量名 = 值
            - 配置文件
                mysqld --defaults-file='E:\wupeiqi\mysql-5.7.16-winx64\mysql-5.7.16-winx64\my-default.ini'
                
                my.conf内容:
                    slow_query_log = ON
                    slow_query_log_file = D:/....
                    
# 注意:修改配置文件之后,需要重启服务

复制代码

MySQL日志管理

9 日志分析工具

9.1 mysqldumpshow

  查看mysqldumpshow的帮助信息

复制代码

s:是表示按何种方式排序
c:访问次数
l:锁定时间
r:返回记录
t:查询时间
al:平均锁定时间
ar:平均返回记录数
at:平均查询时间
t:即为返回前面多少条的数据
g:后边搭配一个正则匹配模式,大小写不敏感的

复制代码

9.2 Show profiles

  (1)是什么

    是mysql提供可以用来分析当前会话中语句执行的资源消耗情况。可以用于SQL的调优测量。

    官网:http://dev.mysql.com/doc/refman/5.5/en/show-profile.html

    默认情况下,参数处于关闭状态,并保存最近15次的运行结果

  (2)分析步骤

复制代码

1.是否支持,看看当前的SQL版本是否支持
2.开启功能,默认是关闭,使用前需要开启
3.运行SQL
-- select * from emp group by id%10 limit 150000
-- select * from emp group by id%20 order by 5
4.查看结果,show profiles;
5.诊断SQL,show profile cpu,block io for query 上一步前面的问题SQL 数字号码;
6.日常开发需要注意的结论
-- converting HEAP to MyISAM 查询结果太大,内存都不够用了往磁盘上搬了。
-- Creating tmp table 创建临时表
    -- 拷贝数据到临时表
    --  用完再删除
-- Copying to tmp table on disk 把内存中临时表复制到磁盘,危险!!!
-- locked

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值