Oracle复合键删除速度很慢

时间:2012-10-18 21:42:35

标签: oracle hibernate foreign-keys composite-key

我有一个带有复合键(REGION)的表和另一个引用该表的表(CITY)。插入,查询和单个删除工作很快。问题是当我尝试使用sqlplus批量删除CITY的内容时,从CITY中删除它需要永远。该表将有大约400,000个条目,删除50,000个条目需要15-20分钟。以下是使用Oracle 11的设置:

create table COUNTRY
(
  id varchar2(32) NOT NULL -- PK
...
);

create table REGION -- about 4000 entries
(
  country    varchar2(32) NOT NULL -- PK, FK to COUNTRY
  regionCode char(2)      NOT NULL -- PK
...
);

create table CITY -- about 400,000 entries
(
  id            number       NOT NULL -- PK
  country       varchar2(32) NOT NULL -- FK to COUNTRY
  regionCountry varchar2(32) NULL     -- FK to REGION
  regionCode    char(2)      NULL     -- FK to REGION
...
);

create table LOCATION -- about 2,500,000 entries
(
  id       varchar2(32) NOT NULL -- PK
  country  varchar2(32) NOT NULL -- FK to COUNTRY
  city     number       NULL     -- FK to CITY
...
);



ALTER TABLE COUNTRY ADD CONSTRAINT PK_COUNTRY PRIMARY KEY (id) USING INDEX;

ALTER TABLE REGION ADD CONSTRAINT PK_REGION PRIMARY KEY (country, regionCode) USING INDEX;

ALTER TABLE CITY ADD CONSTRAINT PK_CITY PRIMARY KEY (id) USING INDEX;

ALTER TABLE IPGeoLoc ADD CONSTRAINT PK_LOCATION PRIMARY KEY (id) USING INDEX;



ALTER TABLE REGION ADD CONSTRAINT FK_REGION_COUNTRY
   FOREIGN KEY (country) REFERENCES COUNTRY (id);

ALTER TABLE CITY ADD CONSTRAINT FK_CITY_COUNTRY
   FOREIGN KEY (country) REFERENCES COUNTRY (id);

ALTER TABLE CITY ADD CONSTRAINT FK_CITY_REGION
   FOREIGN KEY (regionCountry, regionCode) REFERENCES REGION (country, regionCode);

ALTER TABLE LOCATION ADD CONSTRAINT FK_LOCATION_COUNTRY
   FOREIGN KEY (country) REFERENCES COUNTRY (id);

ALTER TABLE LOCATION ADD CONSTRAINT FK_LOCATION_CITY
   FOREIGN KEY (city) REFERENCES CITY (id);

varchar2(32)字段是GUID。我知道我不应该使用GUID作为PK但我不能改变它,除非我有证据证明这是问题。

我可以毫无问题地批量删除LOCATION中的条目,在几秒钟内批量删除300,000条,所以这让我相信它是复合键给我带来麻烦。

第二个问题是我目前在CITY表中有两个国家/地区列 - 一个直接链接到COUNTRY,另一个链接作为REGION复合键的一部分。我知道如何在代码中执行此操作并且只有一个国家/地区列,但我必须使用Hibernate。除了删除问题之外,它的工作原理是这样的,所以我不能改变它,除非我能证明这是导致问题。我正在使用sqlplus来尝试删除,所以我知道Hibernate没有导致删除问题。

1 个答案:

答案 0 :(得分:3)

我的赌注是,问题与复合键的存在无关,而且与未编制索引的外键有关。

除非您从问题中省略了它,否则CITY表中的LOCATION列不会被编入索引。这意味着每次尝试从CITY删除行时,Oracle都必须在LOCATION表上执行全表扫描,以查找LOCATION中将成为孤立的行以便强制执行外键约束。通常,如果要从父项中删除,则需要为子表中的外键建立索引。因此LOCATION应该在CITYCOUNTRY上都有索引,CITY表应该有COUNTRY(regionCountry, regionCode)等索引。

即使LOCATION中的所有行都已被删除,如果Oracle必须在LOCATION上进行全表扫描,它也必须读取表格的高水位线。如果该表先前有250万行,而您刚刚执行了DELETE,那么每次从CITY删除行时,仍然需要读取许多块来存储这250万行。

您可以通过几种不同的方式测试我的预感是否正确

  • 您可以为CITY表格中的LOCATION列编制索引。
  • 您可以删除引用LOCATION表的CITY上的外键约束。
  • 您可以截断LOCATION表而不是删除行,以便重置高水位线并且表扫描将花费更少的时间。