一、绑定变量简介
首先理解一下OLTP系统为什么需要绑定变量?
变量绑定会使 OLTP系统 数据库中的SQL执行速度飞快,内存效率极高,减少资源消耗;不使用绑定变量可能会使 OLTP 数据库不堪重负,资源被SQL解析严重耗尽,系统运行缓慢。
对OLTP和OLAP不了解的可以查看这篇文章: OLTP vs OLAP
当一个用户与数据库建立连接后,会向数据库发出操作请求,即向数据库送过去SQL语句。 Oracle 在接收到这些SQL后,会先对这个SQL做一个hash 函数运算,得到一个Hash值,然后到共享池中寻找是否有和这个hash值匹配的SQL存在。 如果找到了,Oracle将直接使用已经存在的SQL 的执行计划去执行当前的SQL,然后将结果返回给用户。 如果在共享池中没有找到相同Hash 值的SQL,oracle 会认为这是一条新的SQL,会进行解析。
二. SQL硬解析和软解析
Oracle中每条SQL语句在执行之前都需要经过解析,这里面又分为软解析和硬解析。在Oracle中存在两种类型的SQL语句:
- DDL语句(数据定义语言),他们是从来不会共享使用的,也就是每次执行都需要进行硬解析。
- DML语句(数据操纵语言),他们会根据情况选择要么进行硬解析,要么进行软解析。
2.1 Oracle的解析过程如下:
-
语法解析:检查SQL的拼写是否正确。
-
语义解析:检查SQL语句中的访问对象(比如表、字段等)是否存在及该用户是否具备相应的权限。
-
对sql语句进行解析:利用内部算法对SQL进行解析,生成解析树和执行计划。
第三步解析分为硬解析和软解析。
硬解析:就是上面提到的对提交的SQL完全重新从头进行解析。
软解析:在共享池中检查是否有完全相同的之前完全解析好的,如果存在直接执行SQL。 -
执行sql,返回结果。
三. 绑定变量
绑定变量的本质就是本来需要做Oracle硬解析的SQL变成软解析,以减少Oracle花费在SQL解析上的时间和资源。
select email from user where name = 'a';select email from user where name = 'b';
有上面两条sql,如果没有使用绑定变量,那么这2条SQL 会被解析2次,因为他们的谓词部分不一样。
但是如果使用了绑定变量,如 select email from user where name = :uname
,之前的2条SQL就变成了一种SQL,Oracle 只需要对每一种SQL做一次硬解析,之后类似的SQL 都使用这条SQL产生的执行计划,这样就可以大大降低数据库花费在SQL解析上的资源开销。 这种效果当SQL执行的越多,就越明显。
简单的说,绑定变量就是拿一个变量来代替谓词常量,让Oracle每次对用户发来的SQL做hash 运算时,运算出的结果都是同样的Hash值,于是将所有的用户发来的SQL看作是同一个SQL来处理。
四. 使用方法
Oracle中可以通过三种方式绑定变量。
- 通过将元组传递给带有编号变量的SQL语句。
run_sql = "select * from table where field1 = :1 and field2 = :2" cursor.execute(run_sql, (value1, value2))
- 通过关键字参数传递给带有命名变量的SQL语句。
run_sql = "select * from table where field1 = :condition1 and field2 = :condition2" cursor.execute(run_sql, condition1=value1, condition2=value2)
- 通过使用命名变量将字典传递给SQL语句。
run_sql = "select * from table where field1 = :condition1 and field2 = :condition2" cursor.execute(run_sql, {"condition1": value1, "condition2": value2})
Mysql中的绑定变量。
- 通过将元组传递。
run_sql = "select * from user where name = %s and role_id = %s" cursor.execute(run_sql, (value1, value2))
- 通过命名变量传递。
run_sql = "select * from user where name = %(condition1)s and role_id = %(condition2)s" cursor.execute(run_sql, {"condition1": value1, "condition2": value2})