php - 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 子句。它真的能对性能产生那么大的影响吗?
解决方案
括号不一样。您的第一个查询将括号放在 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 BY
到r1
. 好吧,这可能没有用——这取决于是否u
涉及多行。但接下来我们会讨论你是否会绊倒ONLY_FULL_GROUP_BY
。所以,请解释一下表格是 1:many 还是 1:1。
(我同意这是一个 XY 问题。)
推荐阅读
- javascript - How to clickable button on the basis of select and fetch data
- python - 使用成对数组值构建的矩阵
- java - (问题已解决)(Maven运行配置)在本地tomcat服务器中更改java项目
- css - CSS 不透明度过渡
- dictionary - Tableau Server 中地图的地理图层
- flutter - 如何在颤振(飞镖)中重新加载 CheckboxListTile?
- r - 在 geom_col 躲避位置中未保留的组内排序
- python - 如何从另一个屏幕获取字段值?
- powershell - Powershell + csv:读取第1列,修改内容并将其写在第2列中
- reactjs - 在使用 react-dnd 的 react typescript 中使用 useDrag({}) 方法时出错