• 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语句,利用绑定变量的好处会被不能有效利用优化器而抵消。

  • 相关阅读:
    Oracle SQL语句收集
    SqlParameter In 查询
    SQL 性能优化
    Entity Framework
    【XLL API 函数】 xlfSetName
    【XLL API 函数】xlfUnregister (Form 2)
    【XLL API 函数】xlfUnregister (Form 1)
    【Excel 4.0 函数】REGISTER 的两种形式以及VBA等效语句
    【Excel 4.0 函数】REGISTER
    【Bochs 官方手册翻译】 第一章 Bochs介绍
  • 原文地址:https://www.cnblogs.com/liquanchun/p/3267945.html
Copyright © 2020-2023  润新知