【问题标题】:Creating a function based Index in Oracle DB using comparison operator使用比较运算符在 Oracle DB 中创建基于函数的索引
【发布时间】:2018-08-29 03:38:44
【问题描述】:

我使用的是 Oracle DB(Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production),我的表定义是这样的:

Create table CardInfo (
Id Number not null,
BalanceInfo Decimal,
...
...
);

很多时候这个表会被这样查询:

select Id, ... from CardInfo where BalanceInfo > 0;

所以,我正在尝试创建一个这样的基于函数的索引:

CREATE INDEX balance_ix ON CardInfo (BalanceInfo > 0);

但是,上面的语句给出了以下错误:

从第 1 行开始的错误命令 -
CREATE INDEX balance_ix ON CardInfo (BalanceInfo > 0);
错误报告 -
ORA-00907: 缺少右括号
00907. 00000 - “缺少右括号”
原因:
行动:

所以我将我的创建索引语句更改为:

CREATE INDEX balance_ix ON CardInfo (BalanceInfo);

这执行得很好并创建了索引。但是,当我像这样为我的 sql 语句执行 Explain Plan 时:

EXPLAIN PLAN 
  SET statement_id = 'ex_plan1' FOR
SELECT * FROM CardInfo WHERE BalanceInfo > 0;;

SELECT PLAN_TABLE_OUTPUT 
  FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, 'ex_plan1','BASIC'));

它产生了以下输出:

计划哈希值:97071123

-------------------------------------------
| Id  | Operation         | Name          |
-------------------------------------------
|   0 | SELECT STATEMENT  |               |
|   1 |  TABLE ACCESS FULL| CardInfo      |
-------------------------------------------

这意味着它没有使用我创建的索引。

有人可以帮忙吗,我怎样才能创建一个索引以便我的 sql 语句使用它? 提前致谢。

【问题讨论】:

  • BalanceInfo 似乎是一个数字列,因为您将它与零进行比较。为什么不使用普通索引来索引 BalanceInfo?在 CardInfo(BalanceInfo) 上创建索引 CardInfoIdx;如果您有大量满足 BalanceInfo > 0 的值,则 FTS 优于 Index Scan。
  • Wernfried Domscheit 的回答中隐藏了您问题的简短答案。即:假设大部分时间里相对较高比例的余额大于零(因为它们在现实生活中),你总是会得到全表扫描。为什么?因为当表中相对较大的部分(例如,超过 20%)的行满足 WHERE 子句时,使用索引的效率

标签: database oracle indexing oracle12c


【解决方案1】:

如果你坚持使用基于函数的索引,那么你可以使用

CREATE INDEX balance_ix ON CardInfo ( SIGN(BalanceInfo) );

SIGN(BalanceInfo) 的结果可以是 -1、0 和 1。

但是,除非您创建 BITMAP 索引(即 CREATE BITMAP INDEX ...,否则 Oracle 将几乎不会使用它,因为该索引具有基数。但创建 BITMAP 索引也会产生其他影响。

另一种方法是创建一个分区表(列表或范围分区)。 BalanceInfo = 0 一个分区,其余的一个分区。会是这样的:

CREATE TABLE CardInfo (
    ID NUMBER NOT NULL,
    BalanceInfo DECIMAL)
PARTITION BY LIST (BalanceInfo) (
    PARTITION P_zero_balance VALUES (0) INDEXING OFF,
    PARTITION P_other_balances VALUES (DEFAULT)
    )
ENABLE ROW MOVEMENT;

CREATE INDEX CARDINFO_BalanceInfo ON CARDINFO (BalanceInfo) LOCAL INDEXING PARTIAL;

注意,你不需要为常量值(即BalanceInfo = 0)创建索引条目,所以我设置了INDEXING OFF

如果你更喜欢 RANGE 分区,你可以使用

CREATE TABLE CARDINFO (
    ID NUMBER NOT NULL,
    BalanceInfo DECIMAL)
PARTITION BY RANGE (BalanceInfo) (
    PARTITION P_negative_balances VALUES LESS THAN (0),
    PARTITION P_zero_balance VALUES LESS THAN (0.001) INDEXING OFF,
    PARTITION P_positive_balances VALUES LESS THAN (MAXVALUE)
    )
ENABLE ROW MOVEMENT;

CREATE INDEX CARDINFO_BalanceInfo ON CARDINFO (BalanceInfo) LOCAL INDEXING PARTIAL;

【讨论】:

  • 您好,感谢您的回复。我尝试使用建议的第二种方法,但无法弄清楚如何为 BalanceInfo = 0 创建分区。在此 linkCREATE INDEX cost_ix ON sales (amount_sold) GLOBAL PARTITION BY RANGE (amount_sold) (PARTITION p1 VALUES LESS THAN (1000), PARTITION p2 VALUES LESS THAN (2500), 中,但如何创建大于和其他分区的分区以获取价值等于 0 ?
猜你喜欢
  • 2016-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-04
  • 2017-02-22
相关资源
最近更新 更多