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();
    }
}
相关文章
相关标签/搜索