【问题标题】:Any performance impact in Oracle for using LIKE 'string' vs = 'string'?使用 LIKE 'string' vs = 'string' 对 Oracle 的性能有何影响?
【发布时间】:2010-09-13 03:55:33
【问题描述】:

这个

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 - 查看解释计划

标签: sql performance oracle


【解决方案1】:

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

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

我提供了两个查询的执行计划的屏幕截图,即使用 like 子句但没有 % 的查询以及使用 like 子句和 % 的查询。

【讨论】:

  • 感谢您详细周到的回复。请知道我在这个问题上是在扮演魔鬼的拥护者;当你的意思是“=”时,使用 LIKE 绝对“感觉”是错误的。话虽如此-您的回答实际上是否表明使用 LIKE 很好?如果优化器以同样的方式处理它,那么就不会影响性能,也不会影响功能——那么“=”的意义何在?
【解决方案2】:

like 在形式上是相同的,如果你没有像$% 这样的字符,所以发现它具有相同的成本也就不足为奇了。

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

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

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

【讨论】:

    【解决方案3】:

    当您使用绑定变量时有一个明显的区别,您应该在 Oracle 中将其用于数据仓库或其他批量数据操作以外的任何事情。

    举个例子:

    SELECT * FROM SOME_TABLE WHERE SOME_FIELD LIKE :b1
    

    Oracle 直到执行时才知道 :b1 的值是 '%some_value%' 或 'some_value' 等,因此它会根据启发式方法对结果的基数进行估计并提出一个合适的计划可能适合也可能不适合 :b 的各种值,例如 '%A'、'%'、'A' 等。

    类似的问题也适用于等式谓词,但可能导致的基数范围更容易根据列统计信息或唯一约束的存在来估计。

    所以,就我个人而言,我不会开始使用 LIKE 作为 = 的替代品。优化器有时很容易被愚弄。

    【讨论】:

    • 好答案!当我读到这个问题时,这似乎很愚蠢,但我无法说出确切的原因。这是正确的答案。
    【解决方案4】:

    如果这是真的,我的问题是,为什么 曾经使用过“=”吗?

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

    【讨论】:

      【解决方案5】:

      LIKE '%WHATEVER%' 必须进行全索引扫描。

      如果没有百分比,那么它就像一个等于。

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

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

      【讨论】:

        【解决方案6】:

        你试过了吗?测试是唯一确定的方法。

        顺便说一句,这些语句都不能确定返回相同的行。试试看:

        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,除非您需要它的通配符功能。 (显然,在进行临时查询时,它可能没问题。)

        【讨论】:

        • 结果有何不同?我无权访问沙盒服务器来测试您的示例。
        • LIKE '%some_value%' 返回所有三个记录,= 'some_value' 仅返回第二个记录,LIKE 'some_value' 返回第一个和第三个记录。
        • LIKE 'some_value' 返回第一条和第三条记录。 = 'some_value' 也返回那些相同的记录。从逻辑上讲,它们将始终返回相同的记录集。 IIRC 当我写这个问题时,我正在生成一些动态 sql,我很生气必须根据用户选择的选项有条件地提供“=”或“LIKE”。因为它们总是会返回相同的结果,所以我想知道仅使用 LIKE 是否有不利之处。大卫奥尔德里奇的回答指出了很好的理由。
        【解决方案7】:

        查看EXPLAIN PLAN 两者。它们生成相同的执行计划,因此对于数据库来说,它们是相同的东西。

        您可以使用 = 来测试相等性,而不是相似性。如果您也在控制比较值,那么它并没有太大的区别。如果那是由用户提交的,那么 'apple' 和 'apple%' 会给你带来很大不同的结果。

        【讨论】:

        • 对于非常大的表,即使计划相同,LIKE 测试和 = 之间也可能存在明显的性能差异。但最好进行测试。
        • 是的,如果您使用绑定变量,那么优化器并不真正知道您将传递给它什么。因此,它不一定能针对仅在一侧使用通配符进行优化。 (当然,Oracle 可能已经解决了这个特性)。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-17
        • 2011-07-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多