文章目录
- 0、group by 优化
- 1、删除多余的索引
- 2、查询 group by profession
- 3、执行计划 group by profession
- 4、创建联合索引 idx_user_pro_age_sta
- 5、再次执行计划 group by profession
- 6、执行计划 group by age
- 7、执行计划 group by profession,age
- 8、执行计划 where profession='软件工程' group by age
0、group by 优化
分组操作时,可以通过索引来提高效率。
分组操作时,索引的使用也是满足最左前缀法则的。
group by 即使没有过滤条件用到索引,也可以直接使用索引。
group by 先排序再分组,遵照索引建的最佳左前缀法则
包含了order by、group by、distinct这些查询的语句,where条件过滤出来的结果集请保持在1000行以内,否则SQL会很慢。
where效率高于having,能写在where限定的条件就不要写在having中了
当无法使用索引列,增大 max_length_for_sort_data 和 sort_buffer_size 参数的设置
减少使用order by,和业务沟通能不排序就不排序,或将排序放到程序端去做。order by、group by、distinct这些语句较为耗费CPU,数据库的CPU资源是极其宝贵的。
1、删除多余的索引
mysql> show index from tb_user;
+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+
| tb_user | 0 | PRIMARY | 1 | id | A | 24 | NULL | NULL | | BTREE | | | YES | NULL |
| tb_user | 1 | idx_user_pro_age_sta | 1 | profession | A | 16 | NULL | NULL | YES | BTREE | | | YES | NULL |
| tb_user | 1 | idx_user_pro_age_sta | 2 | age | A | 22 | NULL | NULL | YES | BTREE | | | YES | NULL |
| tb_user | 1 | idx_user_pro_age_sta | 3 | status | A | 24 | NULL | NULL | YES | BTREE | | | YES | NULL |
| tb_user | 1 | idx_email_5 | 1 | email | A | 23 | 5 | NULL | YES | BTREE | | | YES | NULL |
| tb_user | 1 | idx_user_age_phone | 1 | age | A | 19 | NULL | NULL | YES | BTREE | | | YES | NULL |
| tb_user | 1 | idx_user_age_phone | 2 | phone | A | 24 | NULL | NULL | | BTREE | | | YES | NULL |
| tb_user | 1 | idx_user_age_pho_ad | 1 | age | A | 19 | NULL | NULL | YES | BTREE | | | YES | NULL |
| tb_user | 1 | idx_user_age_pho_ad | 2 | phone | D | 24 | NULL | NULL | | BTREE | | | YES | NULL |
+
9 rows in set (0.00 sec)
mysql> drop index idx_user_pro_age_sta on tb_user;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> drop index idx_user_age_phone on tb_user;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> drop index idx_user_age_pho_ad on tb_user;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> drop index idx_email_5 on tb_user;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show index from tb_user;
+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+
| tb_user | 0 | PRIMARY | 1 | id | A | 24 | NULL | NULL | | BTREE | | | YES | NULL |
+
1 row in set (0.00 sec)
mysql>
2、查询 group by profession
mysql> select profession,count(*) from tb_user group by profession;
+
| profession | count(*) |
+
| 软件工程 | 4 |
| 通讯工程 | 1 |
| 英语 | 1 |
| 工程造价 | 3 |
| 舞蹈 | 1 |
| 应用数学 | 2 |
| 化工 | 2 |
| 金属材料 | 1 |
| 机械工程及其自动
化 | 1 |
| 无机非金属材料工
程 | 1 |
| 会计 | 1 |
| 工业经济 | 1 |
| 国际贸易 | 1 |
| 城市规划 | 2 |
| 土木工程 | 1 |
| 城市园林 | 1 |
+
16 rows in set (0.00 sec)
mysql>
3、执行计划 group by profession
mysql> explain select profession,count(*) from tb_user group by profession;
+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+
| 1 | SIMPLE | tb_user | NULL | ALL | NULL | NULL | NULL | NULL | 24 | 100.00 | Using temporary |
+
1 row in set, 1 warning (0.00 sec)
mysql>
MySQL 没有使用任何索引,而是执行了全表扫描(type: ALL),并且使用了临时表(Extra: Using temporary)来完成分组操作。
Extra字段显示了"Using temporary",表示MySQL需要创建一个临时表来存储中间结果。
4、创建联合索引 idx_user_pro_age_sta
mysql> create index idx_user_pro_age_sta on tb_user(profession,age,status);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show index from tb_user;
+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+
| tb_user | 0 | PRIMARY | 1 | id | A | 24 | NULL | NULL | | BTREE | | | YES | NULL |
| tb_user | 1 | idx_user_pro_age_sta | 1 | profession | A | 16 | NULL | NULL | YES | BTREE | | | YES | NULL |
| tb_user | 1 | idx_user_pro_age_sta | 2 | age | A | 22 | NULL | NULL | YES | BTREE | | | YES | NULL |
| tb_user | 1 | idx_user_pro_age_sta | 3 | status | A | 24 | NULL | NULL | YES | BTREE | | | YES | NULL |
+
4 rows in set (0.01 sec)
mysql>
5、再次执行计划 group by profession
mysql> explain select profession,count(*) from tb_user group by profession;
+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+
| 1 | SIMPLE | tb_user | NULL | index | idx_user_pro_age_sta | idx_user_pro_age_sta | 54 | NULL | 24 | 100.00 | Using index |
+
1 row in set, 1 warning (0.00 sec)
mysql>
6、执行计划 group by age
mysql> explain select age,count(*) from tb_user group by age;
+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+
| 1 | SIMPLE | tb_user | NULL | index | idx_user_pro_age_sta | idx_user_pro_age_sta | 54 | NULL | 24 | 100.00 | Using index; Using temporary |
+
1 row in set, 1 warning (0.00 sec)
mysql>
Extra: 额外的信息。Using index 表示 MySQL 仅使用了索引中的信息来满足查询,但没有实际读取表中的数据。但是,Using temporary 表示 MySQL 需要使用一个临时表来存储中间结果,这通常会增加查询的开销
7、执行计划 group by profession,age
mysql> explain select profession,age,count(*) from tb_user group by profession,age;
+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+
| 1 | SIMPLE | tb_user | NULL | index | idx_user_pro_age_sta | idx_user_pro_age_sta | 54 | NULL | 24 | 100.00 | Using index |
+
1 row in set, 1 warning (0.00 sec)
mysql>
8、执行计划 where profession=‘软件工程’ group by age
mysql> explain select age,count(*) from tb_user where profession='软件工程' group by age;
+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+
| 1 | SIMPLE | tb_user | NULL | ref | idx_user_pro_age_sta | idx_user_pro_age_sta | 47 | const | 4 | 100.00 | Using index |
+
1 row in set, 1 warning (0.00 sec)
mysql>
Extra: 这次只显示了 Using index,表示 MySQL 仅使用了索引中的信息来满足查询,而无需回表(即无需再读取表中的数据)。这是使用索引的理想情况,因为它避免了读取整个数据行,从而提高了查询效率。
