绑定变量对于SQL性能的影响
绑定变量
SQL> set timing on
SQL> alter session set statistics_level=all;
VAR v4 VARCHAR2(32)
VAR v5 VARCHAR2(128)
VAR v6 VARCHAR2(128)
EXEC :v4:='007680'
EXEC :v5:='P1803585080457506817'
EXEC :v6:='202406200826069960000000000'
SELECT AD.* FROM TEST1.TESTTABLE AD WHERE AD.InstitutionID = :v4 AND AD.PaymentTxSn = :v5 AND AD.SourceSystemNo = :v6 AND Status = 30;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Elapsed: 00:00:00.87
SQL> SQL_ID 06nzu53vnm5gf, child number 0
-------------------------------------
SELECT AD.* FROM AGGREGATE1.TESTTABLE AD WHERE
AD.InstitutionID = :v4 AND AD.PaymentTxSn = :v5 AND AD.SourceSystemNo =
:v6 AND Status = 30
Plan hash value: 4134968517
------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 0 |00:00:00.86 | 542K|
|* 1 | TABLE ACCESS BY INDEX ROWID BATCHED| TESTTABLE | 1 | 1 | 0 |00:00:00.86 | 542K|
|* 2 | INDEX RANGE SCAN | U_TESTTABLE_INSTID_TXSN | 1 | 1 | 572K|00:00:00.08 | 6340 |
------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(("AD"."PAYMENTTXSN"=:V5 AND "AD"."SOURCESYSTEMNO"=:V6 AND TO_NUMBER("STATUS")=30))
2 - access("AD"."INSTITUTIONID"=:V4)
Elapsed: 00:00:00.03
SQL> alter session set statistics_level=all;
VAR v4 VARCHAR2(32)
VAR v5 VARCHAR2(128)
VAR v6 VARCHAR2(128)
EXEC :v4:='007759'
EXEC :v5:='P1803585080457506817'
EXEC :v6:='202406200826069960000000000'
SELECT AD.* FROM AGGREGATE1.TESTTABLE AD WHERE AD.InstitutionID = :v4 AND AD.PaymentTxSn = :v5 AND AD.SourceSystemNo = :v6 AND Status = 30;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Elapsed: 00:00:12.48
SQL> SQL_ID 06nzu53vnm5gf, child number 0
-------------------------------------
SELECT AD.* FROM AGGREGATE1.TESTTABLE AD WHERE
AD.InstitutionID = :v4 AND AD.PaymentTxSn = :v5 AND AD.SourceSystemNo =
:v6 AND Status = 30
Plan hash value: 4134968517
---------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
---------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 0 |00:00:12.48 | 11M| 4 |
|* 1 | TABLE ACCESS BY INDEX ROWID BATCHED| TESTTABLE | 1 | 1 | 0 |00:00:12.48 | 11M| 4 |
|* 2 | INDEX RANGE SCAN | U_TESTTABLE_INSTID_TXSN | 1 | 1 | 12M|00:00:01.54 | 128K| 0 |
---------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(("AD"."PAYMENTTXSN"=:V5 AND "AD"."SOURCESYSTEMNO"=:V6 AND TO_NUMBER("STATUS")=30))
2 - access("AD"."INSTITUTIONID"=:V4)
Elapsed: 00:00:00.03
全使用绑定变量第一次执行sql之后,紧接着第二次执行不同绑定变量的值情况下第一次执行0.87秒第二次执行12.48秒,是因为oracle数据库为了防止大量硬解析做的优化工作。第二次会沿用第一次的执行计划。
不绑定变量
SQL> alter session set statistics_level=all;
VAR v5 VARCHAR2(128)
VAR v6 VARCHAR2(128)
EXEC :v5:='P1803585080457506817'
EXEC :v6:='202406200826069960000000000'
SELECT AD.* FROM AGGREGATE1.TESTTABLE AD WHERE AD.InstitutionID = '007759' AND AD.PaymentTxSn = :v5 AND AD.SourceSystemNo = :v6 AND Status = 30;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Elapsed: 00:00:00.00
SQL_ID a7x2cx23c1034, child number 0
-------------------------------------
SELECT AD.* FROM AGGREGATE1.TESTTABLE AD WHERE
AD.InstitutionID = '007759' AND AD.PaymentTxSn = :v5 AND
AD.SourceSystemNo = :v6 AND Status = 30
Plan hash value: 1281936248
------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 0 |00:00:00.01 | 4 |
|* 1 | TABLE ACCESS BY INDEX ROWID BATCHED| TESTTABLE | 1 | 1 | 0 |00:00:00.01 | 4 |
|* 2 | INDEX RANGE SCAN | I_TESTTABLE_PAYMENTTXSN | 1 | 1 | 0 |00:00:00.01 | 4 |
------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(("AD"."SOURCESYSTEMNO"=:V6 AND "AD"."INSTITUTIONID"='007759' AND TO_NUMBER("STATUS")=30))
2 - access("AD"."PAYMENTTXSN"=:V5)
Elapsed: 00:00:00.10
SQL> alter session set statistics_level=all;
VAR v5 VARCHAR2(128)
VAR v6 VARCHAR2(128)
EXEC :v5:='P1803585080457506817'
EXEC :v6:='202406200826069960000000000'
SELECT AD.* FROM AGGREGATE1.TESTTABLE AD WHERE AD.InstitutionID = '007898' AND AD.PaymentTxSn = :v5 AND AD.SourceSystemNo = :v6 AND Status = 30;
select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
Elapsed: 00:00:00.01
SQL_ID gn57p95cqx1ga, child number 0
-------------------------------------
SELECT AD.* FROM AGGREGATE1.TESTTABLE AD WHERE
AD.InstitutionID = '007898' AND AD.PaymentTxSn = :v5 AND
AD.SourceSystemNo = :v6 AND Status = 30
Plan hash value: 4134968517
------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 0 |00:00:00.01 | 6 |
|* 1 | TABLE ACCESS BY INDEX ROWID BATCHED| TESTTABLE | 1 | 1 | 0 |00:00:00.01 | 6 |
|* 2 | INDEX RANGE SCAN | U_TESTTABLE_INSTID_TXSN | 1 | 1 | 1 |00:00:00.01 | 5 |
------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(("AD"."PAYMENTTXSN"=:V5 AND "AD"."SOURCESYSTEMNO"=:V6 AND TO_NUMBER("STATUS")=30))
2 - access("AD"."INSTITUTIONID"='007898')
Elapsed: 00:00:00.04
把机构id绑定变量取消了,带入不同机构id情况下执行计划改变了,并且每次执行时间都很短,符合开发规范中对于绑定变量不可以使用在分布不均匀的列上的说法
总结:
绑定变量:
SQL在数据库认为就是一条SQL,该SQL在硬解析后会统一使用一个执行计划,在重新硬解析前都会沿用该执行计划,即便有效率高的执行计划,此时数据库也不再考虑使用,因此出现慢SQL。
不绑定变量:
SQL参数不同,在数据库认为是不同的SQL,每条SQL会分别解析出自己合适的执行计划,会减少慢SQL的发生,考虑当前环境因素,建议在报表类或分析类场景不绑定变量。
- 对于字段值比较少,个数小于100,且分布很不均匀的情况不要使用绑定变量,比如说状态、性别、类型等,还有绑定变量最好用于等值连接
- 对于那种大于小于列上有索引,并且会出现跨度很大、跨度很小两级分化很严重的情况也不要使用绑定变量