最新的项目开始使用 Oracle 后,5 个月之间遇到一些在 SqlServer 中没有遇到的问题,这里记录并贴上一些常用的解决办法.
Oracle 相关
一,数据库不同版本还原
刚开始我们一直使用 Oracle12C 进行开发,到上线服务器时说 12C 与可能不太稳定,有些问题不好定位就转用 11g,这里牵扯到 12C 导出的 DMP 文件导入到 11G 上的问题,导出导入语句:
exp 账号/密码@STO_DataBase file=D:\STO_DataBase.dmp full=y
imp 账号/密码@STO_DataBase file=D:\DataBackUp\STO_DataBase.dmp full=y
导入报异常版本不一样,无法导入,这里用一款小工具可以解决问题 下载地址 .
二,数据库创建
数据库文件大小受 DB_BLOCK_SIZE 决定,默认是 8K 对应的数据库文件是 32G,所以创建数据库时数据库的大小不要设置最大值最好设置成无限大,可以多设置几个数据库文件,以免数据库大小不够用引起数据库异常.创建语句:
//创建表空间
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 用户名
三,常见问题
(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;
如果参数使用的和数据库中的表字段一样会引起失效,例如:
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 文件越来越大,而引起某些操作异常.
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 服务器)
查找日志 D:\app\Administrator\diag\rdbms\sto_database\stodatabase\alert
查询跟踪文件 D:\app\Administrator\diag\rdbms\sto_database\stodatabase\trace
然后定位问题解决问题
参考文档
当时遇到的问题是:数据库直接 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 相关
一,处理传参和 LONG RAW 类型
DbCommand 处理 Oracle 数据库默认参数绑定是按次序且不能查询 LONG RAW 类型,处理 SqlServer 数据库不用处理,
所以在初始化 DbCommand 时需要加入如下代码
(cmd as Oracle.DataAccess.Client.OracleCommand).BindByName=true;
(cmd as Oracle.DataAccess.Client.OracleCommand).InitialLONGFetchSize = -1;
二,批量插入
(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();
}
}
来源: https://www.cnblogs.com/kaoleba/p/8328928.html