为什么在 oracle12c 中删除和创建 PK 会使 PK 从 `all_indexes` 中消失?

Why dropping and creating a PK in oracle12c makes the PK disappear from `all_indexes`?

我正在尝试重置主键“hail mary”样式 - 删除并创建。

但是,之后,它从 all_indexes table 中消失了。

PK 似乎存在,因为行为是正确的:

  1. 再次尝试创建时,提示我只能创建一个主键。
  2. 此外,不能插入具有相同 ID 的 2 行 - 违反唯一约束。

脚本:

set echo on;
-- whenever sqlerror exit sql.sqlcode;
set timing on
SET LINESIZE 2000

create table MY_TABLE (
    date_col DATE DEFAULT SYSTIMESTAMP NOT NULL,
    id NUMBER(10) NOT NULL,
    hash NUMBER(19) DEFAULT '0' NOT NULL,
    value1 NUMBER(19) DEFAULT '0' NOT NULL,
    value2 NUMBER(19) DEFAULT '0' NOT NULL,
    CONSTRAINT MY_TABLE_PK PRIMARY KEY (date_col, id, hash)
);
-- Res: Table created.

CREATE INDEX MY_TABLE_I ON MY_TABLE (id, hash, date_col ASC);
-- Res: Index created.

select index_name from all_indexes where table_name = 'MY_TABLE' order by index_name;
-- Res: MY_TABLE_I, MY_TABLE_PK

ALTER TABLE MY_TABLE DROP primary key;
-- Res: Table altered.
ALTER TABLE MY_TABLE ADD CONSTRAINT MY_TABLE_PK PRIMARY KEY (date_col, id, hash);
-- Res: Table altered.
ALTER TABLE MY_TABLE ADD CONSTRAINT MY_TABLE_PK PRIMARY KEY (date_col, id, hash);
-- Res: ORA-02260: table can have only one primary key

insert into MY_TABLE values (SYSDATE, 1, 123456, 10, 20);
-- Res: 1 row created.
insert into MY_TABLE values (SYSDATE, 1, 123456, 10, 20);
-- Res: ORA-00001: unique constraint (ALIK.MY_TABLE_PK) violated

select index_name from all_indexes where table_name = 'MY_TABLE' order by index_name;
-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-- Res: !!!!! Just MY_TABLE_I !!!!!
-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

知道为什么 PK 游戏后 all_indexes 消失了吗?

数据库版本:12.1.0.2.0

干杯。

当您添加主键或唯一约束时,数据库会检查是否存在具有相同前导列的现有索引。如果有,数据库可以使用它。

即使索引列与约束的顺序不同,数据库也会这样做。因此,由于 MY_TABLE_I 具有与 PK 相同的列,因此数据库使用它。

如果你查看 *_constraints,你应该会发现 PK 使用索引 MY_TABLE_I:

select constraint_name, index_name
from   user_constraints
where  table_name = 'MY_TABLE' 
and    constraint_type = 'P';

CONSTRAINT_NAME    INDEX_NAME   
MY_TABLE_PK        MY_TABLE_I  

为避免这种情况,请使用 using index 子句来 define/specify 您希望 PK 使用的索引:

ALTER TABLE MY_TABLE 
  ADD CONSTRAINT MY_TABLE_PK 
  PRIMARY KEY (date_col, id, hash)
  USING INDEX ( 
    CREATE INDEX MY_TABLE_PK ON MY_TABLE (date_col, id, hash) 
  );

基本上,据我了解 Chris 所写的内容,另一个索引接管了 PKs 索引 - 尽管它的顺序不正确。

这意味着如果我查询,例如,仅通过 date_col,查询会很慢,因为它是接管的索引的最后一个参数。

另一个解决方案是在删除 PK 之前先删除具有一组类似于 PK 的值的任何索引。

所以,为了达到相同的状态,我需要删除索引,这样它就不会接管。示例:

DROP INDEX MY_TABLE_I;
-- Res: Index dropped.

ALTER TABLE MY_TABLE DROP primary key;
-- Res: Table altered.

ALTER TABLE MY_TABLE ADD CONSTRAINT MY_TABLE_PK PRIMARY KEY (date_col, id, hash);
-- Res: Table altered.

CREATE INDEX MY_TABLE_I ON MY_TABLE (id, hash, date_col ASC);
-- Res: Index created.

select index_name from all_indexes where table_name = 'MY_TABLE' order by index_name;
-- Res: MY_TABLE_PK and MY_TABLE_I