【问题标题】:Oracle doesn't use index on varchar2 column in case of of order by clause在 order by 子句的情况下,Oracle 不在 varchar2 列上使用索引
【发布时间】:2015-03-24 10:23:54
【问题描述】:

这是我的几百万行的表格:

  CREATE TABLE "TEST_TABLE"
  ( "ID" NUMBER(*,0),
    "TYPE" NUMBER(*,0),
    "NAME" VARCHAR2(10 BYTE)
  );

还有几个索引:

   CREATE INDEX TEST_INDEX_T_N ON TEST_TABLE (TYPE, NAME);
   CREATE INDEX TEST_INDEX_T_I ON TEST_TABLE (TYPE, ID);

以下查询时

   SELECT * FROM TEST_TABLE WHERE TYPE = 1 ORDER BY ID

我有以下计划

   |   0 | SELECT STATEMENT |                |   886K|    21M|  2192   (1)| 00:00:27 |
   |*  1 |  INDEX RANGE SCAN| TEST_INDEX_T_I |   886K|    21M|  2192   (1)| 00:00:27 |

但是,如果出现以下情况:

   SELECT NAME FROM TEST_TABLE WHERE TYPE = 1 ORDER BY NAME;

我明白了

   |   0 | SELECT STATEMENT  |                |   886K|    16M|       |  7826   (1)| 00:01:34 |
   |   1 |  SORT ORDER BY    |                |   886K|    16M|    23M|  7826   (1)| 00:01:34 |
   |*  2 |   INDEX RANGE SCAN| TEST_INDEX_T_N |   886K|    16M|       |  2415   (1)| 00:00:29 |

所以,据我了解,oracle 不使用索引对 varchar 列进行排序(因为说明计划中有额外的 SORT ORDER BY 操作),但在 INT 或 DATE 类型的情况下一切都很好。如何“使用索引进行排序”varchar 列?

【问题讨论】:

  • 为什么要 Oracle 使用索引进行排序?当 Oracle 必须对结果集进行排序时,内存或 TEMP 表空间中的所有内容都已可用。无需从光盘中读取任何其他内容。
  • 请注意,您认为它不适用于 varchars 的建议是不正确的。我试图重现你的情况(但是在更小的集合上,比如 100k 行),对于按 NAME 排序的第二个查询,我正在为第一个查询制定像你一样的计划,即只有 select 语句和 INDEX RANGE SCAN by test_index_t_n跨度>
  • @Wernfried 因为它要快得多。在以下查询 SELECT * FROM TEST_TABLE WHERE TYPE = 1 ORDER BY ID 的情况下,在我的特定情况下(在开发人员机器上,表中有 10.000.000 条记录,结果集中有 1000.000 条记录),速度要快 50 倍。
  • @Mina 你能展示你的初始化脚本吗?
  • @san DDL 与您的完全一样,然后我用示例数据填充了表格,其中前两列是随机数 1-500,第三列是五个预定义字符串之一。肯定它不符合您的情况,但只是为了证明执行计划非常依赖数据。

标签: oracle indexing sql-order-by


【解决方案1】:

如果 TYPE 的不同值非常少,那么优化器可能会计算出只执行表的完整扫描并对结果进行排序会更快,而不是通过索引读取大部分表。

Oracle 可以使用索引为字符列提供有序排序,但您还必须考虑 ORDER BY 是二进制(即根据 ASCII 或其他字符代码)还是语言(因语言而异)。您可能必须使用将匹配 NLS 语言排序顺序的特定 NLS 参数创建索引,或修改 ORDER BY 以使其基于文本的二进制代码。

您应该采取的方法取决于您是否在文本中使用非 ASCII 字符集,甚至可能您是否关心大小写字符的正确排序。

【讨论】:

  • DavidAldridge @Wernfried 谢谢。在 TEST_TABLE(TYPE, NLSSORT(NAME, 'NLS_SORT=BINARY')) 上创建索引 FOOBAR; SELECT * FROM TEST_TABLE WHERE TYPE = 3 ORDER BY NLSSORT(NAME, 'NLS_SORT = BINARY');
【解决方案2】:

当您执行ORDER BY NAME 时,实际顺序可能会因您当地的NLS_SORTNLS_COMP 设置而异。因此,索引内的顺序可能与您的输出顺序不同。对于任何DATENUMBER 数据类型,ASCDESC 的顺序总是 相同,并且很可能与内部组织的索引相同。

【讨论】:

    猜你喜欢
    • 2018-04-29
    • 1970-01-01
    • 2018-10-04
    • 2011-09-15
    • 1970-01-01
    • 2015-09-06
    • 1970-01-01
    • 2021-07-06
    • 1970-01-01
    相关资源
    最近更新 更多