故事要從前幾天學會讓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>
<version number="*">
  <dataSources>
    <dataSource alias="SampleDataSource" descriptor="(DESCRIPTION…省略…) "/>
  </dataSources>
  <settings>
    <setting name="TNS_ADMIN" value="X:\Oracle\product\12.1.0\client\Network\Admin"></setting>
    <setting name="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>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <publisherPolicy apply="no"/>
        <assemblyIdentity name="Oracle.ManagedDataAccess" 
          publicKeyToken="89b483f429c47342" culture="neutral"/>
        <bindingRedirect oldVersion="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檔案…


Comments

# by Kevin

感恩,我這裡的環境也是類似的狀況: 1.sql developer可以連線,Web API連線使用connectSting搭配TNS_NAME.ora檔 2.API連線結果顯示ORA-12154: TNS: 無法解析指定的連線 ID 3.所有程式的執行位置都不存在(x86),所以排除Will大大的 [解決 ASP.NET 跑在 x64 機器上無法連接 Oracle DB 的問題] 安裝歷史 1.先安裝Managed ODAC後再卸載(都是透過官網本身給的BAT檔),因為連不上果斷放棄 2.安裝64-bit ODAC 12.2c Release 1 (12.2.0.1.1) for Windows x64 我這裡的解法: 直接將machine.config的TNS_ADMIN(其値原本是已卸載的Managed ODAC路徑....也夾雜了萬惡的(x86)字串) 改為原本環境變數使用的TNS_ADMIN値(ODAC 安裝路徑的NetWork/Admin) 結果API就能正常連線了,甚至連系統環境變數移除TNS_ADMIN也不影響(不知道是好是壞......

Post a comment