2012-10-18 83 views
2

我有一個帶有組合鍵(REGION)和另一個引用該表的表(CITY)的表。插入,查詢和單個刪除操作很快。問題在於,當我嘗試使用sqlplus批量刪除CITY的內容時,從CITY中刪除它將需要永久。這個表格將有約400,000個條目,並且需要15-20分鐘才能刪除50,000條目。這裏是我使用Oracle 11的設置:Oracle複合鍵刪除速度很慢

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

你有沒有向Oracle詢問解釋計劃,看看它有什麼作用?你有'location.city'上的索引,因爲在刪除它之前,Oracle必須檢查一個城市沒有被某個位置引用。因此,由於位置表很大,如果您沒有這樣的索引,則需要花時間進行檢查。 –

回答

3

我的下注是該問題與組合鍵的存在無關,以及與未索引的外鍵有關的所有問題。

除非您已將其從您的問題中省略,否則LOCATION表中的CITY列未編制索引。這意味着每次您嘗試從CITY刪除一行時,Oracle必須對LOCATION表執行全表掃描,查找LOCATION中將被孤立以執行外鍵約束的行。一般來說,如果你想永遠從父項中刪除,子表中的外鍵需要被編入索引。所以LOCATION應該有兩個CITYCOUNTRY索引,CITY表應該有索引,對COUNTRY(regionCountry, regionCode)

即使所有從LOCATION行已被刪除,如果甲骨文必須做全表掃描上LOCATION ,它必須讀取表格的高水位標記。如果表格以前有250萬行,而您只是執行了DELETE,那麼您仍然需要閱讀,但是每次從CITY刪除一行時,需要存儲很多塊才能存儲這250萬行。

您可以測試我的預感是否正確在幾個不同的方式

  • 你可以索引在LOCATION表中的列CITY
  • 您可以刪除引用CITY表的LOCATION上的外鍵約束。
  • 您可以截取LOCATION表而不是刪除行,以便高位標記重置並且表掃描將花費更少的時間。
+0

我不確定這是否是問題,因爲我在嘗試刪除CITY表之前首先刪除了LOCATION表的內容。因此,我知道LOCATION表有0行,它仍然需要永久刪除CITY表。我希望這是答案,但除非甲骨文認爲LOCATION中還有行需要檢查,否則這並不合理。 –

+1

@MikeAdamakis - 我更新了我的答案。如果您只刪除了數據而不是截斷表格,則表格掃描仍然需要讀取高位標記,並且需要花費與表格有250萬行時相同的時間。 –

+0

它的工作原理:-)我首先截取了空的LOCATION表,並能夠快速完全刪除CITY表。然後,我將約200k個對象重新加載到LOCATION中,並將50k個對象重新加載到CITY中,並且能夠快速刪除CITY對象,解決了主要問題。學習了關於如何使用索引的好教訓。不幸的是,我對Oracle的信心震動,因爲我期望它足夠聰明,知道父表是否爲空,它不應該在父母的空白塊中查找子鍵 - 愚蠢的Oracle。謝謝一堆。 –