MySQL 优化学习1 -- 索引

转载自: https://www.cnblogs.com/phpdragon/p/8231533.html,实践如下


主键索引和普通索引

mysql> show create table test_user;
+-----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table     | Create Table                                                                                                                                                                                                                                                                                                 |
+-----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| test_user | CREATE TABLE `test_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `email` varchar(30) DEFAULT NULL,
  `password` varchar(32) DEFAULT NULL,
  `status` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10000001 DEFAULT CHARSET=utf8 |
+-----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
  • 查看表索引

如下是个主键索引

mysql> SHOW INDEX FROM test_user;
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table     | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test_user |          0 | PRIMARY  |            1 | id          | A         |     9702644 |     NULL | NULL   |      | BTREE      |         |               |
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)

mysql> 
  • 1千万条数据select count(*)需要2sec多
mysql> select count(*) from test_user;
+----------+
| count(*) |
+----------+
| 10000000 |
+----------+
1 row in set (2.06 sec)

mysql> select count(*) from test_user;
+----------+
| count(*) |
+----------+
| 10000000 |
+----------+
1 row in set (2.08 sec)

mysql> 
  • sql 主键 与 非主键 查询
mysql> EXPLAIN SELECT id,username,email,password FROM sample_data.test_user WHERE id=999999;
+----+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table     | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+----+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+
|  1 | SIMPLE      | test_user | const | PRIMARY       | PRIMARY | 8       | const |    1 | NULL  |
+----+-------------+-----------+-------+---------------+---------+---------+-------+------+-------+
1 row in set (0.00 sec)

mysql> EXPLAIN SELECT id,username,email,password FROM test_user WHERE username='username_9000000';
+----+-------------+-----------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows    | Extra       |
+----+-------------+-----------+------+---------------+------+---------+------+---------+-------------+
|  1 | SIMPLE      | test_user | ALL  | NULL          | NULL | NULL    | NULL | 9702644 | Using where |
+----+-------------+-----------+------+---------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)

mysql> 
  • 查询时间
mysql> SELECT id,username,email,password FROM test_user WHERE username='username_9000000';
+---------+------------------+----------------+----------------------------------+
| id      | username         | email          | password                         |
+---------+------------------+----------------+----------------------------------+
| 9000000 | username_9000000 | 9000000@qq.com | 48e4e6ac22db9be84820222d57841428 |
+---------+------------------+----------------+----------------------------------+
1 row in set (3.02 sec)

mysql> SELECT id,username,email,password FROM sample_data.test_user WHERE id=999999;
+--------+-----------------+---------------+----------------------------------+
| id     | username        | email         | password                         |
+--------+-----------------+---------------+----------------------------------+
| 999999 | username_999999 | 999999@qq.com | 52c69e3a57331081823331c4e69d3f2e |
+--------+-----------------+---------------+----------------------------------+
1 row in set (0.00 sec)

mysql> 
  • 给 usename 建立索引
mysql> ALTER TABLE `test_user` ADD INDEX index_name(username) ;
Query OK, 0 rows affected (27.21 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql>  SHOW INDEX FROM test_user;
+-----------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table     | Non_unique | Key_name   | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test_user |          0 | PRIMARY    |            1 | id          | A         |     9702644 |     NULL | NULL   |      | BTREE      |         |               |
| test_user |          1 | index_name |            1 | username    | A         |     9702644 |     NULL | NULL   | YES  | BTREE      |         |               |
+-----------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.00 sec)

mysql> 
  • 对普通字段建立索引后查询
mysql> EXPLAIN SELECT id,username,email,password FROM test_user WHERE username='username_9000000';
+----+-------------+-----------+------+---------------+------------+---------+-------+------+-----------------------+
| id | select_type | table     | type | possible_keys | key        | key_len | ref   | rows | Extra                 |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+-----------------------+
|  1 | SIMPLE      | test_user | ref  | index_name    | index_name | 153     | const |    1 | Using index condition |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+-----------------------+
1 row in set (0.01 sec)

mysql> SELECT id,username,email,password FROM test_user WHERE username='username_9000000';
+---------+------------------+----------------+----------------------------------+
| id      | username         | email          | password                         |
+---------+------------------+----------------+----------------------------------+
| 9000000 | username_9000000 | 9000000@qq.com | 48e4e6ac22db9be84820222d57841428 |
+---------+------------------+----------------+----------------------------------+
1 row in set (0.00 sec)

mysql>
  • and or 有索引的区别
mysql> SELECT id, username, email, PASSWORD FROM test_user WHERE `password` = '7ece221bf3f5dbddbe3c2770ac19b419' OR username = 'username_900000';
+--------+-----------------+---------------+----------------------------------+
| id     | username        | email         | PASSWORD                         |
+--------+-----------------+---------------+----------------------------------+
|  24601 | username_24601  | 24601@qq.com  | 7ece221bf3f5dbddbe3c2770ac19b419 |
| 900000 | username_900000 | 900000@qq.com | c3c4f8c964d8fbd9ce62ff3921bd5e79 |
+--------+-----------------+---------------+----------------------------------+
2 rows in set (3.42 sec)

mysql> SELECT id, username, email, PASSWORD FROM test_user WHERE `password` = '7ece221bf3f5dbddbe3c2770ac19b419' and username = 'username_900000';
Empty set (0.01 sec)

mysql> 

and语句中,username有索引,优先使用了索引
or语句中,username有索引,但是password是没有索引的,or语句还是扫描全部数据,所以很耗时

mysql> explain SELECT id, username, email, PASSWORD FROM test_user WHERE `password` = '7ece221bf3f5dbddbe3c2770ac19b419' and username = 'username_900000';
+----+-------------+-----------+------+---------------+------------+---------+-------+------+------------------------------------+
| id | select_type | table     | type | possible_keys | key        | key_len | ref   | rows | Extra                              |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+------------------------------------+
|  1 | SIMPLE      | test_user | ref  | index_name    | index_name | 153     | const |    1 | Using index condition; Using where |
+----+-------------+-----------+------+---------------+------------+---------+-------+------+------------------------------------+
1 row in set (0.00 sec)

mysql> explain  SELECT id, username, email, PASSWORD FROM test_user WHERE `password` = '7ece221bf3f5dbddbe3c2770ac19b419' OR username = 'username_900000';
+----+-------------+-----------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows    | Extra       |
+----+-------------+-----------+------+---------------+------+---------+------+---------+-------------+
|  1 | SIMPLE      | test_user | ALL  | index_name    | NULL | NULL    | NULL | 9702644 | Using where |
+----+-------------+-----------+------+---------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)

mysql> 

聚合索引

mysql> ALTER TABLE `test_user` ADD INDEX index_union_name_password(username,password);
Query OK, 0 rows affected (33.63 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SHOW INDEX FROM test_user;
+-----------+------------+---------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table     | Non_unique | Key_name                  | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+---------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test_user |          0 | PRIMARY                   |            1 | id          | A         |     9702644 |     NULL | NULL   |      | BTREE      |         |               |
| test_user |          1 | index_name                |            1 | username    | A         |     9702644 |     NULL | NULL   | YES  | BTREE      |         |               |
| test_user |          1 | index_union_name_password |            1 | username    | A         |     9702644 |     NULL | NULL   | YES  | BTREE      |         |               |
| test_user |          1 | index_union_name_password |            2 | password    | A         |     9702644 |     NULL | NULL   | YES  | BTREE      |         |               |
+-----------+------------+---------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
4 rows in set (0.00 sec)

mysql> 

  • or 在聚合索引中无效
mysql>  SELECT id, username, email, PASSWORD FROM test_user WHERE username = 'username_900000' OR `password` = '7ece221bf3f5dbddbe3c2770ac19b419';
+--------+-----------------+---------------+----------------------------------+
| id     | username        | email         | PASSWORD                         |
+--------+-----------------+---------------+----------------------------------+
|  24601 | username_24601  | 24601@qq.com  | 7ece221bf3f5dbddbe3c2770ac19b419 |
| 900000 | username_900000 | 900000@qq.com | c3c4f8c964d8fbd9ce62ff3921bd5e79 |
+--------+-----------------+---------------+----------------------------------+
2 rows in set (3.45 sec)

mysql> explain  SELECT id, username, email, PASSWORD FROM test_user WHERE username = 'username_900000' OR `password` = '7ece221bf3f5dbddbe3c2770ac19b419';
+----+-------------+-----------+------+--------------------------------------+------+---------+------+---------+-------------+
| id | select_type | table     | type | possible_keys                        | key  | key_len | ref  | rows    | Extra       |
+----+-------------+-----------+------+--------------------------------------+------+---------+------+---------+-------------+
|  1 | SIMPLE      | test_user | ALL  | index_name,index_union_name_password | NULL | NULL    | NULL | 9702644 | Using where |
+----+-------------+-----------+------+--------------------------------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)

mysql> 
  • and 使用了聚合索引
mysql> SELECT id, username, email, PASSWORD FROM test_user WHERE `password` = '7ece221bf3f5dbddbe3c2770ac19b419' and username = 'username_900000';
Empty set (0.00 sec)

mysql> explain SELECT id, username, email, PASSWORD FROM test_user WHERE `password` = '7ece221bf3f5dbddbe3c2770ac19b419' and username = 'username_900000';
+----+-------------+-----------+------+--------------------------------------+------------+---------+-------+------+------------------------------------+
| id | select_type | table     | type | possible_keys                        | key        | key_len | ref   | rows | Extra                              |
+----+-------------+-----------+------+--------------------------------------+------------+---------+-------+------+------------------------------------+
|  1 | SIMPLE      | test_user | ref  | index_name,index_union_name_password | index_name | 153     | const |    1 | Using index condition; Using where |
+----+-------------+-----------+------+--------------------------------------+------------+---------+-------+------+------------------------------------+
1 row in set (0.00 sec)

mysql> 
mysql> SELECT id, username, email, PASSWORD FROM test_user WHERE `password` = '7ece221bf3f5dbddbe3c2770ac19b419' and username = 'username_900000' \
    -> and status = 0;
Empty set (0.00 sec)

mysql> explain SELECT id, username, email, PASSWORD FROM test_user WHERE `password` = '7ece221bf3f5dbddbe3c2770ac19b419' and username = 'username_900000' and status = 0;
+----+-------------+-----------+------+--------------------------------------+------------+---------+-------+------+------------------------------------+
| id | select_type | table     | type | possible_keys                        | key        | key_len | ref   | rows | Extra                              |
+----+-------------+-----------+------+--------------------------------------+------------+---------+-------+------+------------------------------------+
|  1 | SIMPLE      | test_user | ref  | index_name,index_union_name_password | index_name | 153     | const |    1 | Using index condition; Using where |
+----+-------------+-----------+------+--------------------------------------+------------+---------+-------+------+------------------------------------+
1 row in set (0.00 sec)

mysql> 
mysql> explain SELECT id, username, email, PASSWORD FROM test_user WHERE status = 0 and `password` = '7ece221bf3f5dbddbe3c2770ac19b419' and username = 'username_900000';
+----+-------------+-----------+------+--------------------------------------+------------+---------+-------+------+------------------------------------+
| id | select_type | table     | type | possible_keys                        | key        | key_len | ref   | rows | Extra                              |
+----+-------------+-----------+------+--------------------------------------+------------+---------+-------+------+------------------------------------+
|  1 | SIMPLE      | test_user | ref  | index_name,index_union_name_password | index_name | 153     | const |    1 | Using index condition; Using where |
+----+-------------+-----------+------+--------------------------------------+------------+---------+-------+------+------------------------------------+
1 row in set (0.00 sec)

mysql>
AND 语句才使用到了聚合索引,聚合索引必须使用AND条件,同时要符合最左原则

点击参考

  • 最左索引 例子
mysql> ALTER TABLE `test_user` ADD INDEX index_union_name_password_status(username,password,status);
Query OK, 0 rows affected (33.51 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SHOW INDEX FROM test_user;
+-----------+------------+----------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table     | Non_unique | Key_name                         | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+----------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test_user |          0 | PRIMARY                          |            1 | id          | A         |     9702644 |     NULL | NULL   |      | BTREE      |         |               |
| test_user |          1 | index_name                       |            1 | username    | A         |     9702644 |     NULL | NULL   | YES  | BTREE      |         |               |
| test_user |          1 | index_union_name_password        |            1 | username    | A         |     9702644 |     NULL | NULL   | YES  | BTREE      |         |               |
| test_user |          1 | index_union_name_password        |            2 | password    | A         |     9702644 |     NULL | NULL   | YES  | BTREE      |         |               |
| test_user |          1 | index_union_name_password_status |            1 | username    | A         |     9702644 |     NULL | NULL   | YES  | BTREE      |         |               |
| test_user |          1 | index_union_name_password_status |            2 | password    | A         |     9702644 |     NULL | NULL   | YES  | BTREE      |         |               |
| test_user |          1 | index_union_name_password_status |            3 | status      | A         |     9702644 |     NULL | NULL   | YES  | BTREE      |         |               |
+-----------+------------+----------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
7 rows in set (0.00 sec)

mysql> 

如下的sql不会使用到索引

explain SELECT id, username, email, PASSWORD FROM test_user WHERE `password` = '7ece221bf3f5dbddbe3c2770ac19b419';

explain SELECT id, username, email, PASSWORD FROM test_user WHERE `password` = '7ece221bf3f5dbddbe3c2770ac19b419' and status = 0;

如下的语句则会使用索引

explain SELECT id, username, email, PASSWORD FROM test_user WHERE `username` = '999999' and status = 0;

猜你喜欢

转载自blog.csdn.net/qq_26437925/article/details/82714672