mysql----索引优化(1)

索引优化案例分析
    单表:
        create table if not exists article(
            id int unsigned not null primary key auto_increment,
            author_id int unsigned not null,
            category_id int unsigned not null,
            views int unsigned not null,
            comments int unsigned not null,
            title varchar(255) not null,
            content text not null
        );
        insert into article(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');
        查询category_id是1且comments>1的情况下,views最多的id.
        select id,author_id from article
        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      | article | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |    33.33 | Using where; Using filesort |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
 
 
(范围之后的索引会导致失效)
1.create index idx_article_ccv on article(category_id,comments,views);
+----+-------------+---------+------------+-------+-----------------+-----------------+---------+------+------+----------+---------------------------------------+
| id | select_type | table   | partitions | type  | possible_keys   | key             | key_len | ref  | rows | filtered | Extra                                 |
+----+-------------+---------+------------+-------+-----------------+-----------------+---------+------+------+----------+---------------------------------------+
|  1 | SIMPLE      | article | NULL       | range | idx_article_ccv | idx_article_ccv | 8       | NULL |    1 |   100.00 | Using index condition; Using filesort |
+----+-------------+---------+------------+-------+-----------------+-----------------+---------+------+------+----------+---------------------------------------+
1 row in set, 1 warning (0.07 sec)
因为结果中有using filesort,因此本次的索引不合适

2.drop index idx_article_ccv on article;
  去掉comments的索引  
  create index idx_article_cv on article(category_id,views);
    


    
双表:
   商品类别class
    create table if not exists class(
        id int not null primary key auto_increment,
        card int not null        
    );
   商品book
    create table if not exists book(
        book_id int not null primary key auto_increment,
        card int not null
    );
    
    insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
        insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
    insert into class(card) value(floor(1+rand()*20));
    
        insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
        insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
查询:
    select * from book inner join class on book.card = class.card;
    select * from book left join class on book.card = class.card;
    select * from book fight join class on book.card = class.card;
mysql> explain select * from book right join class on book.card = class.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 |   20 |   100.00 | NULL                                               |
|  1 | SIMPLE      | book  | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   20 |   100.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)
问题:索引应该建在哪张表?
    尝试在book表建索引:alter table book add index idx_b_c(card);    
     mysql> explain select * from class left join book on book.card = class.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               |   20 |   100.00 | NULL        |
            |  1 | SIMPLE      | book  | NULL       | ref  | idx_b_c       | idx_b_c | 4       | db_name.class.card |    1 |   100.00 | Using index |
            +----+-------------+-------+------------+------+---------------+---------+---------+--------------------+------+----------+-------------+
            左链接加在右表索引是正确的。
            结论:左连接或者右连接都在相反的方向加索引。
            简单点理解就是,如果是左连接,坐标一定全包含,因此只需要右表查询快就好。
            
 三表:
    新增表phone
    create table if not exists phone(
        phone_id int not null primary key auto_increment,
        card int not null
    );
         insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
        insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
    insert into book(card) value(floor(1+rand()*20));
     
问题:3表连接索引应该建在哪张表?
     explain select * from class left join book on class.card = book.card left join phone on book.card = phone.card;
    mysql>     explain select * from class left join book on class.card = book.card left join phone on book.card = phone.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 |   20 |   100.00 | NULL                                               |
    |  1 | SIMPLE      | book  | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   40 |   100.00 | Using where; Using join buffer (Block Nested Loop) |
    |  1 | SIMPLE      | phone | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where; Using join buffer (Block Nested Loop) |
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
    3 rows in set, 1 warning (0.00 sec)
     
尝试:左连接时在右侧的两张表建索引
    mysql> alter table book add index idx_b_c(card);
    Query OK, 0 rows affected (0.53 sec)
    Records: 0  Duplicates: 0  Warnings: 0

    mysql> alter table phone add index idx_p_c(card);
    Query OK, 0 rows affected (0.39 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql>     explain select * from class left join book on class.card = book.card left join phone on book.card = phone.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               |   20 |   100.00 | NULL        |
    |  1 | SIMPLE      | book  | NULL       | ref  | idx_b_c       | idx_b_c | 4       | db_name.class.card |    2 |   100.00 | Using index |
    |  1 | SIMPLE      | phone | NULL       | ref  | idx_p_c       | idx_p_c | 4       | db_name.book.card  |    1 |   100.00 | Using index |
    +----+-------------+-------+------------+------+---------------+---------+---------+--------------------+------+----------+-------------+
     结论:尽量减少join中nestedlook的循环次数,永远用小表驱动大表。

发布了76 篇原创文章 · 获赞 21 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/shen_chengfeng/article/details/104456216