MySQL:如何使用索引优化主键上的 JOIN

问题描述 投票:0回答:1

我希望优化使用第二个表中一小部分列的表之间的 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 query-optimization covering-index
1个回答
0
投票

这是我的测试结果:

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”字段,所以只需要逐一比较和过滤即可。

© www.soinside.com 2019 - 2024. All rights reserved.