一個索引創建引出的思考
- 2019 年 10 月 7 日
- 筆記
版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/bisal/article/details/101043935
前兩天上線,碰見了些問題,還是很值得探討。
問題1,
一張3000萬記錄的單表中,創建了唯一約束,(A,B,C),其中A的重複值非常多,B的重複值很少,接近於主鍵效果,但是某個邏輯,用到的是B作為檢索條件,而且在開發測試階段,因為數據量有限,未識別出這個字段需要創建索引,只在實際量級的生產系統下,才會暴露問題。但是,(A,B,C)自帶的唯一約束索引,是無法使用的,因為業務不能停,為了避免造成問題數據,所以不能改這個唯一約束。只可以選擇再創建個索引,即B的單鍵值索引。
這個問題暴露的,其實就是在索引創建的選擇上,應該多考慮一些不同場景的使用,(A,B,C)和B這兩個不同的使用場景,如果提前知道,並且對索引的基本原理有些了解,應該知道(B,A,C)是正確的創建路徑,一方面這兩個場景的索引使用要求,另一方面降低了存儲兩個索引的成本消耗。
但往往這種案例,非常常見,如何能從根本解決此類問題?我覺得可能有這幾種方式:
1. 提高開發人員對數據庫的了解,尤其是這種和開發直接相關的使用場景。
2. 提高DBA在此類問題的審核力度。
方法1其實是王道,開發了解業務,同時對數據庫的基本原理了解,自然能更容易地識別這類問題,授人以魚不如授人以漁。方法2是被動的,畢竟DBA或者專業的數據庫人員,對數據庫了解,但對業務不了解,除非開發告訴他,我有這兩種用法,當然有其他方式,或許能找到這類問題,但是消耗不小,投入產出比不高。方法3是技術手段的輔助,例如在非生產環境下,通過工具,即使數據量小,我也能通過執行計劃等信息,找出此類問題,結合方法2,對這種問題進行預警提示,一定程度上,還是能接受的。
問題2,
因為正常業務在頻繁地做增刪改操作,所以不能直接創建索引,他會阻塞DML,需要採用online方式,但是問題來了,在PLSQL Developer中,執行如下語句,等了將近30分鐘,還未完成,
create index idx_t_01 on t(id) online;
當然這個語句,存在一定的問題,就是沒用parallel,沒用充分利用數據庫服務器的多CPU,一定程度上,影響執行效率,畢竟創建索引,無論在線,還是非在線,尤其對大表,還是很消耗資源,所以正確做法,應該是加上parallel,當然要結合當前數據庫的CPU個數以及idle,來確定parallel並行度,
create index idx_t_01 on t(id) online parallel 16;
另外,如果要中斷當前創建索引的過程,可能會出現未回收的索引段,導致不能重新創建索引,解決方案是,
1. 可以嘗試利用如下SQL捕獲異常的Index Object_id,
select i.obj#, i.flags, u.name, o.name, o.type# from sys.obj$ o, sys.user$ u, sys.ind_online$ i where (bitand(i.flags, 256) = 256 or bitand(i.flags, 512) = 512) and (not ((i.type# = 9) and bitand(i.flags, 8) = 8)) and o.obj# = i.obj# and o.owner# = u.user#;
2. 將異常的object_id帶入如下存儲過程手工清理,
declare isclean boolean; begin isclean := false; while isclean = false loop isclean := DBMS_REPAIR.ONLINE_INDEX_CLEAN(對應OBJECT_ID, dbms_repair.lock_wait); dbms_lock.sleep(10); end loop; end; /
關於在線online和非online創建索引的方式,各自背後執行的路徑、優缺點、成本消耗,以及中斷索引創建的案例等,可以參考,如下文章,
《
《》
《
讀到此處的朋友,如果對上面這兩個問題,你有自己的見解,歡迎一起討論。