我有3张表A,B和C:
我正在运行这样的查询:
SELECT A.Id FROM A, B, C
WHERE A.Id = B.SomeId OR (A.Id = C.SomeId AND C.SomeValue = 'X')
INTO OUTFILE '/tmp/result.txt';
A.Id
是表A的主键B.SomeId
设置了索引C.SomeId
已设置索引C.SomeVal
也设置了一个索引,但它只是一个只有两个可能值的VARCHAR(1)我认为这只需要遍历表A中的每个Id
(1000行),然后可能跨其他表查询(取决于MySQL是否短路,我不知道是否存在)
但查询似乎仍然悬而未决,或者至少需要花费很长时间。如果它只需要迭代1000行,那么比我想象的要长得多。 10分钟后输出文件仍为空。如果我能提供更多信息,请告诉我。
my@laptop$ mysql --version
mysql Ver 14.14 Distrib 5.5.37, for debian-linux-gnu (i686) using readline 6.3
修改:
我正在寻找的结果是'给我表A中的所有ID,其中Id匹配B.SomeId或 ELSE Id匹配C.SomeId AND C.SomeValue等于'X'。
答案 0 :(得分:5)
OR
表达式通常会使MySQL难以使用索引。尝试更改为UNION
:
SELECT A.id
FROM A
JOIN B ON A.id = B.SomeID
UNION
SELECT A.id
FROM A
JOIN C ON A.id = C.SomeID
WHERE C.SomeValue = 'A'
最小化WHERE子句中的OR关键字。如果没有索引有助于在OR的两侧定位值,则任何行都可能是结果集的一部分,因此必须测试所有行,这需要全表扫描。如果您有一个索引有助于优化OR查询的一侧,而另一个索引有助于优化另一侧,请使用UNION运算符运行单独的快速查询并在之后合并结果。
您的查询由最后一句描述:OR
查询的每一侧都有不同的索引。
答案 1 :(得分:2)
让我们走得更小。假设你的表看起来像这样:
A.ID 1 2 B.SomeID 1 3 C.SomeID | C.SomeValue 1 | X 2 | X
现在,让我们看看你的查询会做什么。首先,我们查看A.ID匹配和B.SomeID是否匹配。在A.ID = 1的情况下,我们有一个匹配! Sql短路。这意味着如果or
的第一部分为真,则sql不会评估or
的第二部分。现在,我们仍然必须加入表C.由于没有连接条件,因此对于表C,sql将A.ID与表C中的所有列进行匹配。
现在我们需要将A.ID与B中的下一行进行比较。嗯,1<>所以,我们继续讨论or
的第二部分。当C.SomeID = 1时,包括该行。当C.SomeID = 2时,不包括该行。 A.ID = 1的结果是:
A.ID | B.SomeID | C.SomeID | C.SomeValue 1 | 1 | 1 | X 1 | 1 | 2 | X 1 | 3 | 1 | X
这显然不是您要寻找的结果表。由于您要使用表B或C加入A而不是or
,因此您应该使用union
SELECT A.Id FROM A, B
WHERE A.Id = B.SomeId
Union All
Select A.ID From A, C
Where A.Id = C.SomeId AND C.SomeValue = 'X'
Union all将第一个查询的结果放入与第二个查询的结果相同的结果表中。现在,您的问题是您只想要一个表中的A.ID而不是另一个表中的A.ID(或其他)。有几种方法可以做到这一点。在这种情况下,我将使用having
和子查询。您也可以使用not exists
,但我相信having
将使用更少的资源。
Select T.ID
From
(SELECT A.Id FROM A, B
WHERE A.Id = B.SomeId
Union All
Select A.ID From A, C
Where A.Id = C.SomeId AND C.SomeValue = 'X') T
Group By T.ID
Having count(1) = 1
我们只希望显示一次的ID。只有在B或C中不重复id时才会有效,所以请记住这一点。由于条件基于聚合函数count,因此该规定必须在having
。
答案 2 :(得分:0)
我在MySQL中并不强大,但我认为这会更好:
SELECT Id FROM
( SELECT A.Id FROM A, B
WHERE A.Id = B.SomeId
UNION
SELECT A.Id FROM A, C
WHERE A.Id = C.SomeId AND C.SomeValue = 'X'
) X
INTO OUTFILE '/tmp/result.txt';