与子查询EXISTS VS在 - MySQL的(Subqueries with EXISTS vs

2019-07-17 21:57发布

下面这两个查询是子查询。 两者都是相同的,都为我工作得很好。 但问题是方法1次的查询需要大约10秒,而方法2查询下1秒需要执行。

我能方法1个查询转换为方法2,但我不明白发生了什么在查询中。 我一直在试图找出自己。 我真的想了解什么是以下两个查询以及如何在性能增益发生之间的区别? 什么是其背后的逻辑是什么?

我是新来的这些进步的技术。 我希望有人能帮助我在这里。 鉴于我读文档不给我一个线索。

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

Answer 1:

一个Explain Plan将显示你到底为什么你应该使用Exists 。 通常情况下,问题来了Exists vs Count(*) Exists比较快。 为什么?

  • 对于目前由NULL挑战:当子查询返回Null ,在整个查询变得Null 。 所以,你需要处理这点。 但是,使用Exist ,它只是一个false 。 更容易应付。 只需IN无法比拟与任何Null ,但Exists即可。

  • 例如Exists (Select * from yourtable where bla = 'blabla'); 你真/假的那一刻一个找到命中/匹配

  • 在这种情况下, IN排序采取的位置Count(*)来选择基础上的所有匹配行WHERE ,因为它比较所有值。

但不要忘了这两种:

  • EXISTS在高速对抗执行IN :当子查询的结果是非常大的。
  • IN得到提前EXISTS :当子查询的结果是非常小的。

参考有关更多详细信息:

  • 子查询使用IN 。
  • IN -子查询优化
  • 加入与子查询 。


Answer 2:

方法二是快,因为它使用EXISTS运算符,其中我MySQL不加载任何结果。 正如你所提到的文档链接为好,因为它忽略了有没有以任何SELECT子句。 它仅用于匹配的条件的第一个值,支票一旦发现它设置条件TRUE和用于进一步处理移动。

在另一边方法1具有IN其中加载所有可能的值操作,然后进行匹配。 条件设置TRUE ,只有当发现完全匹配是耗时的过程。

因此,您的方法2是很快的。

希望能帮助到你...



Answer 3:

EXISTS操作是布尔逻辑运算符返回true或false。 操作员通常使用的在EXISTS的子查询 ,以测试一个“ 存在 ”状态。

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

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

此外,EXISTS操作会立即终止进一步的处理,一旦它找到一个匹配的行。 由于这个特点,你可以使用EXISTS操作,以提高在某些情况下,查询的性能。

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

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

其原因是,EXISTS的基础上,“至少发现”的原则经营者的作品。 它返回true,停止扫描表中的至少一个匹配行发现一次。

在另一方面,当IN操作符与子查询相结合,MySQL必须首先处理的子查询,然后使用子查询来处理整个查询的结果。

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

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

对于详细的解释和示例: MySQL的EXISTS - mysqltutorial.org



Answer 4:

第二种方法是更快,因为你有这个好像有“WHERE t3.reservation_id = t.reservation_id”。 在第一种情况下,你的子查询必须做一个完整的扫描到表中的信息进行验证。 然而在20方法的子查询确切地知道它在寻找,一旦发现被检查为条件,那么。



Answer 5:

他们的官方文档。 子查询优化与已存在



文章来源: Subqueries with EXISTS vs IN - MySQL