SQL IN子句比单个查询慢

时间:2009-03-19 23:09:41

标签: sql mysql performance hibernate jpa

我在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的性能限制吗?

6 个答案:

答案 0 :(得分:11)

这是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应用于结果集,这会导致额外的无索引排序。

答案 1 :(得分:1)

如果您正在使用IN运算符,则与说:

没什么不同
(p.name = 'Joe' OR p.name = 'Jane' OR p.name = 'Bob' OR p.name = 'Alice')

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

答案 2 :(得分:1)

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

您是否对相关表格进行过分析?

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

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

答案 3 :(得分:0)

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

在名称列上有一个索引会有所帮助。

答案 4 :(得分:0)

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

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

我使用IN子句与数字键相当:

e.g。

抓住五个主要项目,所有子网站可以是:

$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查询生成数据树

答案 5 :(得分:0)

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

这是一个example of using in clause