编写此查询的更好/更有效的方法

时间:2013-12-17 20:00:20

标签: mysql sql

我正在尝试计算表中的记录数。 该表称为附属关系,只有4列(其中2列是外键)

我想计算附属列为0且business_id与特定account_email相关的记录数。

我知道如何使用IN关键字进行此查询,但我想知道是否有更好或更有效的方法来执行此操作。

这是查询的IN版本:

SELECT COUNT(1) FROM affiliations 
WHERE business_id IN (
    SELECT business_id 
    FROM affiliations 
    WHERE account_email = 'address@domain.ext'
) AND affiliated = 0

我知道我可以用EXISTS取代它:

SELECT COUNT(1) FROM affiliations 
WHERE EXISTS (
    SELECT 1 FROM affiliations 
    WHERE account_email = 'address@domain.ext'
) AND affiliated = 0

EXISTS的声明是否有效?如前所述,还有更好的方法吗?

提前致谢!

3 个答案:

答案 0 :(得分:1)

我使用exists,但还记得将子查询与主表相关联,如下所示。

SELECT COUNT(1) FROM affiliations a
WHERE exists (
    SELECT 1
    FROM affiliations a1
    WHERE account_email = 'address@domain.ext'
    and a1.business_id=a.business_id
) AND affiliated = 0

答案 1 :(得分:0)

IN子句的问题中的第一个查询与EXIST的第二个查询不等效。

要使用IN转换第一个查询,必须使用从属子查询:

SELECT COUNT(1) FROM affiliations a1
WHERE EXISTS (
    SELECT 1 FROM affiliations a2
    WHERE account_email = 'address@domain.ext'
      AND a1.business_id = a2.business_id
) AND affiliated = 0

注意这种情况:AND a1.business_id = a2.business_id

上述查询在语义上与您使用IN的第一个查询等效 它们的性能也是一样的,因为在最优化阶段,MySql在意图上转换为这种形式的条件:

outer_expr IN (SELECT inner_expr FROM ... WHERE subquery_where)

进入这个:

EXISTS (SELECT 1 FROM ... WHERE subquery_where AND outer_expr=inner_expr)

请参阅此链接以获取detalis:http://dev.mysql.com/doc/refman/5.0/en/subquery-optimization-with-exists.html
特别注意有关NULL值的讨论以及NULL如何影响优化器。

简而言之 - 如果business_id列声明为NOT NULL,则MySql可以优化这两个查询。
查看最终结论(在此链接的页面底部):

  

为了帮助查询优化器更好地执行查询,请使用以下提示:

     
      
  • 如果确实存在,则必须将列声明为NOT NULL。 (这也有助于优化器的其他方面。)

  •   
  • 如果您不需要将NULL与FALSE子查询结果区分开来,则可以轻松避免执行路径缓慢。替换看起来像这样的比较:

         

    outer_expr IN(SELECT inner_expr FROM ...)

         

    用这个表达式:

         

    (outer_expr IS NOT NULL)AND(outer_expr IN(SELECT inner_expr FROM ...))

         

    然后永远不会评估NULL IN(SELECT ...),因为只要表达式结果清除,MySQL就会停止评估AND部分。

  •   

答案 2 :(得分:-1)

使用JOIN而不是IN。如果你想要匹配很多值,那么IN的表现很糟糕

SELECT COUNT(1) 
FROM affiliations AS ABB2
    JOIN (SELECT business_id 
          FROM affiliations 
          WHERE account_email = 'address@domain.ext') AS ABB1
        ON ABB1.business_id = ABB2.business_id
WHERE affiliated = 0