假设我有一个表,其中一列的取值范围是1到10。我需要选择除了9和10之外的所有值。如果我使用以下查询语句,是否会有性能方面的差异:
SELECT * FROM tbl WHERE col NOT IN (9, 10)
还有这一个呢?
SELECT * FROM tbl WHERE col IN (1, 2, 3, 4, 5, 6, 7, 8)
假设我有一个表,其中一列的取值范围是1到10。我需要选择除了9和10之外的所有值。如果我使用以下查询语句,是否会有性能方面的差异:
SELECT * FROM tbl WHERE col NOT IN (9, 10)
还有这一个呢?
SELECT * FROM tbl WHERE col IN (1, 2, 3, 4, 5, 6, 7, 8)
使用"IN",因为它很可能会让DBMS使用相应列上的索引。
"NOT IN"理论上也可以被转换为索引使用,但这种方式更加复杂,DBMS可能不会花费额外的开销时间进行使用。
IN
版本只有 NOT IN
版本的 1% 成本。此外,NOT IN
查询还抱怨缺失索引。你可能认为优化器应该足够聪明以识别等价性,但显然并不是这样。IN
胜利! - MarredCheese关于性能问题,您应该始终对代码进行剖析(即运行查询数千次,并使用某种秒表
来测量每个循环的性能。 示例)。
但是在这里,我强烈建议使用第一个查询以便更好地进行未来的维护。逻辑是您需要所有记录,但不包括9和10。如果您将值11添加到表中并使用第二个查询,则应用程序的逻辑将被破坏,这将导致错误。
编辑:我记得这被标记为php语言,所以我提供了php语言的示例,但我可能错了。我猜重写到您所使用的语言不会很难。
我发现如果列是可空的,Oracle在优化某些NOT IN查询时会遇到问题。如果您可以两种方式编写查询,则我认为IN更好。
对于常量列表,MySQL 将在内部将您的代码扩展为:
SELECT * FROM tbl WHERE ((col <> 9 and col <> 10))
对于另一个,同样使用 8 次 =
。
所以是的,第一个会更快,需要比较的次数更少。然而,可测量的机会几乎可以忽略不计,因为与解析 SQL 和检索数据的一般开销相比,少量常量比较的开销微不足道。
IN
操作是通过对列表进行二进制搜索来实现的,而不是8个=
比较。 - Martin SmithIN
"语句在内部的工作方式类似于一系列的"OR"语句。例如:
SELECT * FROM tbl WHERE col IN (1, 2, 3)
它等于
SELECT * FROM tbl WHERE col = 1 OR col = 2 OR col = 3
“OR”语句可能会导致一些性能问题,正如这篇文章所解释的那样: https://bertwagner.com/2018/02/20/or-vs-union-all-is-one-better-for-performance/
当你使用NOT IN语句时,情况都是一样的,但结果具有逻辑否定。但是,您可以编写一个性能更好的等效查询。在您的示例中:
"SELECT * FROM tbl WHERE col NOT IN (9, 10)
它等于
SELECT * FROM tbl WHERE col <> 9 AND col <> 10
使用“AND”语句时,当所有条件中的一个为假时,数据库停止分析,因此,在“IN”语句中使用“OR”比“AND”在性能上要好得多。
true
,则 AND
链必须继续,而 OR
链则会立即停止。 - Onno Rouast
col1
的覆盖索引,则我更喜欢使用BETWEEN
而不是IN
。 - Martin Smith