索引建立

索引建立

  1. 单表
    • create table if not exists `artcle`(
          id INT(10) unsigned not null primary key auto_increment,
          author_id INT(10) unsigned not null ,
          category_id INT(10) unsigned not null,
          views INT(10) unsigned not null ,
          comments INT(10) unsigned not null ,
          title varbinary(255) not null ,
          content TEXT not null
      );
      
      
      desc artcle;
      
      
      insert into artcle(author_id, category_id, views, comments, title, content) values
      (1,1,1,1,'1','1');
      (2,2,2,2,'2','2')
      (1,1,3,3,'3','3');
      
      
      select * from artcle;
      
      explain select id ,author_id from artcle where category_id = 1 and comments>1 order by views desc limit 1;

      +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
      | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
      | 1 |      SIMPLE |  artcle |    NULL |    ALL |      NULL |     NULL |   NULL | NULL  | 4 |      25.00 | Using where; Using filesort |
      +----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
      1 row in set, 1 warning (0.00 sec)

      type是all 而且extra 为Using filesort,要优化
      select id ,author_id from artcle where category_id = 1 and comments>1 order by views desc limit 1;
      show index from artcle;
      开始优化
      1,新建索引2.删除索引
      建立 ccv 联合主键
      create index idx_artcle_ccv on artcle(category_id,comments,views);

      show index from artcle;
      explain select id ,author_id from artcle where category_id = 1 and comments>1 order by views desc limit 1;

      explain select id ,author_id from artcle where category_id = 1 and comments>1 order by views desc limit 1; 索引尽量用等于 = 
      +----+-------------+--------+------------+-------+----------------+----------------+---------+------+------+----------+---------------------------------------+
      | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      +----+-------------+--------+------------+-------+----------------+----------------+---------+------+------+----------+---------------------------------------+
      | 1 | SIMPLE | artcle | NULL | range | idx_artcle_ccv | idx_artcle_ccv | 8 | NULL | 1 | 100.00 | Using index condition; Using filesort |
      +----+-------------+--------+------------+-------+----------------+----------------+---------+------+------+----------+---------------------------------------+
      1 row in set, 1 warning (0.00 sec)

      从结果看,联合索引运用到了,但是extra还是Using filesort 
      1.建立联合索引ccv之后因为按照Btree索引工作原理,先排序category_id,如果遇到相同的category_id则再排序comments,如果遇到相同comments
      再排序views
      2.当comments字段在联合索引里处于中间位置时,因为comments>1条件是一个范围值,range ,mysql无法利用索引对后面的views部分进行检索
      ,即range类型查询字段后面的索引无效。


      建立 cv联合索引
      create index idx_artcle_cv on artcle(category_id,views);
      再次explain
      explain select id ,author_id from artcle where category_id = 1 and comments>1 order by views desc limit 1;

      mysql> explain select id ,author_id from artcle where category_id = 1 and comments>1 order by views desc limit 1;
      +----+-------------+--------+------------+------+---------------+---------------+---------+-------+------+----------+----------------------------------+
      | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      +----+-------------+--------+------------+------+---------------+---------------+---------+-------+------+----------+----------------------------------+
      | 1 | SIMPLE | artcle | NULL | ref | idx_artcle_cv | idx_artcle_cv | 4 | const | 2 | 33.33 | Using where; Backward index scan |
      +----+-------------+--------+------------+------+---------------+---------------+---------+-------+------+----------+----------------------------------+
      1 row in set, 1 warning (0.00 sec)


      发现type变成了ref 实际运用索引被使用,extra里面Using
      filesort 消失 出现了Backward index scan 问题解决
      
      

       

  2. 两表
    建表语句为
    create table if not exists `class`(
    id int(10) unsigned not null auto_increment,
    card int(10) unsigned not null,
    primary key(id)
    );

    create table if not exists `book`(
    bookid int(10) unsigned not null auto_increment,
    card int(10) unsigned not null ,
    primary key (bookid)
    );

    show tables;

    insert into class(card) values(FLOOR(1+(RAND()*20)));

    delimiter $
    create procedure insertt(in count int(10))
    begin
    declare i int default 1;
    a:while i<count do
    insert into class(card) values(FLOOR(1+(RAND()*20)));
    set i = i+1;
    end while a;
    end $


    delimiter $
    create procedure insert_book(in count int(10))
    begin
    declare i int default 1;
    a:while i<count do
    insert into book(card) values(FLOOR(1+(RAND()*20)));
    set i = i+1;
    end while a;
    end $

    call insertt(12);
    call insert_book(12);
    select * from class;
    select * from book;
    mysql> explain select * from class left join book b on class.card = b.card;
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+
    | id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                      |
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+
    |  1 | SIMPLE      | class | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   18 |   100.00 | NULL                                       |
    |  1 | SIMPLE      | b     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   18 |   100.00 | Using where; Using join buffer (hash join) |
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+
    2 rows in set, 1 warning (0.00 sec)
    type 等于 all
    alter table book add index Y(card);
    建立book表索引
    mysql> show index from book; +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression | +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+ | book | 0 | PRIMARY | 1 | bookid | A | 18 | NULL | NULL | | BTREE | | | YES | NULL | | book | 1 | Y | 1 | card | A | 11 | NULL | NULL | | BTREE | | | YES | NULL | +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+ 2 rows in set (0.01 sec) mysql> explain select * from class left join book b on class.card = b.card; +----+-------------+-------+------------+------+---------------+------+---------+--------------------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+--------------------+------+----------+-------------+ | 1 | SIMPLE | class | NULL | ALL | NULL | NULL | NULL | NULL | 18 | 100.00 | NULL | | 1 | SIMPLE | b | NULL | ref | Y | Y | 4 | mysqljj.class.card | 1 | 100.00 | Using index | +----+-------------+-------+------------+------+---------------+------+---------+--------------------+------+----------+-------------+ 2 rows in set, 1 warning (0.00 sec)
    type 变为 ref 情况变好点
    建立class表card索引
    alter table class add index Y(card);
    mysql> explain select * from class left join book b on class.card = b.card;
    +----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+--------------------------------------------+
    | id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                      |
    +----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+--------------------------------------------+
    |  1 | SIMPLE      | class | NULL       | index | NULL          | Y    | 4       | NULL |   18 |   100.00 | Using index                                |
    |  1 | SIMPLE      | b     | NULL       | ALL   | NULL          | NULL | NULL    | NULL |   18 |   100.00 | Using where; Using join buffer (hash join) |
    +----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+--------------------------------------------+
    2 rows in set, 1 warning (0.00 sec)
    个人理解:左连接一般加在右表,因为左面为主表,左表引用右表,我们引用右表,当然是拿左表的数据取检索右表的数据,我们将索引添加到右表,大大提高了性能,type变为了ref
    换一种理解思路,因为我们是用主表中数据取比对附表,那么我们主表数据肯定都有,那么我们检索相对应的表的时候,可以添加所以,提高性能
    同样,right join ,右连接,那么就是在相反的,左表中添加索引

    mysql> alter table `book` add index Y(`card`);
    Query OK, 0 rows affected (0.03 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> explain select * from class left join book b on class.card = b.card;
    +----+-------------+-------+------------+------+---------------+------+---------+--------------------+------+----------+-------------+
    | id | select_type | table | partitions | type | possible_keys | key  | key_len | ref                | rows | filtered | Extra       |
    +----+-------------+-------+------------+------+---------------+------+---------+--------------------+------+----------+-------------+
    |  1 | SIMPLE      | class | NULL       | ALL  | NULL          | NULL | NULL    | NULL               |   18 |   100.00 | NULL        |
    |  1 | SIMPLE      | b     | NULL       | ref  | Y             | Y    | 4       | mysqljj.class.card |    1 |   100.00 | Using index |
    +----+-------------+-------+------------+------+---------------+------+---------+--------------------+------+----------+-------------+
    2 rows in set, 1 warning (0.00 sec)
    
    右连接示范 右连接是查找右面的所有数据,所以,右主表都有,坐标加索引 type 变为 ref 相反建 mysql
    > explain select * from book b RIGHT JOIN class c on b.card = c.card; +----+-------------+-------+------------+------+---------------+------+---------+----------------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+----------------+------+----------+-------------+ | 1 | SIMPLE | c | NULL | ALL | NULL | NULL | NULL | NULL | 18 | 100.00 | NULL | | 1 | SIMPLE | b | NULL | ref | Y | Y | 4 | mysqljj.c.card | 1 | 100.00 | Using index | +----+-------------+-------+------------+------+---------------+------+---------+----------------+------+----------+-------------+ 2 rows in set, 1 warning (0.00 sec)

     

  3. 三表
    添加phone 表
    create
    table if not exists `phone`( phoneid int(10) unsigned not null auto_increment, card int(10) unsigned not null , primary key (phoneid) )ENGINE=INNODB; delimiter $ create procedure insert_phone(in count int(10)) begin declare i int default 1; a:while i<count do insert into phone(card) values(FLOOR(1+(RAND()*20))); set i = i+1; end while a; end $ call insert_phone(21);
    内连接三表连接
    mysql> explain select * from class inner join book b on class.card = b.card inner join phone p on b.card = p.card; +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+ | 1 | SIMPLE | class | NULL | ALL | NULL | NULL | NULL | NULL | 29 | 100.00 | NULL | | 1 | SIMPLE | b | NULL | ALL | NULL | NULL | NULL | NULL | 29 | 10.00 | Using where; Using join buffer (hash join) | | 1 | SIMPLE | p | NULL | ALL | NULL | NULL | NULL | NULL | 50 | 10.00 | Using where; Using join buffer (hash join) | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+ 3 rows in set, 1 warning (0.00 sec)
    type 全为 all
    使用Using join buffer 缓冲流
    添加phone和book的索引

    mysql> alter table `phone` add index Z(`card`);
    Query OK, 0 rows affected (0.06 sec)
    Records: 0 Duplicates: 0 Warnings: 0

    mysql> alter table `book` add index Y(`card`);
    Query OK, 0 rows affected (0.05 sec)
    Records: 0 Duplicates: 0 Warnings: 0

    再次explain 发现b表和p表的type变为了ref,rows优化了,总行数变少,因此索引最好设置再需要经常查询的字段中
    mysql> explain select * from class inner join book b on class.card = b.card inner join phone p on b.card = p.card; +----+-------------+-------+------------+------+---------------+------+---------+--------------------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+--------------------+------+----------+-------------+ | 1 | SIMPLE | class | NULL | ALL | NULL | NULL | NULL | NULL | 3028 | 100.00 | NULL | | 1 | SIMPLE | b | NULL | ref | Y | Y | 4 | mysqljj.class.card | 151 | 100.00 | Using index | | 1 | SIMPLE | p | NULL | ref | Z | Z | 4 | mysqljj.class.card | 152 | 100.00 | Using index | +----+-------------+-------+------------+------+---------------+------+---------+--------------------+------+----------+-------------+ 3 rows in set, 1 warning (0.00 sec)

    join语句的优化

    尽可能减少join语句中的NestedLoop的循环次数,永远用小结果集驱动大的结果集

    个人理解:因为大的结果集运用join的时候他的不能全表扫描all ,这样大大浪费时间和cpu内存,所以要用在大的结果集上加索引,用小的去join结果集大的。

 

posted @ 2021-09-28 16:02  一只小白菜。  阅读(164)  评论(0)    收藏  举报