【问题标题】:SQL IN clause slower than individual queriesSQL IN 子句比单个查询慢
【发布时间】:2010-10-14 10:41:13
【问题描述】:

我在 MySQL 5.0.67 中使用 Hibernate 的 JPA 实现。 MySQL 配置为使用 InnoDB。

在执行 JPA 查询(转换为 SQL)时,我发现使用 IN 子句比执行单个查询要慢。示例:

SELECT p FROM Person p WHERE p.name IN ('Joe', 'Jane', 'Bob', 'Alice')

比四个单独的查询慢:

SELECT p FROM Person p WHERE p.name = 'Joe'
SELECT p FROM Person p WHERE p.name = 'Jane'
SELECT p FROM Person p WHERE p.name = 'Bob'
SELECT p FROM Person p WHERE p.name = 'Alice'

这是为什么?这是 MySQL 的性能限制吗?

【问题讨论】:

    标签: sql mysql performance hibernate jpa


    【解决方案1】:

    如果先获取值,然后将值嵌入到 in 子句中,而不是将 sql 查询嵌入到 sql 语句中,则可以使 in 子句更快

    这是example of using in clause

    【讨论】:

      【解决方案2】:

      对我来说,因为 IN 子句可以释放数据库和表以供其他连接使用,并且使用它对应用程序结构有好处,所以 IN 子句是一个非常宝贵的工具,即使与单个连接有轻微的延迟查询。

      我构建的几乎每个 PHP/MySQL 应用程序都使用了以下技术。

      我在 IN 子句中经常使用数字键:

      例如

      抓取五个主项,所有子项可以是:

      $master_arr = mysql_query(
       select * from master table where master_id in (1,7,9,10)
      );
      

      然后:

      $subitem_arr = mysql_query(
         select * from subitems table where par_master_id in (1,7,9,10)
      );
      

      将子数组添加到主项:

      foreach($subitem_arr AS $sv){
           $m_key = $sv['par_master_id'];
           $s_key = $sv['subitem_id'];
           $master_arr[$m_key]['subitem'][$s_key] = $sv;
      }
      

      这做了两件事: 1.) 表不是通过连接同时保持的 2.) 只有两个 mysql 查询产生一棵数据树

      【讨论】:

        【解决方案3】:

        像 IN 演示的那样简单的查询不应该有优化器选择使用索引的问题。 Bill 提到的 UNION 工作只是在您有更复杂的查询时才偶尔需要。这可能是索引统计的问题。

        您是否对相关桌子进行了分析?

        表中有多少行,有多少行匹配IN子句?

        EXPLAIN 对有问题的查询说了什么?

        【讨论】:

          【解决方案4】:

          这是 MySQL 中的一个已知缺陷。

          确实,使用UNION 比您展示的范围查询执行得更好。对于使用IN (...) 的表达式,MySQL 不会非常智能地使用索引。 OR 的布尔表达式的优化器中存在类似的漏洞。

          请参阅http://www.mysqlperformanceblog.com/2006/08/10/using-union-to-implement-loose-index-scan-to-mysql/ 了解一些解释和详细的基准。

          优化器一直在改进。一个版本的 MySQL 的缺陷可能会在后续版本中得到改进。因此,值得在不同版本上测试您的查询。

          使用UNION ALL 而不是简单的UNION 也是有利的。两个查询都使用临时表来存储结果,但不同之处在于UNIONDISTINCT 应用于结果集,这会导致额外的未索引排序。

          【讨论】:

          • SQL Server有这个缺陷吗?
          • 我不是 SQL Server 用户,所以我不知道答案。最好的办法是在查询分析器中尝试两种查询形式,并使用“显示执行计划”菜单选项。
          • 不,SQL Server 没有这个问题
          • 我见过 SQL Server 也有同样的问题。每一行总是有一个例外。我肯定看到联合而不是 IN 的执行时间更快。我给微软 SQL 团队的一位朋友发了电子邮件,他证实有时这可能是真的,但总的来说,OR 子句非常慢......并且联合允许多个处理器/线程。 a) Select * From Employers Where Employee_ID IN (3,5) vs b) select * From Employers Where Employee_ID = 3 union all Select * from Employers Where Employee_ID = 5
          • 谢谢@Aaron Kempf,这很有趣。这是微软的优势之一。在 MySQL 中,给定的查询只使用一个线程。
          【解决方案5】:

          您是在测量挂钟时间还是查询执行时间?我的猜测是,四个单独查询中每一个的实际执行时间加起来可能少于执行 IN 查询的时间,但四个查询的总挂钟时间会长得多。

          在名称列上建立索引会有所帮助。

          【讨论】:

          • 我正在测量总运行时间。
          【解决方案6】:

          如果您使用的是 IN 运算符,这与说:

          (p.name = 'Joe' OR p.name = 'Jane' OR p.name = 'Bob' OR p.name = 'Alice')
          

          对于查询必须考虑的每一行,必须检查这四个条件。当然,您引用的每个其他查询只有一个条件。我不相信在大多数实际场景中执行四个这样的查询会更快,因为您必须考虑客户读取结果集并对其进行处理所花费的时间。在这种情况下,IN 看起来很不错;如果它可以使用索引就更好了。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2016-04-25
            • 2014-01-02
            • 2015-02-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-06-13
            相关资源
            最近更新 更多