如何将 IN 条件转换为 INNER JOIN 条件 - 加入速度较慢
Posted
技术标签:
【中文标题】如何将 IN 条件转换为 INNER JOIN 条件 - 加入速度较慢【英文标题】:How to convert IN condition to INNER JOIN condition - join is slower 【发布时间】:2014-03-19 13:38:17 【问题描述】:我有一个查询在 INNER JOIN 条件下非常慢,但在 WHERE IN 子句中使用时速度更快:
较慢的内连接:
SELECT *
FROM cases
left join
(
select tst.team_set_id
from team_sets_teams tst
INNER JOIN team_memberships team_memberships
ON tst.team_id = team_memberships.team_id
AND team_memberships.user_id = '1'
AND team_memberships.deleted=0 group by tst.team_set_id
) cases_tf
ON cases_tf.team_set_id = cases.team_set_id
LEFT JOIN contacts_cases
ON contacts_cases.case_id = cases.id
AND contacts_cases.deleted = 0
where cases.deleted=0
ORDER BY cases.name LIMIT 0,20;
在哪里更快:
SELECT *
FROM cases
LEFT JOIN contacts_cases
ON contacts_cases.case_id = cases.id
AND contacts_cases.deleted = 0
where cases.deleted=0
and cases.team_set_id in (
select tst.team_set_id
from team_sets_teams tst
INNER JOIN team_memberships team_memberships
ON tst.team_id = team_memberships.team_id
AND team_memberships.user_id = '1'
AND team_memberships.deleted=0
group by tst.team_set_id
)
ORDER BY cases.name LIMIT 0,20;
INNER JOIN 和 WHERE IN 子句的解释计划如下:
内连接:
+----+-------------+------------------+------+--------------------------------------------+---------------------+---------+-----------------------------------+--------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------------+------+--------------------------------------------+---------------------+---------+-----------------------------------+--------+----------------------------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 4 | Using temporary; Using filesort |
| 1 | PRIMARY | cases | ref | idx_cases_tmst_id | idx_cases_tmst_id | 109 | cases_tf.team_set_id | 446976 | Using where |
| 1 | PRIMARY | contacts_cases | ref | idx_con_case_case | idx_con_case_case | 111 | sugarcrm.cases.id | 1 | |
| 2 | DERIVED | team_memberships | ref | idx_team_membership,idx_teammemb_team_user | idx_team_membership | 109 | | 2 | Using where; Using temporary; Using filesort |
| 2 | DERIVED | tst | ref | idx_ud_team_id | idx_ud_team_id | 109 | sugarcrm.team_memberships.team_id | 1 | Using where |
+----+-------------+------------------+------+--------------------------------------------+---------------------+---------+-----------------------------------+--------+----------------------------------------------+
在状态:
------+-----------------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+------------------+-------+--------------------------------------------+---------------------+---------+-----------------------------------+------+----------------------------------------------+
| 1 | PRIMARY | cases | index | NULL | idx_case_name | 768 | NULL | 20 | Using where |
| 1 | PRIMARY | contacts_cases | ref | idx_con_case_case | idx_con_case_case | 111 | sugarcrm.cases.id | 1 | |
| 2 | DEPENDENT SUBQUERY | team_memberships | ref | idx_team_membership,idx_teammemb_team_user | idx_team_membership | 109 | const | 2 | Using where; Using temporary; Using filesort |
| 2 | DEPENDENT SUBQUERY | tst | ref | idx_ud_team_id | idx_ud_team_id | 109 | sugarcrm.team_memberships.team_id | 1 | Using where |
+----+--------------------+------------------+-------+--------------------------------------------+---------------------+---------+-----------------------------------+------+----------------------------------------------+
虽然有索引,但我无法弄清楚问题所在。请帮帮我。谢谢。 (这是sugarcrm中的查询)
【问题讨论】:
【参考方案1】:无法将IN
条件转换为INNER JOIN
。
带有IN
条件的查询称为semi-join。
半连接从一个表返回将与另一个表连接但不执行完整连接的行。
下面是一个使用 IN 运算符的半连接查询的简单示例:
SELECT *
FROM table1
WHERE some-column IN (
SELECT some-other-column
FROM table2
WHERE some-conditions
)
上面的半连接可以转化为语义等价的查询
(等效 - 表示giving exactly same results
)
使用 EXISTS 运算符和依赖子查询:
SELECT *
FROM table1
WHERE EXISTS(
SELECT 1
FROM table2
WHERE some-conditions
AND table1.some-column = table2.some-other-column
)
大多数领先的数据库对上述两个查询都使用相同的计划,并且它们的速度是相同的, 不幸的是,mysql 并不总是这样。
联接和半联接是完全不同的查询,具有完全不同的执行计划,因此比较它们的速度就像比较苹果和洋葱。 您可以尝试将第一个带有 IN 的查询转换为带有 EXIST 的查询,但不能转换为联接。
【讨论】:
谢谢,但我们最终完全删除了团队条件。以上是关于如何将 IN 条件转换为 INNER JOIN 条件 - 加入速度较慢的主要内容,如果未能解决你的问题,请参考以下文章
如何将 SQL Inner Join、Group By 转换为 Linq?