25

以下两个查询是子查询。两者都是一样的,对我来说都很好。但问题是方法 1 查询需要大约 10 秒才能执行,而方法 2 查询需要不到 1 秒。

我能够将方法 1 查询转换为方法 2,但我不明白查询中发生了什么。我一直试图自己弄清楚。我真的很想了解以下两个查询之间的区别以及性能提升是如何发生的?它背后的逻辑是什么?

我是这些先进技术的新手。我希望有人会在这里帮助我。鉴于我阅读了没有给我线索的文档。

方法一:

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 
         )
   )

方法二:

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
         )                                             
   )
4

5 回答 5

56

AnExplain Plan会告诉你为什么你应该使用Exists. 通常问题来了Exists vs Count(*)Exists是比较快的。为什么?

  • 关于 NULL 带来的挑战:当子查询返回时Null,对于 IN,整个查询变为Null。所以你也需要处理它。但是使用Exist,它只是一个false. 更容易应付。根本IN无法与任何东西相比,NullExists可以。

  • 例如,一旦找到/匹配Exists (Select * from yourtable where bla = 'blabla');了一次命中,您就会得到真/假。

  • 在这种情况下IN,排序会根据Count(*)选择所有匹配行的位置,WHERE因为它正在比较所有值。

但也不要忘记这一点:

  • EXISTSIN对: 当子查询结果非常大时高速执行。
  • IN领先EXISTS:当子查询结果非常小时。

更多详情参考:

于 2013-01-07T10:55:42.640 回答
4

方法 2 很快,因为它使用EXISTS运算符,我MySQL不加载任何结果。正如您的文档链接中提到的那样,它省略了SELECT子句中的任何内容。它只检查与条件匹配的第一个值,一旦找到它就会设置条件TRUE并移动以进行进一步处理。

另一方面,方法 1 具有IN加载所有可能值然后匹配它的运算符。仅在找到完全匹配时才设置条件TRUE,这是一个耗时的过程。

因此,您的方法 2 很快。

希望能帮助到你...

于 2013-01-07T06:14:40.587 回答
2

EXISTS运算符是返回 true 或 false 的布尔运算符。EXISTS 运算符通常用于子查询中以测试“<em>exist”条件。

SELECT 
    select_list
FROM
    a_table
WHERE
    [NOT] EXISTS(subquery);

如果子查询返回任何行,则EXISTS运算符返回 true,否则返回 false。

此外,一旦找到匹配的行, EXISTS运算符就会立即终止进一步的处理。由于此特性,您可以在某些情况下使用EXISTS运算符来提高查询的性能。

NOT运算符否定EXISTS运算符。换句话说,如果子查询没有返回行, NOT EXISTS返回 true,否则返回 false。

您可以在子查询中使用SELECT *SELECT columnSELECT a_constant或任何内容。结果是一样的,因为 MySQL 忽略了出现在SELECT子句中的select_list 。

原因是EXISTS运算符基于“至少找到”原则工作。一旦找到至少一个匹配的行,它就会返回 true 并停止扫描表。

另一方面,当IN运算符与子查询组合时,MySQL 必须先处理子查询,然后使用子查询的结果来处理整个查询。

一般的经验法则是,如果子查询包含大量数据,则EXISTS运算符提供更好的性能。

但是,如果从子查询返回的结果集非常小,则使用IN运算符的查询将执行得更快。

有关详细说明和示例:MySQL EXISTS - mysqltutorial.org

于 2018-09-20T08:04:37.940 回答
0

第二种方法更快,因为你有这样的“WHERE t3.reservation_id = t.reservation_id”。在第一种情况下,您的子查询必须对表进行全面扫描以验证信息。然而,在 2o 方法中,子查询确切地知道它在寻找什么,一旦找到它就会检查有条件。

于 2013-01-07T07:36:00.277 回答
-3

他们的官方文档。Exists 的子查询优化

于 2014-04-15T14:12:23.893 回答