为什么oracle总是在查询下解析?
select MY_SEQUENCE_SEQ.nextval
from dual
Quest SQL Optimizer(8.6.0)的SGA统计信息:
处决:83630
Parse_calls:83630
序列详情:
测试场景:
创建音序器:
CREATE SEQUENCE MY_SEQUENCE_SEQ
START WITH 1
MAXVALUE 999999999999999999999999999
MINVALUE 1
NOCYCLE
CACHE 20
NOORDER;
对符合v $ sql视图的用户执行此查询。
select executions,
parse_calls
from v$sql
where sql_text like 'select MY_SEQ%';`
执行序列n次
从第2点执行查询。
获得的结果:
EXECUTIONS - n
PARSE_CALSS - n
经过测试:
数据库:Oracle数据库10g版本10.2.0.4.0 - 64位生产
客户:Toad版本11.5.1.2
答案 0 :(得分:3)
这不是Oracle的错,它就是TOAD将SQL发送到oracle的方式。即toad不会将语句句柄缓存到oracle,它只是在完成时关闭它。
当查询发送到SQL引擎时,Oracle将对查询执行三个主要操作之一。
即我们想要处于案例3,我们当然不希望成为案例1! 那么每个案件何时会发生?
当SQL根本不在共享池中或SQL在共享池中但是使用的绑定可变数据/文字意味着当前的SQL不可用时,将发生硬解析。例如,假设我们发布了这个SQL三次select MY_SEQUENCE_SEQ.nextval from dual
。这将在Oracle第一次看到这个SQL并将其放入共享池时解析,并在第二次和第三次调用时进行软解析。我们可以很容易地看到这种情况:
SQL> select n.name, s.value from v$mystat s, v$statname n where n.statistic# = s.statistic# and n.name in ('parse count (hard)', 'parse count (total)');
NAME VALUE
-------------------- ----------
parse count (total) 522
parse count (hard) 287
SQL> select /* test1 */ MY_SEQUENCE_SEQ.nextval
2 from dual;
NEXTVAL
----------
62
SQL> select /* test1 */ MY_SEQUENCE_SEQ.nextval
2 from dual;
NEXTVAL
----------
63
SQL> select /* test1 */ MY_SEQUENCE_SEQ.nextval
2 from dual;
NEXTVAL
----------
64
SQL> select n.name, s.value from v$mystat s, v$statname n where n.statistic# = s.statistic# and n.name in ('parse count (hard)', 'parse count (total)');
NAME VALUE
-------------------- ----------
parse count (total) 526
parse count (hard) 288
SQL> select sql_text, executions, parse_calls from v$sql where sql_text like 'select /* test1 */%';
SQL_TEXT EXECUTIONS PARSE_CALLS
------------------------------ ---------- -----------
select /* test1 */ MY_SEQUENCE 3 3
_SEQ.nextval from dual
硬解析由一个登记,sql已经注册了3个解析,因此1个硬解析(将其放入共享池)和2个软解析。
为什么软解析?为了使“无解析”发生,客户端代码必须保持语句句柄并重新执行它。 即如果我们用Java编写这个,我们会写这个:
public static int getNextSeq(String str)
throws Exception
{
if (sel == null)
{
sel = con.prepareStatement("select MY_SEQUENCE_SEQ.nextval v from dual "+str);
}
ResultSet rs = sel.executeQuery();
int seqVal=0;
while (rs.next())
{
seqVal = rs.getInt("V");
}
return seqVal;
}
即。如果我们还没有这样做,我们只调用PrepareStatement。如果我们用
执行此代码System.out.println(getNextSeq(args[0]));
System.out.println(getNextSeq(args[0]));
System.out.println(getNextSeq(args[0]));
我们可以看到这一点:
SQL> host java Prep two
70
71
72
SQL> select sql_text, executions, parse_calls from v$sql where sql_text like 'select %two';
SQL_TEXT EXECUTIONS PARSE_CALLS
------------------------------ ---------- -----------
select MY_SEQUENCE_SEQ.nextval 3 1
v from dual two
现在oracle DID不解析SQL与1硬解析的区别。如果Java代码写得不好,我们会看到:
sel = con.prepareStatement("select MY_SEQUENCE_SEQ.nextval v from dual "+str);
ResultSet rs = sel.executeQuery();
SQL> host java Prep three
73
74
75
SQL> select sql_text, executions, parse_calls from v$sql where sql_text like 'select %three';
SQL_TEXT EXECUTIONS PARSE_CALLS
------------------------------ ---------- -----------
select MY_SEQUENCE_SEQ.nextval 3 3
v from dual three
现在我们看到解析count =执行。换句话说,我们软解析每个不理想的调用。再次不是Oracle限制,只是糟糕的客户端实现。
使用PL / SQL,我们不必担心这个问题。为什么? PL / SQL不会解析它作为运行SQL的优化很多(毫无疑问!)。 例如:SQL> declare
2 v_seq number;
3 begin
4 for idx in 1..3 loop
5 select MY_SEQUENCE_SEQ.nextval into v_seq from dual pls_test;
6 end loop;
7 end;
8 /
PL/SQL procedure successfully completed.
SQL> select sql_text, executions, parse_calls from v$sql where sql_text like 'SELECT %PLS_TEST';
SQL_TEXT EXECUTIONS PARSE_CALLS
------------------------------ ---------- -----------
SELECT MY_SEQUENCE_SEQ.NEXTVAL 3 1
FROM DUAL PLS_TEST
现在,pl / sql为我们做这个优化有一个警告,那就是参数SESSION_CACHED_CURSORS。在给定的会话中,Oracle将为我们打开一组游标(即它们是软打开的,即如果我们需要更多的游标,它将关闭它们)。因此,如果我们有SESSION_CACHED_CURSORS = 0并重复上述测试,我们将看到软解析突然陷入:
SQL> alter session set session_cached_cursors=0;
Session altered.
SQL> declare
2 v_seq number;
3 begin
4 for idx in 1..3 loop
5 select MY_SEQUENCE_SEQ.nextval into v_seq from dual pls_test2;
6 end loop;
7 end;
8 /
PL/SQL procedure successfully completed.
SQL> select sql_text, executions, parse_calls from v$sql where sql_text like 'SELECT %PLS_TEST2';
SQL_TEXT EXECUTIONS PARSE_CALLS
------------------------------ ---------- -----------
SELECT MY_SEQUENCE_SEQ.NEXTVAL 3 3
FROM DUAL PLS_TEST2
显然,缓存游标的值越高,我们就越需要避免软解析并达到避免完全解析的圣杯。
答案 1 :(得分:1)
这取决于您如何在客户端处理语句。如果你保留相同的变量/处理程序,则不应该对每个调用进行解析。
<小时/> 如果您在每次调用时创建并释放语句,您可以期望在共享池(软解析)或重新编译(硬解析)中搜索并找到sql。