【问题标题】:How to avoid Full Table Scan with LIKE operator如何避免使用 LIKE 运算符进行全表扫描
【发布时间】:2015-05-15 11:07:37
【问题描述】:

我在使用不同的正确查询更改 PL/SQL oracle 中的查询时遇到问题。当前查询:

SELECT MAX (workzone)
           FROM sccd_device_uim_tab
          WHERE NAME LIKE 18075009 || '%';

我的客户需要修改查询,因为:

Full table with a % should definitely be avoided.

这个问题有什么解决办法?

提前致谢


从包中添加查询

PROCEDURE sccd_get_impactservice_manual (
      in_faultid          IN       VARCHAR2,
      in_deviceid         IN       VARCHAR2,
      in_status           IN       VARCHAR2,
      in_opendate         IN       DATE,
      in_closedate        IN       DATE,
      out_impact_result   OUT      tcur,
      out_count_service   OUT      NUMBER,
      out_workzone        OUT      VARCHAR2,
      p_ret_char          OUT      VARCHAR2,
      p_ret_number        OUT      NUMBER,
      p_ret_msg           OUT      VARCHAR2
   )
   IS
   BEGIN
      SELECT orauser.ossa_get_sto_from_device (in_deviceid)
        INTO out_workzone
        FROM DUAL;

      IF out_workzone IS NULL
      THEN
         SELECT MAX (workzone)
           INTO out_workzone
           FROM sccd_device_uim_tab
          WHERE NAME = in_deviceid; --//this is I try to solve
          --WHERE NAME LIKE in_deviceid || '%'; //this is the current issue
      END IF;

【问题讨论】:

  • 您需要提供更多详细信息。 NAME 列的数据类型是什么?似乎是一个 varchar2,但你正在将它与一个数字进行比较。所以,解释一下。当您说正在进行全表扫描时,请发布执行计划。是否涉及任何索引?如果它是一个 NUMBER 列,那么使用 LIKE 是没有意义的。您正在强制进行隐式数据类型转换。对于数字,请使用 RANGE 比较,而不是 LIKE。
  • 感谢您回答我的问题,为什么我们使用 like 因为 18075009 的类型不是数字,它也是 varchar2 和列名称。
  • 你得到什么错误信息?
  • 我很惊讶,它以前如何使用 WHERE NAME LIKE 18075009 || '%'; 是一个语法错误
  • WHERE NAME LIKE in_deviceid || '%' 如果列上有索引,您应该看到索引扫描而不是全表扫描。看我的回答。

标签: sql oracle indexing sql-like full-table-scan


【解决方案1】:

在_deviceid 中命名的位置 || '%';

绝对应避免使用带有 % 的完整表。

你错了。当您使用 LIKE 运算符作为'STRING-%' 时,如果列上有任何索引,Oracle 将执行 INDEX SCAN。随着统计数据的更新,您应该不会看到全表扫描

我们来看一个测试用例:

SQL> CREATE TABLE emp_new AS SELECT ename FROM emp;

Table created.

SQL>
SQL> EXEC DBMS_STATS.gather_table_stats('LALIT', 'EMP_NEW');

PL/SQL procedure successfully completed.

SQL>

LIKE ename||'%' : 没有索引:

SQL> EXPLAIN PLAN FOR
  2  SELECT * FROM emp_new WHERE ename LIKE ename||'%';

Explained.

SQL>
SQL> SELECT * FROM TABLE(dbms_xplan.display);

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------
Plan hash value: 565523140

-----------------------------------------------------------------------------
| Id  | Operation         | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |         |     2 |    12 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| EMP_NEW |     2 |    12 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------

   1 - filter("ENAME" LIKE "ENAME"||'%')

13 rows selected.

SQL>

所以,正如预期的那样,Oracle 会进行全表扫描。

LIKE ename||'%' : WITH 索引:

SQL> CREATE INDEX idx_nm ON emp_new(ename);

Index created.

SQL>
SQL> EXEC DBMS_STATS.gather_table_stats('LALIT', 'EMP_NEW');

PL/SQL procedure successfully completed.

SQL>
SQL> EXPLAIN PLAN FOR
  2  SELECT * FROM emp_new WHERE ename LIKE ename||'%';

Explained.

SQL>
SQL> SELECT * FROM TABLE(dbms_xplan.display);

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
Plan hash value: 848277793

---------------------------------------------------------------------------
| Id  | Operation        | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT |        |     2 |    12 |     1   (0)| 00:00:01 |
|*  1 |  INDEX FULL SCAN | IDX_NM |     2 |    12 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------

   1 - filter("ENAME" LIKE "ENAME"||'%')

13 rows selected.

SQL>

因此,您可以清楚地看到正在使用的索引。

【讨论】:

  • 感谢您的回答,但似乎很难理解 :)
  • @Koyix,不客气。请将其标记为已回答,它将对其他人有所帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-04
  • 1970-01-01
  • 2019-07-17
相关资源
最近更新 更多