insert 是唯一無法直接從索引獲益的操作,因為它沒有 where 子句。
新增一列發生了什麼事#
第一步:找地方存放。 對一般的堆積表(沒有特定列順序)而言,資料庫可以挑任何有足夠空閒空間的資料表區塊。這個過程非常簡單快速,大多在主記憶體中完成;之後只要把新條目加進該資料區塊即可。
第二步:更新所有索引。 若表上有索引,資料庫必須確保新條目透過這些索引也找得到,因此得把它加進該表的每一個索引。
而且把條目加進索引,比插入堆積結構昂貴得多,因為資料庫必須維持索引順序與樹的平衡:
- 新條目不能寫進任意區塊——它屬於某個特定葉節點。雖然資料庫用索引樹本身找到正確的葉節點,仍得為樹走訪讀取幾個索引區塊。
- 找到葉節點後,資料庫確認其中是否還有足夠空間。若沒有,就得分裂葉節點,把條目分配到舊節點與新節點之間。
- 分裂還會影響對應分支節點中的參照(必須跟著複製一份),而分支節點同樣可能空間不足、同樣可能得分裂。
- 最壞情況下,資料庫必須一路分裂到根節點——這也是樹唯一會增加一層、深度成長的情況。
效能實測#

圖 8.1:依索引數量的 insert 效能
資料表沒有任何索引時,執行時間幾乎看不見(0.0003 秒)。然而只要加上單一個索引,執行時間就足足增加一百倍,之後每多一個索引又更慢。
索引維護說到底才是 insert 操作中最昂貴的部分。要優化 insert 效能,把索引數量壓低非常重要。
但別走極端#
單就 insert 而言,完全不建索引效能最好。然而現實應用中沒有索引的資料表相當不切實際——你總會想把存進去的資料再讀出來,那就需要索引來加快查詢。即使是只寫的日誌表,通常也有主鍵與相應索引。
不過,無索引時的效能好到一件事變得合理:載入大量資料時暫時把所有索引砍掉——前提是這段期間沒有其他 SQL 敘述需要它們。這能帶來圖中可見的戲劇性加速,事實上也是資料倉儲的常見實務。
- 若改用索引組織表或叢集索引,圖 8.1 會有什麼變化?
insert有沒有可能間接從索引獲益?也就是說,多一個索引有沒有可能讓insert變快?