防不勝防:一個空格在資料庫裡可能引發的N重血案
編輯手記:在Oracle DBA的職業生涯中,無數看似簡單的一個疏忽就能夠導致致命的故障和資料損失,一個空格看似很小,可是如果在指令碼執行環境中,就絕對不容輕視。
你可能還記得我們分享過的一個真實案例:一個空格引發的血案。
今天我們來看另外一個和空格有關的案例,基於11.2.0.3版本的測試:
這是一個 11.2.0.3 的 sqlplus 客戶端,那麼以下這個簡單的查詢結果是什麼?
好,我承認是在故弄玄虛,結果就是簡單到不能再簡單的1,那麼問題來了,上面第二個查詢的結果是什麼?
不要扔磚,雖然結果還是意料之內的,但是見證奇蹟的時刻馬上就要到了,這第三個查詢的結果是什麼?
這個結果是不是很2 ?
這個語句和上面第二個語句只是相差了一個空格,結果是完全不同的。對於第二個語句而言,註釋並沒有對語句產生任何的影響;而對於第三個語句,實際上 Oracle 並沒有把這個語句作為包含註釋的語句看待,實際上 sqlplus 執行的是/,也就是將快取中的語句再執行一次,而完全忽略了/之後的內容。
可能有些人認為這個 bug 對於系統的影響不大,而如果在資料庫中執行 .sql 檔案,或者通過 shell 呼叫 sql 指令碼,那麼這個問題出現的可能性就大大增加了。
考慮一下極端的情況,這個問題可能帶來哪些危害。最明顯的莫過於使得上一個執行的 SQL 重複執行。
如果上一條是 SELECT,則顯然對系統影響最小(事實上這個影響也不小,因為當前需要執行的
即使不在指令碼中執行,有些情況下也是沒有機會回滾的,比如:
這種想要恢復就只能通過閃回了。而如果重複執行的是 DDL,那麼連閃回的機會都沒有了。
重複 DDL 的一個例子:雖然並不會真正造成什麼資料的損失,但是資料的載入以及分割槽 EXCHANGE 的工作就完全白做了。
好在這個問題只是發生在 sqlplus 中,且 SQL 語句開頭是以/*方式的註釋開頭,註釋與後面的內容之間沒有空格的情況下,因此想要碰到這個錯誤也並不容易。可是不要忘記墨菲定律,可能發生故障的地方,終究會有人掉進坑裡。