Oracle Parameter

在实际开发中,经常会需要对数据库进行访问,最常见的开发方法就类似:
  string sql = "select * from table1 where name = '" + name + "'";
  这种方式有被注入攻击的危险
  所以解决方案有2种:
  1、改成:string sql = "select * from table1 where name = '" + name.Replace("'","''") + "'"; // 替换一个单引号为两个单引号
  2、使用参数化形式,如在Oracle中,用如下方式执行:
  string sql = "select * from table1 where name = :vName";
  OracleParameter para = new OracleParameter("vName", OracleType.VarChar);
  para.Value = name;
  OracleConnection con = new OracleConnection (constr);
  con.Open();
  OracleCommand com = con.CreateCommand();
  com.CommandText = sql;
  com.Parameters.Add(para);
  com.ExecuteReader();
  如此看来,使用参数化的形式复杂的许多,用替换的方式简单的多
  所以我一直以来都是用替换的方式来处理,昨天发现了用参数的另一个好处
  才知道,使用参数化形式还可以提高Oracle的性能(不知道SqlServer有没有类似的好处)
  通过分析SQL语句的执行计划优化SQL
  共享sql语句
  为了不重复解析相同的SQL语句(因为解析操作比较费资源,会导致性能下降),在第一次解析之后,ORACLE将SQL语句及解析后得到的执行计划存放在内存中。这块位于系统全局区域SGA(system global area)的共享池(shared buffer pool)中的内存可以被所有的数据库用户共享。因此,当你执行一个SQL语句(有时被称为一个游标)时,如果该语句和之前的执行过的某一语句完全相同,并且之前执行的该语句与其执行计划仍然在内存中存在,则ORACLE就不需要再进行分析,直接得到该语句的执行路径。ORACLE的这个功能大大地提高了SQL的执行性能并大大节省了内存的使用。使用这个功能的关键是将执行过的语句尽可能放到内存中,所以这要求有大的共享池(通过设置shared buffer pool参数值)和尽可能的使用绑定变量的方法执行SQL语句。
  当你向ORACLE 提交一个SQL语句,ORACLE会首先在共享内存中查找是否有相同的语句。这里需要注明的是,ORACLE对两者采取的是一种严格匹配,要达成共享,SQL语句必须完全相同(包括空格,换行等)。
  下面是判断SQL语句是否与共享内存中某一SQL相同的步骤:
  1. 对所发出语句的文本串进行hashed。如果hash值与已在共享池中SQL语句的hash值相同,则进行第2步:
  2.将所发出语句的文本串(包括大小写、空白和注释)与在第1步中识别的所有
  已存在的SQL语句相比较。
  例如:
  SELECT * FROM emp WHERE empno = 1000;
  和下列每一个都不同
  SELECT * from emp WHERE empno = 1000;
  SELECT * FROM EMP WHERE empno = 1000;
  SELECT * FROM emp WHERE empno = 2000;
  在上面的语句中列值都是直接SQL语句中的,今后我们将这类sql成为硬编码SQL
  或字面值SQL
  使用绑定变量的SQL语句中必须使用相同的名字的绑定变量(bind variables) ,
  例如:
  a. 该2个sql语句被认为相同
  select pin , name from people where pin = :blk1.pin;
  select pin , name from people where pin = :blk1.pin;
  b. 该2个sql语句被认为不相同
  select pin , name from people where pin = :blk1.ot_ind;
  select pin , name from people where pin = :blk1.ov_ind;
  今后我们将上面的这类语句称为绑定变量SQL。
  3. 将所发出语句中涉及的对象与第2步中识别的已存在语句所涉及对象相比较。
  例如:
  如用户user1与用户user2下都有EMP表,则
  用户user1发出的语句:SELECT * FROM EMP; 与
  用户user2发出的语句:SELECT * FROM EMP;
  被认为是不相同的语句,
  因为两个语句中引用的EMP不是指同一个表。
  4. 在SQL语句中使用的捆绑变量的捆绑类型必须一致。
  如果语句与当前在共享池中的另一个语句是等同的话,Oracle并不对它进行语法分析。而直接执行该语句,提高了执行效率,因为语法分析比较耗费资源。
  注意的是,从oracle 8i开始,新引入了一个CURSOR_SHARING参数,该参数的主要目的就是为了解决在编程过程中已大量使用的硬编码SQL问题。因为在实际开发中,很多程序人员为了提高开发速度,而采用类似下面的开发方法:
  str_sql string;
  int_empno int;
  int_empno = 2000;
  str_sql = ‘SELECT * FROM emp WHERE empno = ‘ + int_empno;
  …………
  int_empno = 1000;
  str_sql = ‘SELECT * FROM emp WHERE empno = ‘ + int_empno;
  上面的代码实际上使用了硬编码SQL,使我们不能使用共享SQL的功能,结果是数据库效率不高。但是从上面的2个语句来看,产生的硬编码SQL只是列值不同,其它部分都是相同的,如果仅仅因为列值不同而导致这2个语句不能共享是很可惜的,为了解决这个问题,引入了CURSOR_SHARING参数,使这类问题也可以使用共享SQL,从而使这样的开发也可以利用共享SQL功能。听起来不错,ORACLE真为用户着想,使用户在不改变代码的情况下还可以利用共享SQL的功能。真的如此吗?天上不会无缘无故的掉一个馅饼的,ORACLE对该参数的使用做了说明,建议在经过实际测试后再改该参数的值(缺省情况下,该参数的值为EXACT,语句完全一致才使用共享SQL)。因为有可能该变该值后,青年人网提示你的硬编码SQL是可以使用共享SQL了,但数据库的性能反而会下降。 青年人网提示实际应用中已经遇到这种情况。所以建议编写需要稳定运行程序的开发人员最好还是一开始就使用绑定变量的SQL。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
优化这串代码using Oracle.ManagedDataAccess.Client; public static OracleDbType ConvertOracleDbType(Type type) { switch(type.Name.ToLower()) { case "decimal": return OracleDbType.Decimal; case "string": return OracleDbType.Varchar2; case "datetime": return OracleDbType.Date; default: return OracleDbType.Varchar2; } } public static dynamic InitList(Type type) { switch(type.Name.ToLower()) { case "decimal": return new List<decimal>(); case "string": return new List<string>(); case "datetime": return new List<DateTime>(); default: return new List<string>(); } } public static void AddValue(dynamic list, Type type, object value) { switch(type.Name.ToLower()) { case "decimal": list.Add(Convert.ToDecimal(value)); break; case "string": list.Add(Convert.ToString(value)); break; case "datetime": list.Add(Convert.ToDateTime(value)); break; default: list.Add(Convert.ToString(value)); break; } } public static int BulkCopy(DataTable dataTable) { string connStr = ""; int result = 0; List<string> sql_column = new List<string>(); List<string> sql_para = new List<string>(); List<OracleParameter> paras = new List<OracleParameter>(); foreach(DataColumn column in dataTable.Columns) { sql_column.Add(column.ColumnName); sql_para.Add(":" + column.ColumnName); dynamic list = InitList(column.DataType); foreach(DataRow dr in dataTable.Rows) { AddValue(list, column.DataType, dr[column]); } OracleParameter para = new OracleParameter(column.ColumnName, ConvertOracleDbType(column.DataType)); para.Value = list.ToArray(); paras.Add(para); } using(var connection = new OracleConnection(connStr)) { connection.Open(); string sql = $"insert into {dataTable.TableName}({string.Join(",", sql_column)}) values ({string.Join(",", sql_para)})"; OracleCommand cmd = new OracleCommand(sql, connection); cmd.Parameters.AddRange(paras.ToArray()); cmd.ArrayBindCount = dataTable.Rows.Count; result = cmd.ExecuteNonQuery(); connection.Close(); } return result; }
最新发布
06-02

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值