[20250615]sqlplus大量赋值的问题.txt

[20250615]sqlplus大量赋值的问题.txt

--//前段时间测试大量绑定变量sq语句l执行"缓慢"的问题,实际上问题出在sqlplus客户端,通过pstack观察发现sqlplus要大量调用
--//lxoBinCmpMutl函数。当时猜测也许是sqlplus获得绑定变量定位方式"不合理"导致的情况,一直没时间验证这个问题,主要实际的情
--//况以及执行语句很少存在非常多绑定变量的情况。

1.环境:
SCOTT@book01p> @ ver2
==============================
PORT_STRING                   : x86_64/Linux 2.4.xx
VERSION                       : 21.0.0.0.0
BANNER                        : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
BANNER_FULL                   : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0
BANNER_LEGACY                 : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production
CON_ID                        : 0
PL/SQL procedure successfully completed.

2.建立测试脚本:
$ cat a.txt
set pagesize 0
set head off
set feedback off
set verify off
set timing off
spool b1.txt
select 'set termout off'  from dual;
select 'variable b'||to_char(level)||' number;'  from dual connect by level<=&1;
select 'begin'  from dual;
select ':b'||to_char(level)||' :='|| to_char(level)||';'  from dual connect by level<=&1;
select 'end;'  from dual;
select '/' from dual ;
select 'set termout on' txt from dual;
spool off

spool b2.txt
--select 'set timing on' txt from dual;
select 'select count(data_object_id) from t where (1,object_id) in (' txt from dual ;
select '(1,:b'||to_char(level)||'),' txt from dual connect by level<=&&1 -1 ;
select '(1,:b'||to_char(&&1)||'));' txt from dual ;
--select 'set timing off' txt from dual;
spool off

set pagesize 9999
set head on
set feedback on
--//分别建立2个文件b1.txt赋值,b2.txt脚本执行。

$ cat lx.gdb
set pagination off
set logging overwrite on
set logging on
set $lx_count  = 0

break lxoBinCmpMutl
commands
 silent
 printf "lxoBinCmpMutl count %02d -", ++$lx_count
 c
 end

--//set $lx_count  = 0

3.测试:
--//session 1:
SCOTT@book01p> @ spid
==============================
SID                           : 142
SERIAL#                       : 40846
PROCESS                       : 3848
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SERVER                        : DEDICATED
SPID                          : 3850
PID                           : 49
P_SERIAL#                     : 7
KILL_COMMAND                  : alter system kill session '142,40846' immediate;
PL/SQL procedure successfully completed.
--//sqlplus进程号是3848。

--//window 1:
$ gdb -f -p 3848 -x lx.gdb

--//session 1:
SCOTT@book01p> variable c1 number

--//window 1:
Breakpoint 1 at 0x7f6edc932ec0
(gdb) c
Continuing.
lxoBinCmpMutl count 01
....
lxoBinCmpMutl count 47
--//可以发现简单的定义新的变量c1,调用lxoBinCmpMutl 47次。
--//按ctrl+c退出gdb,再次启动执行
$ gdb -f -p 3848 -x lx.gdb

--//session 1,再次定义新的变量c2:
SCOTT@book01p> variable c2 number

--//window 1:
Breakpoint 1 at 0x7f6edc932ec0
(gdb) c
Continuing.
lxoBinCmpMutl count 01
...
lxoBinCmpMutl count 47
lxoBinCmpMutl count 48
--//可以发现简单的定义新的变量c2,调用lxoBinCmpMutl 48次,比前面的variable c1 number多调用1次lxoBinCmpMutl。
--//可以推测定义变量越多调用lxoBinCmpMutl越多。赋值以及sqlplus执行sql语句也出现类似的情况,不再测试。
--//估计sqlplus探查定义变量的算法采用逐个探查的方式,如果类似存在hash链表之类的探查就不存在这个问题。
--//继续看后面的测试。

4.继续:
--//假设sqlplus会话存在许多绑定变量。

SCOTT@book01p> @ a.txt 65535
-//输出略。
--//编辑b1.txt,并且适当编辑满足前面begin..end之间可以定义32767个绑定变量的限制。

SCOTT@book01p> @ b1.txt
--//等待执行完成。

$ ps -efvp 4171
  PID TTY      STAT   TIME  MAJFL   TRS   DRS   RSS %MEM COMMAND
 4171 pts/7    Ss+    0:01      0    13 122270 16460  0.2 /u01/app/oracle/product/21.0.0/dbhome_1/bin/sqlplus

$ ps -efvp 4171
  PID TTY      STAT   TIME  MAJFL   TRS   DRS   RSS %MEM COMMAND
 4171 pts/7    Rs+    2:05      0    13 153938 46240  0.5 /u01/app/oracle/product/21.0.0/dbhome_1/bin/sqlplus
--//执行过程可以发现DRS,RSS不断增加。

$ ps -efvp 4171
  PID TTY      STAT   TIME  MAJFL   TRS   DRS   RSS %MEM COMMAND
 4171 pts/7    Ss+    4:23      0    13 156906 50476  0.6 /u01/app/oracle/product/21.0.0/dbhome_1/bin/sqlplus

画一个表格:
---------------------------------------------------
执行语句                   gdb最后显示
---------------------------------------------------
select :b1 from dual      lxoBinCmpMutl count 5022
select :b2 from dual      lxoBinCmpMutl count 5023
select :b3 from dual      lxoBinCmpMutl count 5024
select :b4 from dual      lxoBinCmpMutl count 5025
...
select :b9 from dual      lxoBinCmpMutl count 5030
--//每次+1.5030-5022=8
select :b10 from dual     lxoBinCmpMutl count 5022 --//与前面:b1测试一样。
select :b11 from dual     lxoBinCmpMutl count 5023 --//与前面:b2测试一样。
select :b12 from dual     lxoBinCmpMutl count 5024 --//与前面:b3测试一样。
...
select :b99 from dual     lxoBinCmpMutl count 5111
--//每次+1.5111-5022 = 89
--//测试到这里,实际上可以猜测sqlplus按照变量的长度建立1个链表,根据定义顺序存放。或者按照变量的长度分类。
select :b100 from dual    lxoBinCmpMutl count 5022 --//验证自己的判断。
select :b101 from dual    lxoBinCmpMutl count 5023
...
select :b300 from dual    lxoBinCmpMutl count 5222
select :b300 from dual    lxoBinCmpMutl count 5322
...
select :b999 from dual    lxoBinCmpMutl count 5921
--//每次+1. 5921-5022  = 899
select :b1000 from dual   lxoBinCmpMutl count 5022 --//验证自己的判断。
...
select :b2000 from dual   lxoBinCmpMutl count 6022
...
select :b9999 from dual   lxoBinCmpMutl count 14021
--//每次+1. 14021-5022 = 8999
select :b10000 from dual  lxoBinCmpMutl count 5023 --//这里为什么比前面多1,是因为登录时我的环境定义了变量MY_SID,长度为6.
...
select :b65535 from dual  lxoBinCmpMutl count 60558
--//每次+1. 60558-5023 = 55535

select :b0 from dual      lxoBinCmpMutl count 56    --//该变量不存在,按照理解应该至少调用lxoBinCmpMutl 5030次。5030-56= 4974
select :a01 from dual     lxoBinCmpMutl count 137   --//该变量不存在,按照理解应该至少调用lxoBinCmpMutl 5111次。5111-137 = 4974
select :b65536 from dual  lxoBinCmpMutl count 55584 --//该变量不存在,按照理解应该至少调用lxoBinCmpMutl 60558次。60558-55584 = 4974

--//gdb可以不需要退出,按ctrl+c中断后,执行set $lx_count=0,可以重新计数。

select :b1,:b1 from dual         lxoBinCmpMutl count 9996
select :b1,:b2 from dual         lxoBinCmpMutl count 9998
select :b65535,b65534 from dual  lxoBinCmpMutl count 121068

--//看看执行b2.txt的情况:

SCOTT@book01p> @ sl all
alter session set statistics_level = all;
Session altered.

SCOTT@book01p> set timing on
SCOTT@book01p> @ b2.txt
COUNT(DATA_OBJECT_ID)
---------------------
                 3970
1 row selected.
Elapsed: 00:04:53.35

SCOTT@book01p> @ b2.txt
COUNT(DATA_OBJECT_ID)
---------------------
                 3970
1 row selected.
Elapsed: 00:04:47.79

SCOTT@book01p> @ dpc '' '-peeked_binds -projection' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  97pbm7taxr6d8, child number 1
-------------------------------------
select count(data_object_id) from t where (1,object_id) in ( (1,:b1),
(1,:b2), (1,:b3), (1,:b4), (1,:b5), (1,:b6), (1,:b7), (1,:b8), (1,:b9),
(1,:b10), (1,:b11), (1,:b12), (1,:b13), (1,:b14), (1,:b15), (1,:b16),
(1,:b17), (1,:b18), (1,:b19), (1,:b20), (1,:b21), (1,:b22), (1,:b23),
(1,:b24), (1,:b25), (1,:b26), (1,:b27), (1,:b28), (1,:b29), (1,:b30),
(1,:b31), (1,:b32), (1,:b33), (1,:b34), (1,:b35), (1,:b36), (1,:b37),
(1,:b38), (1,:b39), (1,:b40), (1,:b41), (1,:b42), (1,:b43), (1,:b44),
(1,:b45), (1,:b46), (1,:b47), (1,:b48), (1,:b49), (1,:b50), (1,:b51),
(1,:b52), (1,:b53), (1,:b54), (1,:b55), (1,:b56), (1,:b57), (1,:b58),
(1,:b59), (1,:b60), (1,:b61), (1,:b62), (1,:b63), (1,:b64), (1,:b65),
(1,:b66), (1,:b67), (1,:b68), (1,:b69), (1,:b70), (1,:b71), (1,:b72),
(1,:b73), (1,:b74), (1,:b75), (1,:b76), (1,:b77), (1,:b78), (1,:b79),
(1,:b80), (1,:b81), (1,:b82), (1,:b83), (1,:b84), (1,:b85), (1,:b86),
(1,:b87), (1,:b88), (1,:b89), (1,:b90), (1,:b91), (1,:b92), (1,:b93),
(1,:b94), (1,:b95)
Plan hash value: 2966233522
---------------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |       |  1013 (100)|          |      1 |00:00:00.03 |    1479 |
|   1 |  SORT AGGREGATE    |      |      1 |      1 |     7 |            |          |      1 |00:00:00.03 |    1479 |
|*  2 |   TABLE ACCESS FULL| T    |      1 |   4808 | 33656 |  1013  (60)| 00:00:01 |   3970 |00:00:00.03 |    1479 |
---------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1
   2 - SEL$1 / "T"@"SEL$1"
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(("DATA_OBJECT_ID" IS NOT NULL AND INTERNAL_FUNCTION("OBJECT_ID")))
39 rows selected.
Elapsed: 00:00:15.65
--//执行计划选择全表扫描,但是注意看A-Time=00:00:00.03,大部分时间花在sqlplus的客户端探查绑定变量值到sql语句上。

5.小结:
--//猜测sqlplus按照变量的长度建立1个链表,根据定义顺序存放或者按照变量的长度分类。
--//不清楚变量不存在的情况。
作者:lfree原文地址:https://www.cnblogs.com/lfree/p/18937105

%s 个评论

要回复文章请先登录注册