zoukankan      html  css  js  c++  java
  • Oracle绑定变量在C#.NET中的应用及意义

    一、 什么是绑定变量
    绑定变量(bind variable) :
    select * from emp where empno=:empno;
    是用户放入查询中的占位符,它会告诉Oracle“我会随后为这个变量提供一个值,现在需要生成一个方案,但我实际执行语句的时候,会提供应该使用的实际值”。
    实质就是用于替代sql语句中常量的替代变量。绑定变量能够使得每次提交的sql语句都完全一样。


    二、 为什么使用绑定变量
    使用绑定变量可以减少硬语法分析,优化共享池的使用。在oracle 中,对于一个提交的sql语句,存在两种可选的解析过程, 一种叫做硬解析,一种叫做软解析。
    当一个sql语句提交后,oracle会首先检查一下共享缓冲池里有没有与之完全相同的语句,如果有的话只须执行软分析即可,否则就得进行硬分析。
    一个硬解析需要经分析、解析、安全检查 、制定执行路径、优化访问计划等等许多的步骤。需消耗大量的cpu及资源。
    举个例子,要查询编号为001的儿童,下面两种写法都可以实现:
    select * from t_child where childid=’001’;//不使用绑定变量
    select * from t_child where childid =: childid;//使用绑定变量
    但是实际应用中经常是查询编号为001的儿童一次以后,有可能再也不用;接着你有可能查询儿童’002’,然后查询’003’等等。这样每次查询都是新的查询,都需要硬解析;
    而第二个查询语句提供了绑定变量: childid,它的值在查询执行时提供,查询经 过一次编译后,查询方案存储在共享池中,可以用来检索和重用;在性能和伸缩性方面,这两者的差异是巨大的,甚至是惊人的;
    若不使用绑定变量,每个查询的条件不同导致共享池中SQL语句数量太多,重用性极低,加速了SQL语句的老化,导致共享池碎片过多。 共享池中不同的SQL语句数量巨大,根据LRU原则,一些语句逐渐老化,最终被清理出共享池;这样就导致shared_pool_size 里面命中率下降,共享池碎片增多,可用内存空间不足。而为了维护共享池内部结构,需要使用latch,一种内部生命周期很短的lock,这将使用大量的cpu 资源,使得性能急剧下降。
    不使用绑定变量违背了oracle 的shared pool 的设计的原则,违背了这个设计用来共享的思想。


    三、 如何使用绑定变量

    public DataSet GetDataTable(T_child entity)
    {
        ArrayList parmlist = new ArrayList();
        ArrayList valuelist = new ArrayList();
        String sql = "select * from t_child where childid =: childid";
        parmlist.Add("childid");
        valuelist.Add(entity.Childid);
        DataSet ds = SqlHelper(sql, dbName, valuelist, parmlist, ref errorMsg);
        return ds;
    }

    调用以下方法:

    public static DataSet SqlHelper(string query, string dataBaseName, ArrayList bllist, ArrayList pamlist, ref string returnMessage)
    {
        AdoHelper adoHelper = null;
        try
        {
            adoHelper = DatabaseConnectEntity.CreateHelper(dataBaseName);
            IDataParameter[] parameters = new IDataParameter[bllist.Count];
            if (adoHelper._dbFactory.DatabaseType == DatabaseType.DB_Oracle)
            {
                ArrayList paramlist = new ArrayList();
                for (int i = 0; i < bllist.Count; i++)
                {
                    OracleParameter parm;
                    string paramvalue = "";
                    if (bllist[i] == null)
                    {
                        parm = new OracleParameter(pamlist[i].ToString(), null);
                    }
                    else
                    {
                        paramvalue = bllist[i].ToString();
                        if (bllist[i].GetType().ToString() == "System.DateTime")
                        {
                            parm = new OracleParameter(pamlist[i].ToString(), OracleType.DateTime);
                            parm.Value = paramvalue.Trim();
                        }
                        else
                        {
                            parm = new OracleParameter(pamlist[i].ToString(), paramvalue.Trim());
                        }
                    }
                    paramlist.Add(parm);
                }
                paramlist.CopyTo(parameters, 0);
            }
            else
            {
                returnMessage = "非ORACLE数据库不能执行此存储过程!";
                return null;
            }
            DataSet ds = adoHelper.ExecuteDataSet(CommandType.Text, query, parameters);
            return ds;
        }
        catch (Exception ex)
        {
            returnMessage = "查询失败!" + ex.ToString();
            return null;
        }
        finally
        {
            adoHelper.Close();
        }
    }

    四、 绑定变量使用限制条件
    在对建有索引的字段(包括字段集),且字段(集)的集的势非常大时,使用绑定变量可能会导致无法选择最优的查询计划,因而会使查询效率非常低。
    集的势非常大【即倾斜性很严重 】,如:一个索引字段,总记录数有1000条,有A值的有900条;B值50条;C值50条,那么我们就说这个字段的集的势很大。当然这个集的势的算法比较复杂,他跟查询条件、是否建索引等都有关系。比如:若全表扫描:集的势=记录数;索引扫描,查询条件“=”:集的势=记录数/字段上的唯一值数 ;
    那么为什么说集的势大时使用绑定变量反而会时查询效率变低呢?
    因为Oracle在执行SQL语句时,会计算各个访问路径的代价,采用最小代价的访问路径作为语句的执行计划。若第一次查询的条件刚好是索引字段中记录最多的值,那么这个索引扫描成本就非常高,根据分析会使用全表扫描,并将这个查询计划保存到共享池中,而当查询其他值时成本很低,但由于采用绑定变量,不再进行硬解析,也就是不去分析采用什么执行计划,而是直接使用之前的这个查询计划,这样会导致无法选择最优的查询计划。
    对于隔相当一段时间才执行一次的sql语句,利用绑定变量的好处会被不能有效利用优化器而抵消。

  • 相关阅读:
    Java方法
    Java流程控制
    Java基础
    常用Dos命令
    MarkDown语法
    怎样获取最新版的javascript文件,解决被浏览器缓存的问题
    笔记:javascript操作iframe内的DOM元素,及调用iframe内的方法
    .net程序部署(mono方式)
    面向对象的一点简易理解
    [李说新语]系列(1)西汉勇士贯高到底该不该死
  • 原文地址:https://www.cnblogs.com/liquanchun/p/3267945.html
Copyright © 2011-2022 走看看