需求描述
为什么会有这个需求? 因为一些SQL输出很多(例如数千行),但我们只需要他的执行计划或SQL Monitor报告。
太多的输出不仅干扰了我们所需的信息,而且也拉长了elapsed time。
基本概念
方法其实就是SQL Plus的SET TERMOUT OFF选项。其说明参见这里:
Controls the display of output generated by commands in a script that is executed with @, @@ or START. OFF suppresses the display so that you can spool output to a file without displaying the output on screen. ON displays the output on screen. TERMOUT OFF does not affect output from commands you enter interactively or redirect to SQL*Plus from the operating system.
这里的核心意思是说:
- TERMOUT控制SQL的输出是否输出到屏幕,ON是输出,OFF是不输出
- TERMOUT默认是ON
- 对于交互式输出不管用,只适用于非交互式的通过 @, @@ 或 START调用的脚本。
SQL>settermout SP2-0265: termout must besetONorOFFSQL>showtermout termoutON极简示例
有两个脚本,main.sql调用test1.sql。内容如下,其中--是注释。
$ cat main.sql-- SET TERMOUT OFF@test1exit$ cat test1.sqlselectsysdatefromdual;由于TERMOUT默认是打开,因此可以看到输出:
$ sqlplus-S/ as sysdba @main SYSDATE ---------25-JUN-26把main.sql中的注释去掉,再次执行,这回没有输出了:
$ sqlplus-S/ as sysdba @main $如果SET TERMOUT写在被调用的脚本test1.sql,效果也是一样的。但放在调用脚本控制更方便。
实用场景示例
常用的场景包括:
- 只需要执行计划,不需要结果集
- 只需要实时SQL Monitor 报告,不需要结果集
我们来演示下场景1。
两个脚本,main.sql调用test1.sql:
$ cat main.sqlSETTERMOUTOFF@test1.sqlSETTERMOUTONSELECT*FROMTABLE(DBMS_XPLAN.DISPLAY_CURSOR);exit$ cat test1.sqlselect*fromemployees;执行结果只有执行计划,没有结果集:
$ sqlplus-S hr/******@orclpdb1@mainPLAN_TABLE_OUTPUT--------------------------------------------------------------------------------SQL_ID7jk33n4f4mpy9,child number0-------------------------------------select*fromhr.employeesPlanhashvalue:1445457117-------------------------------------------------------------------------------|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|-------------------------------------------------------------------------------|0|SELECTSTATEMENT||||3(100)|||1|TABLEACCESSFULL|EMPLOYEES|106|7314|3(0)|00:00:01|PLAN_TABLE_OUTPUT---------------------------------------------------------------------------------------------------------------------------------------------------------------13rowsselected.实用场景示例进阶
需求和上一个场景的唯一不同是,我们需要把输出写到文件中,但不包含结果集。例如实时SQL Monitor的html输出。
还是两个脚本,main.sql和test1.sql。
test1.sql不变。来看下main.sql的三种写法。
第一种写法:
$ cat main.sqlSPOOL test1.outSETTERMOUTOFF@test1.sqlSETTERMOUTONSELECT*FROMTABLE(DBMS_XPLAN.DISPLAY_CURSOR);SPOOLOFFEXIT执行如下:
$ sqlplus-Shr/********@orclpdb1 @main PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- SQL_ID 7jk33n4f4mpy9, child number0-------------------------------------select* from hr.employees Planhashvalue:1445457117-------------------------------------------------------------------------------|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|-------------------------------------------------------------------------------|0|SELECT STATEMENT||||3(100)|||1|TABLE ACCESS FULL|EMPLOYEES|106|7314|3(0)|00:00:01|PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- -------------------------------------------------------------------------------13rows selected. $ls-ltest1.out -rw-r--r--.1oracle oinstall65471Jun2509:53 test2.out $headtest1.out EMPLOYEE_ID FIRST_NAME LAST_NAME ----------- -------------------- ------------------------- EMAIL PHONE_NUMBER HIRE_DATE JOB_ID SALARY ------------------------- -------------------- --------- ---------- ---------- COMMISSION_PCT MANAGER_ID DEPARTMENT_ID -------------- ---------- -------------100Steven King SKING515.123.456717-JUN-03 AD_PRES2400090第二种写法:
$ cat main.sqlSETTERMOUTOFF@test1.sqlSETTERMOUTONSPOOL test1.outSELECT*FROMTABLE(DBMS_XPLAN.DISPLAY_CURSOR);SPOOLOFFEXIT执行如下:
$ sqlplus-Shr/********@orclpdb1 @main PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- SQL_ID 7jk33n4f4mpy9, child number0-------------------------------------select* from hr.employees Planhashvalue:1445457117-------------------------------------------------------------------------------|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|-------------------------------------------------------------------------------|0|SELECT STATEMENT||||3(100)|||1|TABLE ACCESS FULL|EMPLOYEES|106|7314|3(0)|00:00:01|PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- -------------------------------------------------------------------------------13rows selected. $ls-ltest1.out -rw-r--r--.1oracle oinstall1399Jun2509:56 test2.out $headtest2.out PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- SQL_ID 7jk33n4f4mpy9, child number0-------------------------------------select* from hr.employees Planhashvalue:1445457117-------------------------------------------------------------------------------第三种写法:
$ cat main.sqlSETTERMOUTOFF@test1.sqlSPOOL test1.outSELECT*FROMTABLE(DBMS_XPLAN.DISPLAY_CURSOR);SPOOLOFFEXIT执行如下:
$ sqlplus-Shr/********@orclpdb1 @main $ls-ltest1.out -rw-r--r--.1oracle oinstall1399Jun2510:00 test1.out $headtest1.out PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- SQL_ID 7jk33n4f4mpy9, child number0-------------------------------------select* from hr.employees Planhashvalue:1445457117-------------------------------------------------------------------------------哪一种写法是正确的?其实二和三都正确,但我常用三。
以上示例揭示了TERMOUT OFF的一个坑,即如果写在SPOOL后面,尽管不会输出到屏幕,但会将输出定向到spool文件。