天天看點

遠端資料庫的表超過20個索引的影響

昨天同僚參加了一個研讨會,有提到一個案例。一個通過dblink查詢遠端資料庫,原來查詢很快,但是遠端資料庫增加了一個索引之後,查詢一下子變慢了。

經過分析,發現那個通過dblink的查詢語句,查詢遠端資料庫的時候,是走索引的,但是遠端資料庫添加索引之後,如果索引的個數超過20個,就會忽略第一個建立的索引,如果查詢語句恰好用到了第一個建立的索引,被忽略之後,隻能走Full Table Scan了。

聽了這個案例,我查了一下,在oracle官方文檔中,關于Managing a Distributed Database有一段話:

說到,如果遠端資料庫使用超過20個索引,這些索引将不被考慮。這段話,在oracle 9i起的文檔中就已經存在,一直到12.2還有。

那麼,超過20個索引,是新的索引被忽略了?還是老索引被忽略了?如何讓被忽略的索引讓oracle意識到?我們來測試一下。

初始化測試表

遠端資料庫的表超過20個索引的影響

可以看到,遠端表有27個字段,目前還隻是在前20個字段建立了索引,且第一個字段是主鍵。本地表,有6個字段,6個字段都建索引。

第一輪測試,遠端表上有20個索引

測試場景1:

在遠端表20索引的情況下,本地表和遠端表關聯,用本地表的第一個字段關聯遠端表的第一個字段:

遠端資料庫的表超過20個索引的影響

我們可以看到,對于遠端表的執行計劃,這是走主鍵的。

測試場景2:

在遠端表20索引的情況下,本地表和遠端表關聯,用本地表的第一個字段關聯遠端表的第20個字段:

遠端資料庫的表超過20個索引的影響

我們可以看到,對于遠端表的執行計劃,這是走索引範圍掃描的。

測試場景3:

在遠端表20索引的情況下,本地表和遠端表關聯,用本地表的第2個字段關聯遠端表的第2個字段:

遠端資料庫的表超過20個索引的影響

測試場景4:

在遠端表20索引的情況下,本地表和遠端表關聯,用本地表的第2個字段關聯遠端表的第20個字段:

遠端資料庫的表超過20個索引的影響

建立第21個索引

遠端資料庫的表超過20個索引的影響

重複上面4個測試

遠端資料庫的表超過20個索引的影響

我們可以看到,對于遠端表的執行計劃,如果關聯條件是遠端表的第一個字段,第一個字段上的索引是被忽略的,執行計劃是選擇全表掃描的。

遠端資料庫的表超過20個索引的影響

我們可以看到,對于遠端表的執行計劃,如果關聯條件是遠端表的第20個字段,這第20個字段上的索引是沒有被忽略的,執行計劃是走索引。

遠端資料庫的表超過20個索引的影響

我們可以看到,對于遠端表的執行計劃,如果關聯條件是遠端表的第2個字段,這第2個字段上的索引是沒有被忽略的,執行計劃是走索引。

遠端資料庫的表超過20個索引的影響

我們目前可以總結到,當遠端表第21個索引建立的時候,通過dblink關聯本地表和遠端表,如果關聯條件是遠端表的第1個建立的索引的字段,那麼這個索引将被忽略,進而走全表掃描。如果關聯條件是遠端表的第2個建立索引的字段,則不受影響。

似乎是有效索引的視窗是20個,當建立第21個,那麼第1個就被無視了。

建立第22個索引,驗證上述猜測

遠端資料庫的表超過20個索引的影響

再次重複上面4個測試

遠端資料庫的表超過20個索引的影響
遠端資料庫的表超過20個索引的影響
遠端資料庫的表超過20個索引的影響

上述的測試,其實是可以驗證我們的猜測的。oracle對于通過dblink關聯通路遠端表,隻是會意識到最近建立的20個索引的字段。這個意識到索引的視窗是20個,一旦建立了一個新索引,那麼最舊的一個索引會被無視。

嘗試rebuild索引

rebuild第2個索引

遠端資料庫的表超過20個索引的影響

重複上面測試

遠端資料庫的表超過20個索引的影響

是以我們看到,索引rebuild,是不能起到重新“喚醒”索引的作用。

嘗試 drop and recreate 第2個索引

遠端資料庫的表超過20個索引的影響

重複上面的測試3和測試4

遠端資料庫的表超過20個索引的影響

我們可以看到,通過drop之後再重建,是可以“喚醒”第二個索引的。這也證明了我們20個索引識别的移動視窗,是按照索引的建立時間來移動的。

對于通過dblink關聯本地表和遠端表,如果遠端表的索引個數少于20個,那麼不受影響。

 對于通過dblink關聯本地表和遠端表,如果遠端表的索引個數增加到21個或以上,那麼oracle在執行遠端操作的時候,将忽略最早建立的那個索引,但是會以20個為視窗移動,最建立立的索引會被意識到。此時如果查詢的關聯條件中,使用到最早建立的那個索引的字段,由于忽略了索引,會走全表掃描。

要“喚醒”對原來索引的意識,rebuild索引無效,需要drop & create索引。

在本地表資料量比較少,遠端表的資料量很大,而索引數量超過20個,且關聯條件的字段時最早索引的情況下,可以考慮使用DRIVING_SITE的hint,将本地表的資料全量到遠端中,此時遠端的關聯查詢可以意識到那個索引。可見文末的例子。是否使用hint,需要評估本地表資料全量推送到遠端的成本,和遠端表使用全表掃的成本。

附:在22個索引的情況下,嘗試采用DRIVING_SITE的hint:

遠端資料庫的表超過20個索引的影響

原文釋出時間為:2017-10-26

本文作者:何劍敏