我希望优化使用第二个表中一小部分列的表之间的 JOIN。
CREATE TABLE `employees` (
`employee_id` bigint NOT NULL,
`manager_id` bigint NOT NULL,
`org_id` bigint NOT NULL,
`union_id` bigint NOT NULL
...
PRIMARY KEY (employee_id),
INDEX (union_id)
);
CREATE TABLE `managers` (
`manager_id` bigint NOT NULL,
`org_id` bigint NOT NULL,
`some_condition` boolean NOT NULL,
PRIMARY KEY (manager_id)
);
现在我想优化两种类型的查询。两者都根据 manager_id 和 org_id 将表连接在一起,并且可以选择对 some_condition 列应用过滤器。
SELECT employees.*
FROM employees
JOIN managers
ON (employees.manager_id = managers.manager_id AND employees.org_id = managers.org_id)
WHERE (employees.union_id = ? AND managers.some_condition);
SELECT employees.*
FROM employees
JOIN managers
ON (employees.manager_id = managers.manager_id AND employees.org_id = managers.org_id)
WHERE (employees.union_id = ?);
假设这些是非常大的桌子和员工>经理。我正在尝试在管理器上创建一个索引,以加快查询速度。现在查询很慢,因为对于每一行,它都必须读取 org_id 和 some_condition。如果可能的话,我想避免进入磁盘。
到目前为止,我有两个可能有效的索引:
INDEX `join_index` (`org_id`,`some_condition`)
INDEX `id_join_index` (`manager_id`, `org_id`, `some_condition`)
我的主要问题是 MySQL 不会在 EXPLAIN 语句中使用任何一个索引,除非我使用 use index (...) 强制它。
哪个索引(如果有的话)会加速我的查询,如果我不过滤 some_condition,我是否需要索引中的 manager_id 来加速连接?
这是我的测试结果:
mysql> alter table managers add index test_1(`some_condition`);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql>
mysql>
mysql>
mysql>
mysql> explain SELECT employees.*
-> FROM employees
-> JOIN managers
-> ON (employees.manager_id = managers.manager_id AND employees.org_id = managers.org_id)
-> WHERE (employees.union_id = "" and managers.some_condition="");
+----+-------------+-----------+------------+--------+----------------+----------+---------+----------------------------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+--------+----------------+----------+---------+----------------------------+------+----------+-----------------------+
| 1 | SIMPLE | employees | NULL | ref | union_id | union_id | 8 | const | 1 | 100.00 | Using index condition |
| 1 | SIMPLE | managers | NULL | eq_ref | PRIMARY,test_1 | PRIMARY | 8 | zbdba.employees.manager_id | 1 | 100.00 | Using where |
+----+-------------+-----------+------------+--------+----------------+----------+---------+----------------------------+------+----------+-----------------------+
2 rows in set, 1 warning (0.00 sec)
这看起来和你的一样。这里的“manager”表使用主键索引。为什么它不使用我们创建的二级索引?因为二级索引只包含指定列的数据。由于您的SQL Join中的字段包含“manager”表的主键“manager_id”字段,因此如果MySQL使用您创建的二级索引,它仍然需要执行查表来查询主键索引以获得“ manager_id”字段。因此,MySQL直接选择了“manager”表的主键索引。因为主键索引包含一整行记录,包括“org_id”和“some_condition”字段,所以只需要逐一比较和过滤即可。