故事要從前幾天學會讓ODP.NET查詢加速10倍的密技說起,原始問題在於Dapper查詢效能不佳,正想把新發現套用在Dapper上… 登楞!Dapper透過IDbConnection擴充方法提供功能,根本沒機會對OracleCommand或OracleDataReader動手腳啊!(抱頭)
打開Dapper原始碼,想研究有沒有地方傳FetchSize參數(還在裡面看到華麗的Emit特技,嘆為觀止),由於FetchSize非通用ADO.NET屬性,無功而返。
另一條路從環境設定著手,倒有點收獲:OLE DB時代,連線字串可加上FetchSize參數,但ODP.NET已不支援。要指定ODP.NET的FetchSize全域設定,可以使用Registry[參考]:HKLM\Software\Oracle\ODP.NET\ version\FetchSize,只是如此將影響該機器上所有使用ODP.NET的程式,執意調高擔心有副作用。最後,發現Managed ODP.NET可以經由config指定FetchSize[參考],將影響範圍縮小到特定應用程式,是較可行的做法。
開了一個小Console Application專案做測試,用NuGet抓了12.1.021的Oracle官方Managed ODP.NET[參考]:
安裝後,app.config自動補上相關設定:
直接執行,程式抱怨無法解析連絡ID:
ORA-12154: TNS: 無法解析指定的連線ID
ORA-12154: TNS:could not resolve the connect identifier specified.
上回提過 Managed ODP.NET 有一套尋找TNSNAMES.ORA的順序,決定使用規則2,在config手動補上TNS_ADMIN路徑參數,順便加上FetchSize:
<oracle.manageddataaccess.client>
<versionnumber="*">
<dataSources>
<dataSourcealias="SampleDataSource"descriptor="(DESCRIPTION…省略…) "/>
</dataSources>
<settings>
<settingname="TNS_ADMIN"value="X:\Oracle\product\12.1.0\client\Network\Admin"></setting>
<settingname="FetchSize"value="1048576"/>
</settings>
</version>
</oracle.manageddataaccess.client>
補上TNS_AMDIN及FetchSize,Dapper果真變成光速前進。測試成功,如法修改使用Dapper的專案,由於為ASP.NET網站,原本web.config沒有<oracle.manageddataaccess.client>,我將測試成功的版本搬過去。以為需一併加上<configSections>的OracleInternal.Common.ODPMSetionHandler一起般去,結果加上反而會出現configSection重複定義錯誤,要移掉才OK。看起來web.config本來認得<oracle.manageddataaccess.client>,沒想太多,跑了網頁,卻一直冒出ORA-12154: TNS: 無法解析指定的連線ID錯誤。
反覆試了很久,結論是在web.config中放入的<oracle.manageddataaccess.client>沒發揮任何作用,改用IIS測試蒐集到新事證:當AppPool改用x64,web.config必須補上ODPMSetionHandler configSection,但可以成功解析連線ID,正確查詢DB。
拼湊以上線索,我想到一件事,應該是之前安裝Oracle ODAC32時,一併安裝了Managed ODP.NET, 導致32位元與64位元.NET設定不同。打開C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.config,薑薑薑薑~
一開頭就有configSection設定
結尾則有鎖定4.121.1.0版號的TNS_ADMIN設定
這解釋了為什麼在Visual Studio,web.config不用加configSection也認得<oracle.manageddataaccess.client>(VS是x86環境)。但為什麼加入的TNS_ADMIN沒作用成謎。試著加入<dataSrouce alias>也無作用,感覺web.config的整個<oracle.manageddataaccess.client>設定被忽略。但又為什麼Console Application跑x86測試也會成功?
經過一番比對測試,找到關鍵差異。NuGet安裝Managed ODP.NET時一併加入bindingRedirect設定:
<runtime>
<assemblyBindingxmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<publisherPolicyapply="no"/>
<assemblyIdentityname="Oracle.ManagedDataAccess"
publicKeyToken="89b483f429c47342"culture="neutral"/>
<bindingRedirectoldVersion="4.121.0.0 - 4.65535.65535.65535"
newVersion="4.121.2.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
將這段設定也加進web.config,Managed ODP.NET就順利找到TNSNAMES.ORA了。
回頭追了一陣子,每法對為何加入bindingRedirect將ODAC裝的4.121.1版Managed OPD.NET強轉為4.121.2能解決問題提出合理解釋,決定停損,將此謎團先歸入X檔案…