2

I have one table with a composite key (REGION) and another table (CITY) that references that table. Inserts, queries, and individual deletions work quickly. The problem is that when I try to bulk-delete the contents of CITY using sqlplus, delete from CITY, it takes forever. This table will have ~400,000 entries and it takes 15-20 minutes just to delete 50,000 entries. Here is my setup using 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);

The varchar2(32) fields are GUIDs. I know I should not use GUIDs as a PK but I cannot change that unless I have proof that this is the problem.

I can bulk-delete entries from LOCATION with no problem, 300,000 in a couple of seconds, so this leads me to believe it is the composite key that is giving me trouble.

The secondary issue is that I currently have two country columns in the CITY table - one linked directly to COUNTRY and the other linked as part of the composite key to REGION. I know how I would do this in code and only have one country column but I have to use Hibernate. This works the way it is except for the delete problem so I can't change it unless I can prove this is causing an issue. I'm using sqlplus to try the deletions so I know Hibernate is not causing the delete problem.

4

1 回答 1

3

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

除非您从问题中省略了它,否则表中的CITYLOCATION不会被索引。这意味着每次您尝试从 中删除一行时CITY,Oracle 都必须对表进行全表扫描,以LOCATION查找LOCATION将成为孤立行的行,以强制执行外键约束。通常,如果您想从父表中删除,则需要对子表中的外键进行索引。所以LOCATION应该在 and 上都有索引CITYCOUNTRYCITY应该在COUNTRYand上都有索引(regionCountry, regionCode),等等。

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

你可以用几种不同的方式测试我的预感是否正确

  • 您可以索引表CITY中的列LOCATION
  • LOCATION您可以删除引用CITY表的外键约束。
  • 您可以截断LOCATION表而不是删除行,以便重置高水位标记并且表扫描将花费更少的时间。
于 2012-10-18T21:50:45.550 回答