標籤:
導致索引失效的直接原因:當某些操作導致資料的rowid改變,索引就會完全失效。
那什麼時候會導致rowid改變使得索引unuseable或者invalid呢?
一般普通表在在如下3個情況下可以使index unusable
1) 手動alter index unusable
2) Move 【alter table move】【alter table t02 move tablespace tbs01;】包括分區操作
3) sqlldr 【sqlldr ( parallel or direct ) append 】【sqlldr direct=y + 主鍵重複】
匹配三個選項:
1、檢查dba_objects的last_ddl_time,對應的時間遠早於問題發生的時間段,第一種可能性排除了
2、檢查問題表沒有分區,也沒有做資料移動、統計資訊收集之類的操作,last_ddl_time也可以作為佐證
3、回憶一下,貌似沒有使用過sqlldr,很奇怪、鬱悶
從AWR、ASH瞭解到問題發生的時間段索引失效的表發生了嚴重的library cache lock等待,查詢曆史效能檢視dba_hist_active_sess_history,發現大量library cache lock等待的會話都在被同一個會話阻塞,而該會話沒有被其他阻塞,等待事件為db file sequential read,不可理解,為什麼會是索引尋找呢?根據sql_id,已經查不到當前會話正在執行的SQL指令碼了。
等待下一次問題重現,希望能夠看到同樣的資訊,看一下阻塞源頭的會話正在執行一個什麼樣的東東。
果然,第二天問題重現了,抓取所有會話及當前正在執行SQL,馬上發現了問題:INSERT /*+ SYS_DL_CURSOR */ INTO "LC0079999"."JKL_TEST" ("ID", "C1","C2","C3",) VALUES (NULL,NULL,NULL,NULL)
第一、這是我們的資料表
第二、好像不是我們手工產生的SQL語句
第三、查了一下SYS_DL_CURSOR 關鍵字,等同於sqlldr(direct=true),重現一把BulkCopy,果然可以看到這條語句
注意:
Bulkcopy的方式本身產生的語句為:INSERT /*+ SYS_DL_CURSOR */ INTO "LC0079999"."JKL_TEST" ("ID", "C1","C2","C3",) VALUES (NULL,NULL,NULL,NULL)
/*+ SYS_DL_CURSOR */ 就是SQL Loader的方式,也就是說Bulkcopy需要謹慎使用,因為他會造成該表的索引失效。
並且在執行Sql Loader前,會執行對錶的獨佔鎖定:LOCK TABLE "LC0079999"."JKL_TEST" IN EXCLUSIVE MODE NOWAIT
結論:按照目前發現的問題,BulkCopy應該僅適用於日誌之類的極少並發的情境,建議謹慎使用Bulkcopy
Bulkcopy對應的實現是Oracle的SQL*LOADER,期間造成Index Unusable,並且last_ddl_time上是不體現的