在Oracle中,使用LIKE 'string'与= 'string'相比会有任何性能影响吗?

17

这个

SELECT * FROM SOME_TABLE WHERE SOME_FIELD LIKE '%some_value%';

比这个慢

SELECT * FROM SOME_TABLE WHERE SOME_FIELD = 'some_value';

但是这个呢?

SELECT * FROM SOME_TABLE WHERE SOME_FIELD LIKE 'some_value';

我的测试表明第二个和第三个例子完全相同。如果是这样,那么我的问题是,为什么要使用"="?


1 - 运行了多次针对一个大表的语句,使用两种方法,并记录执行时间。2 - 查看了执行计划。 - JosephStyons
7个回答

21

如果你在 Oracle 中除了数据仓库或其他批量数据操作之外的任何操作中使用绑定变量,就会出现明显的差异。

举个例子:

SELECT * FROM SOME_TABLE WHERE SOME_FIELD LIKE :b1

Oracle不能在执行之前知道:b1的值是'%some_value%'、'some_value'等,因此它会根据启发式算法估计结果的基数,并提出一个适当的计划,这个计划可能适用于:b的各种值,如'%A'、'%'、'A'等。

使用等式谓词时可能存在类似的问题,但可能产生的基数范围更容易根据列统计信息或唯一约束的存在进行估计。

所以,个人认为我不会开始使用LIKE来替换=。有时优化器很容易被愚弄。


好的回答!当我读到这个问题时,它似乎很愚蠢,但我无法确切地指出原因。这是正确的答案。 - Jon Ericson

5

请查看执行计划。它们生成相同的执行计划,所以对于数据库来说,它们是相同的内容。

你应该使用=来测试等式,而不是相似性。如果你也控制比较值,那么差别不大。如果比较值由用户提交,则'apple'和'apple%'将给出非常不同的结果。


对于非常大的表,即使计划相同,LIKE测试和=之间可能会有明显的性能差异。但最好进行测试。 - Jon Ericson
是的,如果您使用绑定变量(正如您应该做的那样),优化器实际上不知道您将要传递给它什么。因此,它不能保证仅在一侧使用通配符进行优化(当然,Oracle可能已经解决了这个特性)。 - oglester

3
如果这是真的,我的问题是,为什么要使用“=”呢? 更好的问题是:如果这是真的,为什么要使用“LIKE”来测试相等性?你可以省下按Shift键的时间,每个阅读脚本的人都会感到困惑。

2

你尝试过吗?测试是唯一确保正确性的方法。

另外,这些语句中没有一个能够确保返回相同的行。可以尝试:

insert into some_table (some_field) values ('some_value');
insert into some_table (some_fieled) values ('1some_value2');
insert into some_table (some_field) values ('some1value');

SELECT * FROM SOME_TABLE WHERE SOME_FIELD LIKE '%some_value%';

SELECT * FROM SOME_TABLE WHERE SOME_FIELD = 'some_value';

SELECT * FROM SOME_TABLE WHERE SOME_FIELD LIKE 'some_value';

为了保证清晰度并避免细微的错误,最好不要使用LIKE,除非你需要使用通配符功能。(当然,在执行临时查询时,可能没问题。)

结果看起来有什么不同?我没有访问沙盒服务器来测试你的例子。 - Luke
LIKE '%some_value%' 返回所有三条记录,= 'some_value' 只返回第二条记录,LIKE 'some_value' 返回第一条和第三条记录。 - Keith Davies
LIKE 'some_value' 返回第一条和第三条记录。= 'some_value' 也返回相同的记录。从逻辑上讲,它们总是返回相同的记录集。我记得当我写这个问题时,我正在生成一些动态SQL,并且我很烦恼必须根据用户选择有条件地提供“=”或“LIKE”。由于它们将始终返回相同的结果,我想知道是否使用LIKE会有什么不利影响。David Aldridge的答案指出了很好的原因。 - JosephStyons
@JosephStyons:WHERE some_field = 'some_value'不会LIKE 'some_value'一样返回some1value,因为对于LIKE,下划线是任何字符的占位符。对于等号来说,它当然是一个字面值,因此不会返回该记录。试试看吧。 - Lemmes

1

使用“LIKE'%WHATEVER%'”将不得不进行完整的索引扫描。

如果没有百分号,那么它的作用就像等于号。

如果%在一端,则索引可以是范围扫描。

我不确定优化器如何处理绑定字段。


1

like 如果没有像 $% 这样的字符,那么它在形式上是相同的,因此发现它具有相同的成本并不令人惊讶。

我认为David Aldridge的答案很有趣,因为您的应用程序应该使用绑定变量。使用 like '%foobar' 时,您无法利用索引中的排序。如果查询是预编译的,则会导致更多的索引或表全扫描。

此外,我认为这很危险,因为它可能导致SQL注入和奇怪的错误(例如,如果有一个名为john的用户,黑客可以创建一个名为'joh$' 的用户并尝试登录)

为什么要冒险呢?'=' 更清晰,而且没有这些问题。


0

1) %和=旨在用于不同的情况。即使我们可以在like子句中使用精确值进行搜索并获得所需结果,但在所有这样的情况下仍应该使用=。因此,每当我们有精确值要搜索时,我们总是应该使用=。

2) 当搜索子句中没有提供%时,like和=的性能: 在所有这些情况下,查询优化器会自动将like子句转换为=。这可以从查询计划中看到(请参见附加的屏幕截图)。因此,在这种情况下,性能应该完全相同。感谢查询优化器!

我提供了两个查询的执行计划的屏幕截图,即带有like子句但不含%的查询和带有like子句且包含%的查询。

like Cluase with % query execution plan

like clause without % query execution plan


感谢您详细而周到的回复。请知道,我在这个问题上有点像是在玩弄魔鬼的辩护人;当你想要使用“=”时,确实会感觉不对劲。话虽如此——难道您的答案并不是表明使用LIKE是可以的吗?如果优化器以相同的方式处理它,那么就没有性能影响和功能影响——那么“=”的意义何在呢? - JosephStyons

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接