MySQL 在 if 函数中无法使用索引:
您需要一个 MySQL 中不可能的函数索引。
另请参阅:How does one create an index on the date part of DATETIME field in MySql
我正在使用员工测试数据库http://dev.mysql.com/doc/employee/en/employee.html
mysql> describe employees;
+------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------+------+-----+---------+-------+
| emp_no | int(11) | NO | PRI | NULL | |
| birth_date | date | NO | | NULL | |
| first_name | varchar(14) | NO | | NULL | |
| last_name | varchar(16) | NO | | NULL | |
| gender | enum('M','F') | NO | | NULL | |
| hire_date | date | NO | | NULL | |
+------------+---------------+------+-----+---------+-------+
6 rows in set (0.01 sec)
mysql> select count(*) from employees;
+----------+
| count(*) |
+----------+
| 300024 |
+----------+
1 row in set (0.37 sec)
将所有性别设置为男性,以便模仿问题。
mysql> update employees set gender = 'M';
Query OK, 1 row affected (9.11 sec)
Rows matched: 300024 Changed: 1 Warnings: 0
mysql> select emp_no, gender from employees order by emp_no limit 2;
+--------+--------+
| emp_no | gender |
+--------+--------+
| 10001 | M |
| 10002 | M |
+--------+--------+
2 rows in set (0.00 sec)
将一名员工设置为女性。
(注意它使用索引并且几乎是即时的。)
mysql> update employees set gender = 'F' where emp_no = 10001;
Query OK, 1 row affected (0.14 sec)
Rows matched: 1 Changed: 1 Warnings: 0
现在我们使用建议的答案。 (注意它不使用索引并触及每一行。)
mysql> update employees set gender = if(emp_no=10002, 'F', 'M');
Query OK, 2 rows affected (10.67 sec)
Rows matched: 300024 Changed: 2 Warnings: 0
索引会有帮助吗?
> mysql> create index employees_gender_idx on employees(gender);
Query OK, 300024 rows affected (21.61 sec)
Records: 300024 Duplicates: 0 Warnings: 0
> mysql> update employees set gender = if(emp_no=10001, 'F', 'M');
Query OK, 2 rows affected (9.02 sec)
Rows matched: 300024 Changed: 2 Warnings: 0
Nope.
也有人说 MySQL 只会查看需要更改的行。
mysql> update employees set gender = 'M';
Query OK, 1 row affected (8.78 sec)
Rows matched: 300024 Changed: 1 Warnings: 0
猜不出来。如果使用WHERE 子句怎么办?
mysql> update employees set gender = 'M' where gender ='F';
Query OK, 0 rows affected (0.03 sec)
Rows matched: 0 Changed: 0 Warnings: 0
真快,现在它使用了索引。
Mysql 不知道IF 函数会返回什么,并且必须 进行全表扫描。请注意,WHERE 确实表示位置,SET 确实表示设置。您不能指望 DB 只安排所有子句以获得良好的性能。
正确的解决方案是发布两次更新(如果使用索引,这几乎是即时的。)
注意,在别处说过 MySQL 会神奇地知道只更新它需要更改的行。