# 预估并转化为常数表达式

当 MySQL 检测到一个表达式可以转化为常数的时候，就会一直把该表达式作为**常数**进行优化处理。例如，一个用户自定义变量在查询中没有发生变化时就可以将其转换为一个常数。数学表达式则是另一种典型的例子。

## 示例

在优化阶段，有时候一个查询也能够转化为一个常数。

一个例子是**在索引列上执行 MIN() 函数，**&#x5982;果 WHERE 子句中使用了该类索引的常数条件，MySQL 可以在查询开始阶段就先查找到这些值，这样优化器就能够知道并将其转换为常数表达式：

```sql
EXPLAIN
SELECT 
    film.film_id, film_actor.actor_id
FROM 
    film
INNER JOIN film_actor USING (film_id)
WHERE 
    film.film_id = 1;
```

```sql
+-------------+--------------------------+
|id           |1          |1             |
+-------------+--------------------------+
|select_type  |SIMPLE     |SIMPLE        |
+-------------+--------------------------+
|table        |film       |film_actor    |
+-------------+--------------------------+
|partitions   |NULL       |NULL          |
+-------------+--------------------------+
|type         |const      |ref           |
+-------------+--------------------------+
|possible_keys|PRIMARY    |idx_fk_film_id|
+-------------+--------------------------+
|key          |PRIMARY    |idx_fk_film_id|
+-------------+--------------------------+
|key_len      |2          |2             |
+-------------+--------------------------+
|ref          |const      |const         |
+-------------+--------------------------+
|rows         |1          |10            |
+-------------+--------------------------+
|filtered     |100        |100           |
+-------------+--------------------------+
|Extra        |Using index|Using index   |
+-------------+--------------------------+
```

MySQL 分两步来执行这个查询，也就是上面执行计划的两列输出：

* 第一步先从 film 表找到需要的行。因为在 film\_id 列上有主键索引，所以 MySQL 优化器知道这只会返回一行数&#x636E;**，优化器在生成执行计划的时候，就已经通过索引信息知道将返回多少行数据了**。因为查询优化器已经明确知道有多少个值（WHERE 条件中的值）需要做索引查询，所以这里的表访问类型是 const。
* 在执行计划的第二步时，MySQL 将第一步中返回的 film\_id 列当作一个已知取值的列来处理。因为**优化器清楚在第一步执行完成后，该值就会是明确的了**。注意，正如在第一步中一样，使用 film\_actor 字段对表的访问类型也是 const。
