Oracle.DataAccess 10.2的問題?Oracle找不準索引

來源:互聯網
上載者:User
伺服器為Oracle
9i,NHibernate使用NHibernate.Driver.OracleDataClientDriver(Oracle.DataAccess.dll,使用ODTwithODAC1020221這個版本安裝。因為正式部署打算用Oracle
10g,所以用戶端NHibernate用了這個驅動,另外也是為了避免System.Data.OracleClient.dll操作Clob/Nclob時的問題),陸續發現不少奇怪的問題。不清楚是這個驅動跟Oracle
9i之間的相容性造成還是其它原因,不過最終基本都解決了。

1. 今天解決了2個效能方面的問題,原因都是日期類型的欄位造成。

1.1
第一個查詢是對一個60多萬的表執行單表查詢,有一個日期欄位建了索引,查詢會使用這個日期欄位。一開始查詢很慢,估計是NHibernate產生的SQL語句沒有使用到索引(把日誌中的SQL語句拿出來分析,查詢計劃中顯示是使用了索引的)。解決方案是按照使用NHibernate, Oracle Clob/NClob無法插入、亂碼問題的方式建立一個使用者自訂日期類型,將IDbCommand中對應參數的OracleDbType設定為OracleDbType.Date,然後在NHibernate中把日期欄位配置為這個類型。這樣查詢就能使用到索引了。

1.2 跟第一個問題基本類似。
也是一個查詢,涉及到多個表的關聯,有個表資料400多萬。同樣估計是一個日期欄位的索引沒有發揮作用而導致的低效(同樣,SQL語句抓出來用查詢計劃分析,顯示索引是使用上了),但是按照1.1中的方法之後還是不起作用。唯一不同之處是1.1用的ICriteria,而這個查詢用的是IQuery。
解決方案是把sql改成類似b.CreateDate>to_date(:startDate,
'YYYY-MM-DD')這種形式,然後使用IQuery.SetString()方法而不是IQuery.SetDateTime(),這樣就OK了。

第一個問題還好理解,如果參數類型沒有設定正確無法利用索引,比較正常,但這個方法無法運用在第二個類似的問題上就比較費解了。

2. 用Oracle.DataAccess 10.2這個版本調用Oracle 9i的Function/Procedure時問題比較多。
2.1 正常情況下調用應當是這個樣子:
OracleConnection con = new OracleConnection("connection string");

con.Open();

OracleCommand cmd = con.CreateCommand();

cmd.CommandType = CommandType.StoredProcedure;

cmd.CommandText = "function / procedure name"; cmd.Parameters.Add(new
OracleParameter("param name", OracleDbType.Double).Value = 12.1);

int effectedRows = cmd.ExecuteNonQuery();

con.Close();
但在Oracle 9i上函數或預存程序聲明的參數類型為Number(老系統的東西,不敢改動),而ODAC
10.2的OracleDbType是沒有Number這個類型的,把參數設定成OracleDbType.Double、OracleDbType.Decimal等各種類型,均報錯無法轉換成數字類型。
只有改成下面這種方式才能成功調用:
OracleConnection con = new OracleConnection("connection string");

con.Open();

OracleCommand cmd = con.CreateCommand();

cmd.CommandType = CommandType.Text;

cmd.CommandText = @"

Declare v_value Number;

    Begin v_value:=function or procedure name(:p1, :p2, :returnValue);

End;";

cmd.Parameters.Add(new OracleParameter("p1", OracleDbType.Double).Value = 12.1);

cmd.Parameters.Add(new OracleParameter("p2", OracleDbType.Varchar2).Value =
"Test");

cmd.Parameters.Add(new OracleParameter("returnValue", OracleDbType.Int32,
ParameterDirection.Output).Value = 0);

int effectedRows = cmd.ExecuteNonQuery();

con.Close();
if (cmd.Parameters[2].Value != null && cmd.Parameters[2].Value != DBNull.Value)

{

    int returnValue = Convert.ToInt32(cmd.Parameters[2].Value);

    /*....*/
}

2.2 如果Function/Procedure有out型的參數,參數類型為Varchar2等字串型的,必須指定參數的Size屬性,否則報緩衝區溢位錯誤。

3. 極個別的情況下,用戶端已經把一條資料刪除了,用SQL查詢資料庫確實查不到這條資料,但是NHibernate仍然能夠擷取到這個對象。
確認NHibernate沒有開二級緩衝;確認NHibernate有向伺服器提交這個SQL語句,跟蹤到NHibernate,在執行DbCommand查詢時產生的SQL語句正確,參數設定正確,日誌中記錄的這些也是正確的,但NHibernate執行完之後的確返回了這條資料;監控資料庫伺服器,確認伺服器根本沒有執行這個SQL。所以把問題確定在ODAC
10.2這個驅動上面。但更奇怪的是用戶端(Web
Server,上面配置了Oracle網路服務)重起機器,問題還在;資料庫伺服器重起機器,問題還在,還能查出那條資料。後來再沒有發生這種情況,也無從查起。

2008.01.06
上面兩個問題都是Oracle沒有找准索引,從程式層面將參數資訊設定準確確實比較重要。
另外最佳化過程中不斷髮現Oracle找不準索引的情況,在不少查詢中添加了指定索引,甚至是JOIN TYPE的hints,倒忘了另外一個重要方面:測試庫經常大量的匯入測試資料,需要分析維護Oracle索引!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.