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的循環次數,永遠用小表驅動大表。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章