首页 > 解决方案 > MySQL IN 子句与 OR 子句影响性能 - 为什么 OR 比 IN 快?

问题描述

我的任务是重写一个慢查询。我解决了我的性能问题,但是我很不安,因为我不明白为什么我尝试的一种方法比另一种更快。

查询 1(在网站上大约需要 13 秒,在 PHPMYADMIN 中大约需要 0.2 秒):

SELECT t.USER_ID, COUNT(DISTINCT r1.id1) as count_matches 
FROM b_squad_member_result as t
INNER JOIN (SELECT m.IBLOCK_ELEMENT_ID as id1, (m.IBLOCK_ELEMENT_ID + 2) as id2, (m.IBLOCK_ELEMENT_ID + 4) as id3 
            FROM b_iblock_element_prop_s3 as m 
            WHERE m.PROPERTY_8 IS NULL) as r1
      ON t.MATCH_ID  IN(id1, id2, id3)
INNER JOIN b_uts_user as u ON u.VALUE_ID = t.USER_ID
      AND u.UF_ID_TEAM = 2228
GROUP BY t.USER_ID

查询 1 的执行计划

在此处输入图像描述

查询 2(在网站上需要 ~0.2 秒,在 PHPMYADMIN 中需要 ~0.2 秒):

SELECT t.USER_ID, COUNT(DISTINCT r1.id1) as count_matches 
FROM b_squad_member_result as t
INNER JOIN (SELECT m.IBLOCK_ELEMENT_ID as id1, (m.IBLOCK_ELEMENT_ID + 2) as id2, (m.IBLOCK_ELEMENT_ID + 4) as id3 
            FROM b_iblock_element_prop_s3 as m 
            WHERE m.PROPERTY_8 IS NULL) as r1
      ON t.MATCH_ID = id1 OR t.MATCH_ID = id2 OR t.MATCH_ID = id3
INNER JOIN b_uts_user as u ON u.VALUE_ID = t.USER_ID
      AND u.UF_ID_TEAM = 2228
GROUP BY t.USER_ID

查询 2 的执行计划:

我首先使用查询 1,因为在 PHPMYADMIN 中它满足了我的性能预期。但是,在网站本身上,查询花费了更多时间。在尝试了许多不同的解决方案之后,我决定更改t.MATCH_ID = id1 OR t.MATCH_ID = id2 OR t.MATCH_ID = id3的 IN 子句,这样可以尽可能快地工作。但是我想了解为什么第二种方法更快。我读过 IN 子句在实际执行之前被转换为多个 OR 子句。它真的能对性能产生那么大的影响吗?

标签: phpmysql

解决方案


括号不一样。您的第一个查询将括号放在 r1 的ON内部;它会在外面,就像你对第二个查询所做的那样。

我看到它们EXPLAINs是不同的;我不知道这是因为括号还是 IN vs OR。

针对多个列测试一个值对性能非常不利。它通常可以通过模式更改来修复。我将反模式称为“跨列喷洒数组”。通常最好为这些 id 提供另一个具有 [最多] 3 行的表。如果 id 是字符串,则FULLTEXT可能是更好的方法。

虽然上一段是通用的,但它不适用于您的情况,因为 idn 是从单个 column 计算的IBLOCK_ELEMENT_ID。怎么回事?

我真的需要看到SHOW CREATE TABLE全力帮助你。

如果您还没有这些索引,它们可能会有所帮助:

u:  (UF_ID_TEAM, VALUE_ID)
m:  (PROPERTY_8, IBLOCK_ELEMENT_ID)

COUNT(DISTINCT r1.id1)-DISTINCT通过将 a 添加GROUP BYr1. 好吧,这可能没有用——这取决于是否u涉及多行。但接下来我们会讨论你是否会绊倒ONLY_FULL_GROUP_BY。所以,请解释一下表格是 1:many 还是 1:1。

(我同意这是一个 XY 问题。)


推荐阅读