把查询看作一系列子任务,优化方式:消除一些子任务,减少子任务执行次数,子任务运行得更快。
把响应时间当作重要标准。
查询的生命周期(大概):从客户端到服务器,服务器解析,生成执行计划并返回结果给客户端。
查询花费时间在网络,CPU计算,生成统计信息和执行计划,锁等待(互斥等待),底层存储引擎的调用(上下文切换和系统调用),IO操作
6.2.1 请求不需要的数据:
1.查询不需要的记录:扫描行数远远大于返回行数。
2.多表关联时返回全部列
3.总是取出全部列:select * 总是不太好
4.重复查询相同的数据,可以建立缓存
6.2.2
MySQL最简单的衡量查询开销的三个指标:这三个指标都会记录在MySQL慢日志
1.响应时间=服务时间+排队时间(等待IO、等待行锁)
2.扫描行数
3.返回行数
EXPLAIN语句的type列反映了访问类型(查询访问方式怎么返回结果)
EXPALIN内容详解
/*mysql 8.0 database sakila*/
mysql> select * from film_actor where film_id =1;
+----------+---------+---------------------+
| actor_id | film_id | last_update |
+----------+---------+---------------------+
| 1 | 1 | 2006-02-15 05:05:03 |
| 10 | 1 | 2006-02-15 05:05:03 |
| 20 | 1 | 2006-02-15 05:05:03 |
| 30 | 1 | 2006-02-15 05:05:03 |
| 40 | 1 | 2006-02-15 05:05:03 |
| 53 | 1 | 2006-02-15 05:05:03 |
| 108 | 1 | 2006-02-15 05:05:03 |
| 162 | 1 | 2006-02-15 05:05:03 |
| 188 | 1 | 2006-02-15 05:05:03 |
| 198 | 1 | 2006-02-15 05:05:03 |
+----------+---------+---------------------+
10 rows in set (0.06 sec)
mysql> explain select * from film_actor where film_id =1;
+----+-------------+------------+------------+------+----------------+----------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+------+----------------+----------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | film_actor | NULL | ref | idx_fk_film_id | idx_fk_film_id | 2 | const | 10 | 100.00 | NULL |
+----+-------------+------------+------------+------+----------------+----------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from film_actor where film_id =1\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: film_actor
partitions: NULL
type: ref
possible_keys: idx_fk_film_id
key: idx_fk_film_id
key_len: 2
ref: const
rows: 10
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)
删除外键 fk_film_actor_film和索引 idx_fk_film_id
type: ALL
rows: 5073
Extra: Using where
访问类型:全表扫描ALL
Extra: Using where表示通过where条件来筛选存储引擎返回的记录.
应用WHERE条件的三种方式,从好到坏:
1.在索引中使用where,存储引擎层。
2.使用索引覆盖扫描(Extra: Using index),MySQL服务器层,无须回表查询记录。
3.Extra: Using where,MySQL服务器层,从数据表读出数据再过滤。
使用索引减少扫描行数
mysql> select actor_id,count(*) from film_actor group by actor_id;
+----------+----------+
| actor_id | count(*) |
+----------+----------+
| 1 | 19 |
| 2 | 25 |
| 3 | 22 |
| ... | ... |
200 rows in set (0.01 sec)
如果发现查询需要扫描大量的数据但只返回少量行的优化:
1.使用索引覆盖扫描
2.改变库表结构
3.重写复杂的查询
6.7 优化特定类型的查询
6.7.1 count()
1.统计某列的数量,不统计NULL。count(colmun)
2.统计行数,统计NULL。count(*),count(1)
一般查询时,count(1)比count(*)快;
但主键作为count的参数时,count(主键)比count(1)和count(*)都快;
MyISAM 的 count() p237。