2011-11-02 76 views
4

这是一个我从未得到确切答案的问题。我在这个例子中使用MySQL。SQL性能:哪个更快? IN()与JOIN

给定一组相当大的值(可以说500)。它是更快地使用这些值与在寻找一个表()子句:

SELECT * FROM table WHERE field IN(values) 

或者通过在内存中创建一个临时表,用值填充,并将其加入到表被搜索:

CREATE TEMPORARY TABLE `temp_table` (`field` varchar(255) NOT NULL) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

INSERT INTO temp_table VALUES (values) 

SELECT * FROM table t1 JOIN temp_table t2 ON t1.field = t2.field 

两种方法都会产生相同的结果集。

我已经完成了一些我自己的基本基准测试,发现处理超过500个值时,使用临时表比IN()子句更快。

有人可以向我解释MySQL的内部工作原理以及这个问题的正确答案是什么?

感谢, 利奥

+0

请发布您的基准,以便对它们进行验证。你有领域的索引吗? –

+1

你知道答案很大程度上取决于数据库的结构吗?创建临时表,填充它并加入表涉及大量的CPU工作,与使用带有IN运算符的查询相反。由于内存存储IO会更快,但是InnoDB也可以将其工作数据集保存在内存中。如果你根据InnoDB表的主键进行'IN'搜索 - 它会胜过临时表。 –

+0

如果你也发布了解释计划,这将会很有趣。 –

回答

2

从MySQL在线文档,IN()

IN(值,...)

如果所有值都常数,他们是根据评估expr的类型和排序。 然后使用二进制搜索完成对项目的搜索。这意味着 如果IN值列表完全由常量组成,则IN非常快。 否则,根据第11.2节“表达式评估中的类型转换”, 中描述的规则 进行类型转换,但应用于所有参数。

考虑到我认为使用IN()和一组常量是有意义的,否则应该在另一个表上使用子查询。

你可以考虑usign EXISTS()而不是JOIN时,从其他表检索项,它会显著为快大型数据集

SELECT * 
FROM table t1 
WHERE EXISTS 
     (
     SELECT * 
     FROM temp_table t2 
     WHERE t1.field = t2.field 
    ) 
+0

我不明白二进制搜索位。为了这个工作,列需要被排序,因此可能被索引?那么为什么不从索引中查找呢? (除非它们表示搜索使用二进制排序语义而不是谈论实际[二进制搜索](http://en.wikipedia.org/wiki/Binary_search_algorithm) –

+0

@Martin Smith:二进制搜索(每个文档只用于常量)当一组常量被排序时是有意义的,所以这意味着服务器会进行排序,然后只执行二进制搜索 – sll

+0

啊我明白了,我在想另一种方式,所以MySQL做了全表扫描,然后在每个值的常量列表?如果列被索引,并且in子句中只有两个值,那么如何处理?几个索引查找肯定会更有效率? –

1

正确的答案取决于许多因素。

您已经完成了这项工作 - 如果您的基准测试告诉您使用临时表的速度更快,那么这就是要走的路。

如果更改硬件或显着改变模式,请记住再次进行基准测试。