以下两个查询是子查询。两者都是一样的,两者都适合我。但问题是方法1查询需要大约10秒才能执行,而方法2查询需要不到1秒。
我能够将方法1查询转换为方法2,但我不明白查询中发生了什么。我一直试图弄清楚自己。我真的想了解下面两个查询之间的区别是什么以及性能增益是如何发生的?它背后的逻辑是什么?
我是这些先进技术的新手。我希望有人能在这里帮助我。鉴于我阅读的docs并没有给我一些线索。
方法1:
SELECT
*
FROM
tracker
WHERE
reservation_id IN (
SELECT
reservation_id
FROM
tracker
GROUP BY
reservation_id
HAVING
(
method = 1
AND type = 0
AND Count(*) > 1
)
OR (
method = 1
AND type = 1
AND Count(*) > 1
)
OR (
method = 2
AND type = 2
AND Count(*) > 0
)
OR (
method = 3
AND type = 0
AND Count(*) > 0
)
OR (
method = 3
AND type = 1
AND Count(*) > 1
)
OR (
method = 3
AND type = 3
AND Count(*) > 0
)
)
方法2:
SELECT
*
FROM
`tracker` t
WHERE
EXISTS (
SELECT
reservation_id
FROM
`tracker` t3
WHERE
t3.reservation_id = t.reservation_id
GROUP BY
reservation_id
HAVING
(
METHOD = 1
AND TYPE = 0
AND COUNT(*) > 1
)
OR
(
METHOD = 1
AND TYPE = 1
AND COUNT(*) > 1
)
OR
(
METHOD = 2
AND TYPE = 2
AND COUNT(*) > 0
)
OR
(
METHOD = 3
AND TYPE = 0
AND COUNT(*) > 0
)
OR
(
METHOD = 3
AND TYPE = 1
AND COUNT(*) > 1
)
OR
(
METHOD = 3
AND TYPE = 3
AND COUNT(*) > 0
)
)
答案 0 :(得分:47)
Explain Plan
会告诉您为什么要使用Exists
。通常问题来自Exists vs Count(*)
。 Exists
更快。为什么呢?
关于NULL提出的挑战:当子查询返回Null
时,对于IN,整个查询变为Null
。所以你也需要处理它。但是使用Exist
,它只是false
。更容易应对。简单地IN
无法与Null
进行比较,但Exists
可以。
e.g。 Exists (Select * from yourtable where bla = 'blabla');
当找到/匹配一个匹配时,你会得到真/假。
在这种情况下,IN
会根据Count(*)
选择WHERE
选择所有匹配行的位置,因为它会比较所有值。
但不要忘记这一点:
EXISTS
高速执行IN
:子查询结果非常大。IN
超前于EXISTS
:子查询结果非常小。参考了解更多详情:
答案 1 :(得分:3)
方法2很快,因为它使用EXISTS
运算符,其中MySQL
不会加载任何结果。
正如您在docs链接中所提到的那样,它忽略了SELECT
子句中的任何内容。它仅检查匹配条件的第一个值,一旦找到它设置条件TRUE
并移动以进行进一步处理。
另一方面,方法1有IN
运算符,它加载所有可能的值然后匹配它。仅当找到完全匹配时,条件才会设置TRUE
,这是一个耗时的过程。
因此你的方法2很快。
希望它有所帮助...
答案 2 :(得分:1)
EXISTS 运算符是一个布尔运算符,返回true或false。 subquery中经常使用EXISTS运算符来测试“ 存在”条件。
SELECT
select_list
FROM
a_table
WHERE
[NOT] EXISTS(subquery);
如果子查询返回任何行,则 EXISTS 运算符将返回true,否则将返回false。
此外, EXISTS 运算符一旦找到匹配的行,便立即终止进一步的处理。由于这种特性,在某些情况下,您可以使用 EXISTS 运算符来提高查询的性能。
否运算符将对 EXISTS 运算符求反。换句话说,如果子查询不返回任何行,则 NOT EXISTS 返回true,否则返回false。
您可以在子查询中使用 SELECT * , SELECT列, SELECT a_constant 。结果相同,因为MySQL忽略了 SELECT 子句中出现的 select_list 。
原因是 EXISTS 运算符基于“至少找到”原理工作。它返回true,并且一旦找到至少一个匹配的行,便停止扫描表。
另一方面,当 IN 运算符与子查询结合使用时,MySQL必须先处理子查询,然后使用子查询的结果来处理整个查询。
一般的经验法则是,如果子查询包含大量数据,则 EXISTS 运算符将提供更好的性能。
但是,如果子查询返回的结果集很小,则使用 IN 运算符的查询将执行得更快。
有关详细说明和示例:MySQL EXISTS - mysqltutorial.org
答案 3 :(得分:-2)