net+Oracle開發過程當中遇到的小問題

最新的項目開始使用Oracle後,5個月之間遇到一些在SqlServer中沒有遇到的問題,這裏記錄並貼上一些經常使用的解決辦法。html

Oracle相關

1、數據庫不一樣版本還原

剛開始咱們一直使用Oracle12C進行開發,到上線服務器時說12C與可能不太穩定,有些問題很差定位就轉用11g,這裏牽扯到12C導出的DMP文件導入到11G上的問題,導出導入語句:sql

exp 帳號/密碼@STO_DataBase file=D:\STO_DataBase.dmp full=y
imp 帳號/密碼@STO_DataBase file=D:\DataBackUp\STO_DataBase.dmp full=y

導入報異常版本不同,沒法導入,這裏用一款小工具能夠解決問題下載地址數據庫

此處輸入圖片的描述

2、數據庫建立

數據庫文件大小受DB_BLOCK_SIZE決定,默認是8K對應的數據庫文件是32G,因此建立數據庫時數據庫的大小不要設置最大值最好設置成無限大,能夠多設置幾個數據庫文件,以避免數據庫大小不夠用引發數據庫異常。建立語句:c#

//建立表空間
CREATE TABLESPACE STO_Data  
LOGGING  
DATAFILE 
'D:\DataBase\DbFile\STO_DATA.DBF',
'D:\DataBase\DbFile\STO_DATA1.DBF',  
'D:\DataBase\DbFile\STO_DATA2.DBF'  
SIZE 512M   
AUTOEXTEND ON   
NEXT 512M MAXSIZE unlimited
EXTENT MANAGEMENT LOCAL;
//建立臨時表空間
CREATE TEMPORARY TABLESPACE STO_Temp  
TEMPFILE 'D:\DataBase\DbFile\STO_Temp.DBF'  
SIZE 512M  
AUTOEXTEND ON  
NEXT 512M MAXSIZE unlimite
EXTENT MANAGEMENT LOCAL;  
//建立用戶
CREATE USER 用戶名 IDENTIFIED BY 用戶名密碼
DEFAULT TABLESPACE STO_Data  
TEMPORARY TABLESPACE STO_Temp  
//用戶賦權限  
grant connect,resource,dba  to 用戶名

3、常見問題

(1)存儲過程參數

存儲過程的參數命名最好能夠按照規則來不然會有問題,例如:服務器

create or replace procedure Proc_Test(IN_CompanyName       in varchar2, 
                                      OUT_Table        out sys_refcursor) as

begin open OUT_Table for select * from Waybill_Pickup t where t.companyname=IN_CompanyName;
  
end Proc_Test;

若是參數使用的和數據庫中的表字段同樣會引發失效,例如:oracle

create or replace procedure Proc_Test(CompanyName       in varchar2, 
                                      OUT_Table        out sys_refcursor) as

begin open OUT_Table for select * from Waybill_Pickup t where t.companyname=CompanyName;
  
end Proc_Test;

(2)按期釋放Temp文件空間

長時間使用會使Temp文件愈來愈大,而引發某些操做異常。app

alter tablespace STO_TEMP shrink space;

(3)索引失效

Oracle批量插入若是是用Oracle.DataAccess.Client.OracleBulkCopy 類,數據在插入過程當中會引發索引失效,若是是業務表就會引發業務查詢很是緩慢。可是插入效率很高,若是數據庫使用讀寫分離,或者接口採用讀寫分離的兩個表能夠經過此方法進行插入,若是遇到索引失效可用如下語句查看和修復。工具

//查看失效索引
select * from user_indexes where Status='UNUSABLE'
//重建失效索引
begin
  FOR cur in (select INDEX_NAME from user_indexes where Status='UNUSABLE') loop  
     execute immediate  'alter index '|| cur.INDEX_NAME||' rebuild' ;
  END LOOP;  
end;

(4)遇到問題如何排查

當Oracle遇到內部問題出現異常和掛機後的排查步驟(Oracle服務器)oop

  1. 查找日誌D:\app\Administrator\diag\rdbms\sto_database\stodatabase\alert
  2. 查詢跟蹤文件D:\app\Administrator\diag\rdbms\sto_database\stodatabase\trace
  3. 而後定位問題解決問題

參考文檔ui

當時遇到的問題是:數據庫直接Down掉了,鏈接時報沒有監聽程序。重啓服務器後過一會數據庫就掛掉了
檢查Oracle日誌:
D:\app\Administrator\diag\rdbms\sto_database\stodatabase\alert
查看Log文件,在日誌文件中找到錯誤信息提示:
此處輸入圖片的描述

檢查跟蹤文件
D:\app\Administrator\diag\rdbms\sto_database\stodatabase\trace
在跟蹤文件中查看錯誤信息引發的緣由:
根據錯誤查找出引發錯誤的SQL語句,最後定位到是單條語句超過65535個參數引發,因爲.net中使用了DbDataAdapter進行保存數據,他相似於拼接的Sql語句,更改批次提交數解決問題。

.net相關

1、處理傳參和LONG RAW類型

DbCommand處理Oracle數據庫默認參數綁定是按次序且不能查詢LONG RAW類型,處理SqlServer數據庫不用處理,
因此在初始化DbCommand時須要加入以下代碼

(cmd as Oracle.DataAccess.Client.OracleCommand).BindByName=true;
(cmd as Oracle.DataAccess.Client.OracleCommand).InitialLONGFetchSize = -1;

2、批量插入

(1)OracleBulkCopy

OracleBulkCopy在Oracle.DataAccess.DLL中,速率很快,但不進行主鍵和惟一鍵檢查,常常會將惟一索引弄壞,而且在插入過程當中普通索引也會失效。

/// <summary>
/// 批量插入數據庫
/// </summary>
/// <param name="datatable"></param>
/// <returns></returns>
public string OracleBulkInsert(DataTable datatable)
{
    OracleBulkCopy bulkCopy = new OracleBulkCopy(_connStr, OracleBulkCopyOptions.UseInternalTransaction);
    try
    {
        bulkCopy.DestinationTableName = datatable.TableName;
        bulkCopy.BulkCopyTimeout = 600000;
        bulkCopy.BatchSize = 50000;
        if (datatable != null && datatable.Rows.Count != 0)
            bulkCopy.WriteToServer(datatable);
        return "";
    }
    catch (Exception ex)
    {
        throw ex;
    }
    finally
    {
        if (bulkCopy != null)
            bulkCopy.Close();
    }
}

DataTable在插入時應注意字段類型和順序,能夠用如下代碼得到表結構

/// <summary>
/// 根據表名獲取Table結構
/// </summary>
/// <param name="tableName">表名</param>
/// <returns></returns>
public  DataTable InitStructureByTable(string tableName)
{
    DataTable dtColums = helper.GetDataSet("select column_name,data_type from user_tab_columns where table_name='" + tableName.ToUpper() + "' order by column_id", null).Tables[0];
    DataTable dtNew = new DataTable();
    dtNew.TableName = tableName;
    //匹配列數
    for (int j = 0; j < dtColums.Rows.Count; j++)
    {
        switch (dtColums.Rows[j][1].ToString().ToUpper())
        {
            case "DATE":
                dtNew.Columns.Add(new DataColumn(dtColums.Rows[j][0].ToString(), typeof(DateTime)));
                break;
            case "NUMBER":
                dtNew.Columns.Add(new DataColumn(dtColums.Rows[j][0].ToString(), typeof(double)));
                break;
            default:
                dtNew.Columns.Add(new DataColumn(dtColums.Rows[j][0].ToString(), typeof(string)));
                break;
        }              
    }
    return dtNew;
}

(2)DbDataAdapter批量插入

這種插入方式要比OracleBulkCopy要慢,至關於拼接了帶參數的插入語句插入,注意UpdateBatchSize數值不要過大,不然可能因爲單句Sql語句參數超過65535引發數據庫崩潰。

/// <summary>
/// 批量插入數據庫
/// </summary>
/// <param name="datatable"></param>
/// <returns></returns>
public  string BulkInsertCopy(DataTable datatable)
{
    DbDataAdapter adapter = _factory.CreateDataAdapter();        
    DbCommand cmd = _factory.CreateCommand();
    DbCommandBuilder cb = _factory.CreateCommandBuilder();      
    try
    {
        adapter.UpdateBatchSize = 200;
        using (DbConnection conn = _factory.CreateConnection())
        {
            conn.ConnectionString = ConnectionString;                
            conn.Open();
            cmd.Connection = conn;
            //cmd.Transaction = conn.BeginTransaction();          
            cb.DataAdapter = adapter;                 
            adapter.SelectCommand = cmd;
            adapter.SelectCommand.CommandText = "select * from " + datatable.TableName;
            adapter.FillSchema(datatable, SchemaType.Source);
            adapter.Update(datatable);
            //cmd.Transaction.Commit();           
        }
        return "";
    }
    catch (Exception ex)
    {
        //cmd.Transaction.Rollback();
        return ex.Message;
    }
    finally
    {
        cmd.Dispose();
        cb.Dispose();
        adapter.Dispose();
    }
}
相關文章
相關標籤/搜索