與動(dòng)態(tài)SQL)
137、ABAP游標(biāo)與動(dòng)態(tài)SQL那是在一個(gè)夜班運(yùn)維的凌晨,MES系統(tǒng)的某個(gè)報(bào)表程序突然報(bào)出“OPEN SQL: database error”的短轉(zhuǎn)儲(chǔ)。查了ST22,指向一段用SELECT-ENDSELECT循環(huán)讀取Z表的邏輯,數(shù)據(jù)量不過兩萬行,卻因?yàn)槊看窝h(huán)內(nèi)還嵌套了三次單條SELECT,把數(shù)據(jù)庫會(huì)話拖垮了。那時(shí)候我剛接手ABAP,第一反應(yīng)是加索引、優(yōu)化WHERE,可DBA說索引已經(jīng)到位,問題出在游標(biāo)持有期間反復(fù)打開新的隱式游標(biāo),加上舊版本ABAP對OPEN CURSOR的鎖處理不友好。后來我把那段嵌套的SELECT-ENDSELECT改成顯式游標(biāo)一次抓一批,再用內(nèi)部表批量處理,數(shù)據(jù)庫壓力瞬間降下來。從那天起,我才真正去研究ABAP游標(biāo)的底層行為,也順帶把動(dòng)態(tài)SQL的坑踩了個(gè)遍。先聊聊游標(biāo)。ABAP里的SELECT-ENDSELECT其實(shí)是隱式游標(biāo),系統(tǒng)幫你打開、取值、關(guān)閉,看著方便,可每取一行都保持?jǐn)?shù)據(jù)庫游標(biāo)打開狀態(tài),如果循環(huán)體里又去操作別的表,數(shù)據(jù)庫端就會(huì)出現(xiàn)游標(biāo)交叉占用。更隱蔽的是,SELECT-ENDSELECT不適合大數(shù)據(jù)量,因?yàn)槊看蜦ETCH都是一次數(shù)據(jù)庫往返,十萬行就是十萬次網(wǎng)絡(luò)開銷。我見過有人拿它讀百級表,硬生生跑了十幾分鐘,最后被業(yè)務(wù)投訴。顯式游標(biāo)用OPEN CURSOR加FETCH NEXT CURSOR,可以一次抓多條到內(nèi)部表。關(guān)鍵參數(shù)是PACKAGE SIZE,這個(gè)不是ABAP語句里的關(guān)鍵字,而是通過FETCH NEXT CURSOR … INTO … 配合內(nèi)部表時(shí),系統(tǒng)默認(rèn)按內(nèi)部表頭大小批量讀。其實(shí)ABAP里控制批量大小主要靠OPEN CURSOR … PACKAGE SIZE n,但很多人不知道這個(gè)n只對數(shù)據(jù)庫游標(biāo)有提示作用,真正有