forked from momokind/orasql
-
Notifications
You must be signed in to change notification settings - Fork 0
/
printsql.prc
706 lines (665 loc) · 33.5 KB
/
printsql.prc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
create or replace procedure PRINTSQL
(i_n_id in number,
i_vc_idtype in varchar2) is
/*
功能: 打印对应spid或sid所对应的sql以及其执行计划
作者: 老熊,dbsnake
创建日期:2010-11-12
输入参数:
i_n_id: 输入的spid或sid
i_vc_idtype : 输入的ID的类型,'SPID'表示输入的是spid,'SID'表示输入的是sid.
输出参数:
无
输入输出参数:
无
调用到的存储过程:
无
*/
o_vc_return_flag varchar2(4000);
type typsqltext is table of varchar2(1000) index by binary_integer;
typsqltexts typsqltext;
vc_paddr varchar2(4000);
n_hashvalue number;
n_childnumber number;
rec_session v$session%rowtype;
rec_sql v$sql%rowtype;
/*select hash_value,child_number,plan_hash_value,executions,buffer_gets,buffer_gets/decode(executions,0,1,executions) gets_per_exec,
rows_processed,rows_processed/decode(executions,0,1,executions) rows_per_exec,
disk_reads,disk_reads/decode(executions,0,1,executions) reads_per_exec,
cpu_time/1000000 cpu_time,cpu_time/decode(executions,0,1,executions)/1000000 cpu_per_exec,
ELAPSED_TIME/1000000 ELAPSED_TIME,ELAPSED_TIME/decode(executions,0,1,executions)/1000000 ela_per_exec
from v$sql where hash_value=&1
and rownum<=100;*/
type type_hash_value is table of v$sql.HASH_VALUE%type index by binary_integer;
hash_values type_hash_value;
type type_child_number is table of v$sql.CHILD_NUMBER%type index by binary_integer;
child_numbers type_child_number;
type type_plan_hash_value is table of v$sql.PLAN_HASH_VALUE%type index by binary_integer;
plan_hash_values type_plan_hash_value;
type type_execution is table of v$sql.EXECUTIONS%type index by binary_integer;
executions type_execution;
type type_buffer_get is table of v$sql.BUFFER_GETS%type index by binary_integer;
buffer_gets type_buffer_get;
type type_gets_per_exec is table of v$sql.BUFFER_GETS%type index by binary_integer;
gets_per_execs type_gets_per_exec;
type type_rows_processed is table of v$sql.ROWS_PROCESSED%type index by binary_integer;
rows_processeds type_rows_processed;
type type_rows_per_exec is table of v$sql.ROWS_PROCESSED%type index by binary_integer;
rows_per_execs type_rows_per_exec;
type type_disk_read is table of v$sql.DISK_READS%type index by binary_integer;
disk_reads type_disk_read;
type type_reads_per_exec is table of v$sql.DISK_READS%type index by binary_integer;
reads_per_execs type_reads_per_exec;
type type_cpu_time is table of v$sql.CPU_TIME%type index by binary_integer;
cpu_times type_cpu_time;
type type_cpu_per_exec is table of v$sql.CPU_TIME%type index by binary_integer;
cpu_per_execs type_cpu_per_exec;
type type_ELAPSED_TIME is table of v$sql.ELAPSED_TIME%type index by binary_integer;
ELAPSED_TIMEs type_ELAPSED_TIME;
type type_ela_per_exec is table of v$sql.ELAPSED_TIME%type index by binary_integer;
ela_per_execs type_ela_per_exec;
-- cursor c_display_cursor(in_address varchar2, in_hash_value number, in_child_number number) is
s_display_cursor varchar2(32767) := '
select case when access_predicates is not null or filter_predicates is not null then ''*'' else '' '' end || substr(to_char(id, ''999''), -3) as p_id,
lpad('' '', depth) || operation || '' '' || options as operation,
object_name as name,
starts,
cardinality as e_rows,
outrows as a_rows,
to_char(to_number(substr(e_time_interval, 2, 9)) * 24 + to_number(substr(e_time_interval, 12, 2)), ''FM900'') || substr(e_time_interval, 14, 9) as a_time,
crgets + cugets as buffers,
case reads when 0 then null else reads end as reads,
case writes when 0 then null else writes end as writes,
case other_tag
when ''PARALLEL_TO_SERIAL'' then ''P->S''
when ''PARALLEL_COMBINED_WITH_PARENT'' then ''PCWP''
when ''PARALLEL_COMBINED_WITH_CHILD'' then ''PCWC''
when ''SERIAL_TO_PARALLEL'' then ''S->P''
when ''PARALLEL_TO_PARALLEL'' then ''P->P''
when ''PARALLEL_FROM_SERIAL'' then ''P<-S''
else other_tag end as in_out,
partition_start,
partition_stop,
distribution,
mem_opt,
mem_one,
last_mem_used || case last_mem_usage when ''OPTIMAL'' then '' (0)'' when ''ONE PASS'' then '' (1)'' when ''MULTI-PASS'' then '' (M)'' end,
case last_degree when 0 then null when 1 then null else last_degree end as last_degree,
--opt_cnt,
--one_cnt,
--multi_cnt,
--max_tmp,
last_tmp,
access_predicates,
filter_predicates,
dynamic_sampling_flag,
id
from (
SELECT /*+ opt_param(''parallel_execution_enabled'', ''false'') */
id, position, depth , operation, options, object_name, cardinality, bytes, temp_space, cost, io_cost,
cpu_cost, partition_start, partition_stop, object_node, other_tag, distribution, null, access_predicates, filter_predicates,
null, null, null, starts, outrows, crgets, cugets, reads, writes, etime, e_time_interval, mem_opt, mem_one, last_mem_used, last_degree, last_mem_usage,
opt_cnt, one_cnt, multi_cnt, max_tmp, last_tmp, dynamic_sampling_flag from (
select /*+ no_merge */
id, depth, position, operation, options,
cost, cardinality, bytes, object_node,
object_name, other_tag, partition_start,
partition_stop, distribution, temp_space, io_cost,
cpu_cost, filter_predicates, access_predicates, other,
last_starts starts,
last_output_rows outrows,
last_cr_buffer_gets crgets,
last_cu_buffer_gets cugets,
last_disk_reads reads,
last_disk_writes writes,
last_elapsed_time etime,
to_char(numtodsinterval(round(last_elapsed_time/10000)*10000/1000000, ''SECOND'')) as e_time_interval,
estimated_optimal_size mem_opt,
estimated_onepass_size mem_one,
last_memory_used last_mem_used,
last_degree,
last_execution last_mem_usage,
optimal_executions opt_cnt,
onepass_executions one_cnt,
multipasses_executions multi_cnt,
max_tempseg_size max_tmp,
last_tempseg_size last_tmp,
case 0 /*instr(other_xml, ''dynamic_sampling'')*/ when 0 then NULL else ''YES'' end as dynamic_sampling_flag
from V$SQL_PLAN_STATISTICS_ALL vp
--where address = hextoraw(:in_address)
where hash_value = :in_hash_value
and child_number = :in_child_number)
)
order by id';
s_display_cursor2 varchar2(32767) := '
select case when access_predicates is not null or filter_predicates is not null then ''*'' else '' '' end || substr(to_char(id, ''999''), -3) as p_id,
lpad('' '', depth) || operation || '' '' || options as operation,
object_name as name,
cardinality as e_rows,
bytes,
temp_space,
cost,
cpu_cost,
object_node,
case other_tag
when ''PARALLEL_TO_SERIAL'' then ''P->S''
when ''PARALLEL_COMBINED_WITH_PARENT'' then ''PCWP''
when ''PARALLEL_COMBINED_WITH_CHILD'' then ''PCWC''
when ''SERIAL_TO_PARALLEL'' then ''S->P''
when ''PARALLEL_TO_PARALLEL'' then ''P->P''
when ''PARALLEL_FROM_SERIAL'' then ''P<-S''
else other_tag end as in_out,
partition_start,
partition_stop,
distribution,
access_predicates,
filter_predicates,
dynamic_sampling_flag,
id
from (
SELECT /*+ opt_param(''parallel_execution_enabled'', ''false'') */
id, position, depth , operation, options, object_name, cardinality, bytes, temp_space, cost, io_cost,
cpu_cost, partition_start, partition_stop, object_node, other_tag, distribution, null, access_predicates, filter_predicates,
null, null, null, starts, outrows, crgets, cugets, reads, writes, etime, e_time_interval, mem_opt, mem_one, last_mem_used, last_degree, last_mem_usage,
opt_cnt, one_cnt, multi_cnt, max_tmp, last_tmp, dynamic_sampling_flag from (
select /*+ no_merge */
id, depth, position, operation, options,
cost, cardinality, bytes, object_node,
object_name, other_tag, partition_start,
partition_stop, distribution, temp_space, io_cost,
cpu_cost, filter_predicates, access_predicates, other,
0 starts,
0 outrows,
0 crgets,
0 cugets,
0 reads,
0 writes,
0 etime,
0 e_time_interval,
0 mem_opt,
0 mem_one,
null last_mem_used,
0 last_degree,
null last_mem_usage,
0 opt_cnt,
0 one_cnt,
0 multi_cnt,
0 max_tmp,
0 last_tmp,
case 0 /*instr(other_xml, ''dynamic_sampling'')*/ when 0 then NULL else ''YES'' end as dynamic_sampling_flag
from V$SQL_PLAN vp
--where address = hextoraw(:in_address)
where hash_value = :in_hash_value
and child_number = :in_child_number)
)
order by id';
type t_list_varchar2 is table of varchar2(4000) index by pls_integer;
type t_column_record is record (
a_data t_list_varchar2,
b_has_data boolean,
s_heading varchar2(255),
b_is_number boolean default false,
s_alignment varchar2(20),
n_max_size pls_integer);
type t_column_list is table of t_column_record index by pls_integer;
a_column_list t_column_list;
n_row_size pls_integer;
s_row varchar2(4000);
a_access_pred t_list_varchar2;
a_filter_pred t_list_varchar2;
s_plan_hash varchar2(255);
a_dyn_sampl t_list_varchar2;
a_id_list t_list_varchar2;
s_output varchar2(32767);
s_sql_address varchar2(255);
s_hash_value varchar2(255);
s_child_num varchar2(255);
b_has_stat boolean := TRUE;
max_line_size constant pls_integer := 255;
c_display_cursor sys_refcursor;
n_cnt pls_integer;
function has_collection_only_nulls(in_coll in t_list_varchar2)
return boolean is
b_return boolean := true;
begin
if in_coll.count > 0 then
for i in in_coll.first..in_coll.last loop
if in_coll(i) is not null then
b_return := false;
exit;
end if;
end loop;
end if;
return b_return;
end has_collection_only_nulls;
function get_max_size(in_coll in t_list_varchar2)
return pls_integer is
n_return pls_integer := 0;
begin
if in_coll.count > 0 then
for i in in_coll.first..in_coll.last loop
if in_coll(i) is not null then
n_return := greatest(n_return, length(in_coll(i)));
end if;
end loop;
end if;
return n_return;
end get_max_size;
function display_cursor_format_number(in_data in varchar2)
return varchar2 is
s_return varchar2(20);
s_trail varchar2(32767);
s_data varchar2(32767);
n_number number;
n_delim_pos number;
e_num_val_error exception;
pragma exception_init(e_num_val_error, -6502);
begin
n_delim_pos := instr(in_data, ' ');
if n_delim_pos > 0 then
s_trail := substr(in_data, n_delim_pos);
s_data := substr(in_data, 1, n_delim_pos - 1);
else
s_data := in_data;
end if;
n_number := to_number(s_data);
s_return :=
case
when n_number >= 100000000000000000000 then to_char(n_number/1000000000000000000, 'FM99999') || 'E'
when n_number >= 100000000000000000 then to_char(n_number/1000000000000000, 'FM99999') || 'P'
when n_number >= 100000000000000 then to_char(n_number/1000000000000, 'FM99999') || 'T'
when n_number >= 100000000000 then to_char(n_number/1000000000, 'FM99999') || 'G'
when n_number >= 100000000 then to_char(n_number/1000000, 'FM99999') || 'M'
when n_number >= 100000 then to_char(n_number/1000, 'FM99999') || 'K'
else to_char(n_number, 'FM99999')
end;
return s_return || s_trail;
exception
when e_num_val_error then
return in_data;
end display_cursor_format_number;
procedure put_line_smart(in_string in varchar2, in_line_prefix in varchar2 default '', in_line_size in pls_integer default 180) is
n_offset pls_integer;
s_delimiter varchar2(1);
n_size_current_line pls_integer;
n_line_counter pls_integer;
begin
n_offset := 1;
n_size_current_line := in_line_size;
n_line_counter := 1;
while case when n_line_counter > 1 and length(in_line_prefix) > 0
then length(in_string) + length(in_line_prefix)
else length(in_string) end
+ 1 - n_offset > in_line_size loop
-- dbms_output.put_line('Debug n_offset: ' || n_offset);
if n_line_counter > 1 and length(in_line_prefix) > 0 then
n_size_current_line := greatest(n_size_current_line - length(in_line_prefix), length(in_line_prefix) + 10);
end if;
-- dbms_output.put_line('Debug n_size_current_line: ' || n_size_current_line);
loop
s_delimiter := substr(in_string, n_offset - 1 + n_size_current_line, 1);
exit when s_delimiter in (' ', chr(9), chr(10), chr(13)/*, '(', ')', '[', ']'*/) or n_size_current_line < 1;
n_size_current_line := n_size_current_line - 1;
end loop;
if n_size_current_line < 1 then
if n_line_counter > 1 and length(in_line_prefix) > 0 then
n_size_current_line := greatest(n_size_current_line - length(in_line_prefix), length(in_line_prefix) + 10);
else
n_size_current_line := in_line_size;
end if;
end if;
if s_delimiter in (chr(13), chr(10)) then
n_size_current_line := n_size_current_line - 1;
end if;
dbms_output.put_line(case when n_line_counter > 1 then in_line_prefix end || substr(in_string, n_offset, n_size_current_line));
if s_delimiter in (chr(13), chr(10)) then
while substr(in_string, n_offset - 1 + n_size_current_line, 1) in (chr(10), chr(13)) loop
n_size_current_line := n_size_current_line + 1;
end loop;
end if;
n_offset := n_offset + n_size_current_line;
n_size_current_line := in_line_size;
n_line_counter := n_line_counter + 1;
end loop;
dbms_output.put_line(case when n_line_counter > 1 then in_line_prefix end || substr(in_string, n_offset));
end put_line_smart;
begin
dbms_output.put_line('--------------------------------------------------------------------------------------');
if ( upper(i_vc_idtype) = 'SPID' ) then
select addr into vc_paddr from v$process where spid=to_char(i_n_id);
select * into rec_session from v$session where paddr=vc_paddr;
select decode(sql_hash_value,0,prev_hash_value,sql_hash_value) into n_hashvalue from v$session where sid=rec_session.SID;
select sql_text bulk collect into typsqltexts from v$sqltext where hash_value=n_hashvalue order by piece;
if ( typsqltexts.count > 0 ) then
for i in typsqltexts.first .. typsqltexts.last loop
---这里处理掉"dbms_output.put_line"不能处理超过255个字符的限制,并且考虑到了sql语句中可能有中文
loop
exit when typsqltexts(i) is null;
dbms_output.put_line( substrb( typsqltexts(i), 1, 254 ) );
typsqltexts(i) := substrb( typsqltexts(i), 255 );
end loop;
end loop;
else
dbms_output.put_line('The sql text has been aged out from the shared pool.');
end if;
elsif ( upper(i_vc_idtype) = 'SID' ) then
select * into rec_session from v$session where sid=i_n_id;
select decode(sql_hash_value,0,prev_hash_value,sql_hash_value) into n_hashvalue from v$session where sid=i_n_id;
select sql_text bulk collect into typsqltexts from v$sqltext where hash_value=n_hashvalue order by piece;
if ( typsqltexts.count > 0 ) then
for i in typsqltexts.first .. typsqltexts.last loop
---这里处理掉"dbms_output.put_line"不能处理超过255个字符的限制,并且考虑到了sql语句中可能有中文
loop
exit when typsqltexts(i) is null;
dbms_output.put_line( substrb( typsqltexts(i), 1, 254 ) );
typsqltexts(i) := substrb( typsqltexts(i), 255 );
end loop;
end loop;
else
dbms_output.put_line('The sql text has been aged out from the shared pool.');
end if;
else
dbms_output.put_line('invalid input id type parameter!');
return;
end if;
dbms_output.put_line('--------------------------------------------------------------------------------------');
dbms_output.put_line('The session id is ' || rec_session.SID);
dbms_output.put_line('The status is ' || rec_session.STATUS);
dbms_output.put_line('The sql hash value is ' || rec_session.SQL_HASH_VALUE);
--dbms_output.put_line('The child cursor number is ' || rec_session.SQL_CHILD_NUMBER);
dbms_output.put_line('The prev hash value is ' || rec_session.PREV_HASH_VALUE);
--dbms_output.put_line('The prev child cursor number is ' || rec_session.PREV_CHILD_NUMBER);
dbms_output.put_line('The osuser is ' || rec_session.OSUSER);
dbms_output.put_line('The machine is ' || rec_session.MACHINE);
dbms_output.put_line('The terminal is ' || rec_session.TERMINAL);
dbms_output.put_line('The program is ' || rec_session.PROGRAM);
--dbms_output.put_line('The event is ' || rec_session.EVENT);
dbms_output.put_line('--------------------------------------------------------------------------------------');
--demo: alter system kill session '417,21188' immediate;
dbms_output.put_line('alter system kill session ''' || rec_session.SID || ',' || rec_session.SERIAL# || ''' immediate;');
select hash_value,child_number,plan_hash_value,executions,buffer_gets,buffer_gets/decode(executions,0,1,executions) gets_per_exec,
rows_processed,rows_processed/decode(executions,0,1,executions) rows_per_exec,
disk_reads,disk_reads/decode(executions,0,1,executions) reads_per_exec,
cpu_time/1000000 cpu_time,cpu_time/decode(executions,0,1,executions)/1000000 cpu_per_exec,
ELAPSED_TIME/1000000 ELAPSED_TIME,ELAPSED_TIME/decode(executions,0,1,executions)/1000000 ela_per_exec
bulk collect into hash_values,child_numbers,plan_hash_values,executions,buffer_gets,gets_per_execs,
rows_processeds,rows_per_execs,disk_reads,reads_per_execs,cpu_times,cpu_per_execs,ELAPSED_TIMEs,ela_per_execs
from v$sql where hash_value=n_hashvalue and rownum<=100;
if( hash_values.count > 0 ) then
for i in hash_values.first .. hash_values.last loop
dbms_output.put_line('--------------------------------------------------------------------------------------');
dbms_output.put_line('The hash_value is ' || hash_values(i));
dbms_output.put_line('The child_number is ' || child_numbers(i));
dbms_output.put_line('The plan_hash_value is ' || plan_hash_values(i));
dbms_output.put_line('The execution is ' || executions(i));
dbms_output.put_line('The buffer_gets is ' || buffer_gets(i));
dbms_output.put_line('The gets_per_exec is ' || gets_per_execs(i));
dbms_output.put_line('The rows_processed is ' || rows_processeds(i));
dbms_output.put_line('The rows_per_exec is ' || rows_per_execs(i));
dbms_output.put_line('The disk_reads is ' || disk_reads(i));
dbms_output.put_line('The reads_per_exec is ' || reads_per_execs(i));
dbms_output.put_line('The cpu_time is ' || cpu_times(i));
dbms_output.put_line('The cpu_per_exec is ' || cpu_per_execs(i));
dbms_output.put_line('The ELAPSED_TIME is ' || ELAPSED_TIMEs(i));
dbms_output.put_line('The ela_per_exec is ' || ela_per_execs(i));
dbms_output.put_line('--------------------------------------------------------------------------------------');
s_hash_value := n_hashvalue;
s_child_num := child_numbers(i);
-- Header information
dbms_output.put_line(chr(13));
put_line_smart(in_string => ' HASH_VALUE: ' || s_hash_value || ' CHILD_NUMBER: ' || s_child_num , in_line_size => max_line_size);
put_line_smart(in_string => '---------------------------------------------------------------------------------------------------------------------------------------------', in_line_size => max_line_size);
begin
execute immediate '
select sql_text,
plan_hash_value
from v$sql
where hash_value = to_number(:s_hash_value)
and child_number = to_number(:s_child_num)'
into s_output, s_plan_hash using s_hash_value, s_child_num;
exception
when NO_DATA_FOUND then
null;
when others then
dbms_output.put_line('Error getting SQL text from V$SQL, check privileges');
end;
put_line_smart(s_output);
dbms_output.put_line(chr(13));
open c_display_cursor for s_display_cursor using to_number(s_hash_value), to_number(s_child_num);
n_cnt := 1;
fetch c_display_cursor into
a_column_list(1).a_data(n_cnt), -- a_p_id(n_cnt),
a_column_list(2).a_data(n_cnt), -- a_operation(n_cnt),
a_column_list(3).a_data(n_cnt), -- a_name(n_cnt),
a_column_list(4).a_data(n_cnt), -- a_starts(n_cnt),
a_column_list(5).a_data(n_cnt), -- a_e_rows(n_cnt),
a_column_list(6).a_data(n_cnt), -- a_a_rows(n_cnt),
a_column_list(7).a_data(n_cnt), -- a_a_time(n_cnt),
a_column_list(8).a_data(n_cnt), -- a_buffers(n_cnt),
a_column_list(9).a_data(n_cnt), -- a_reads(n_cnt),
a_column_list(10).a_data(n_cnt), -- a_writes(n_cnt),
a_column_list(11).a_data(n_cnt), -- a_in_out(n_cnt),
a_column_list(12).a_data(n_cnt), -- a_partition_start(n_cnt),
a_column_list(13).a_data(n_cnt), -- a_partition_stop(n_cnt),
a_column_list(14).a_data(n_cnt), -- a_distribution(n_cnt),
a_column_list(15).a_data(n_cnt), -- a_last_mem_usage(n_cnt),
a_column_list(16).a_data(n_cnt), -- a_last_degree(n_cnt),
a_column_list(17).a_data(n_cnt), -- a_mem_opt(n_cnt),
a_column_list(18).a_data(n_cnt), -- a_mem_one(n_cnt),
--a_column_list(17).a_data(n_cnt), -- a_opt_cnt(n_cnt),
--a_column_list(18).a_data(n_cnt), -- a_one_cnt(n_cnt),
--a_column_list(19).a_data(n_cnt), -- a_multi_cnt(n_cnt),
--a_column_list(22).a_data(n_cnt), -- a_max_tmp(n_cnt),
a_column_list(19).a_data(n_cnt), -- a_last_tmp(n_cnt),
a_access_pred(n_cnt),
a_filter_pred(n_cnt),
a_dyn_sampl(n_cnt),
a_id_list(n_cnt);
if c_display_cursor%notfound then
close c_display_cursor;
--dbms_output.put_line('Debug : Select V$SQL_PLAN');
b_has_stat := FALSE;
a_column_list(1).s_heading := 'Id'; --a_column_list(1).b_is_number := true;
a_column_list(2).s_heading := 'Operation';
a_column_list(3).s_heading := 'Name';
a_column_list(4).s_heading := 'Rows'; a_column_list(4).b_is_number := true;
a_column_list(5).s_heading := 'Bytes'; a_column_list(5).b_is_number := true;
a_column_list(6).s_heading := 'TempSpc'; a_column_list(6).b_is_number := true;
a_column_list(7).s_heading := 'Cost';a_column_list(7).b_is_number := true;
a_column_list(8).s_heading := 'Cpu-Cost';a_column_list(8).b_is_number := true;
a_column_list(9).s_heading := 'TQ';
a_column_list(10).s_heading := 'In-Out';
a_column_list(11).s_heading := 'Pstart'; a_column_list(10).b_is_number := true;
a_column_list(12).s_heading := 'Pstop'; a_column_list(11).b_is_number := true;
a_column_list(13).s_heading := 'PQ Distrib';
open c_display_cursor for s_display_cursor2 using to_number(s_hash_value), to_number(s_child_num);
n_cnt := 0;
else
-- The plan statistics
a_column_list(1).s_heading := 'Id'; --a_column_list(1).b_is_number := true;
a_column_list(2).s_heading := 'Operation';
a_column_list(3).s_heading := 'Name';
a_column_list(4).s_heading := 'Starts'; a_column_list(4).b_is_number := true;
a_column_list(5).s_heading := 'E-Rows'; a_column_list(5).b_is_number := true;
a_column_list(6).s_heading := 'A-Rows'; a_column_list(6).b_is_number := true;
a_column_list(7).s_heading := 'A-Time';
a_column_list(8).s_heading := 'Buffers'; a_column_list(8).b_is_number := true;
a_column_list(9).s_heading := 'Reads'; a_column_list(9).b_is_number := true;
a_column_list(10).s_heading := 'Writes'; a_column_list(10).b_is_number := true;
a_column_list(11).s_heading := 'In-Out';
a_column_list(12).s_heading := 'Pstart'; a_column_list(12).b_is_number := true;
a_column_list(13).s_heading := 'Pstop'; a_column_list(13).b_is_number := true;
a_column_list(14).s_heading := 'PQ Distrib';
a_column_list(15).s_heading := 'OMem'; a_column_list(15).b_is_number := true;
a_column_list(16).s_heading := '1Mem'; a_column_list(16).b_is_number := true;
a_column_list(17).s_heading := 'Used-Mem'; a_column_list(17).b_is_number := true; --a_column_list(15).s_alignment := 'RIGHT';
a_column_list(18).s_heading := 'Last-Degree'; a_column_list(18).b_is_number := true;
--a_column_list(19).s_heading := 'Opt-Cnt'; a_column_list(17).b_is_number := true;
--a_column_list(20).s_heading := 'One-Cnt'; a_column_list(18).b_is_number := true;
--a_column_list(21).s_heading := 'Multi-Cnt'; a_column_list(19).b_is_number := true;
--a_column_list(19).s_heading := 'Max-Tmp'; a_column_list(19).b_is_number := true;
a_column_list(19).s_heading := 'Last-Tmp'; a_column_list(19).b_is_number := true;
n_cnt := 1;
end if;
loop
exit when c_display_cursor%notfound;
n_cnt := n_cnt + 1;
if b_has_stat then
fetch c_display_cursor into
a_column_list(1).a_data(n_cnt), -- a_p_id(n_cnt),
a_column_list(2).a_data(n_cnt), -- a_operation(n_cnt),
a_column_list(3).a_data(n_cnt), -- a_name(n_cnt),
a_column_list(4).a_data(n_cnt), -- a_starts(n_cnt),
a_column_list(5).a_data(n_cnt), -- a_e_rows(n_cnt),
a_column_list(6).a_data(n_cnt), -- a_a_rows(n_cnt),
a_column_list(7).a_data(n_cnt), -- a_a_time(n_cnt),
a_column_list(8).a_data(n_cnt), -- a_buffers(n_cnt),
a_column_list(9).a_data(n_cnt), -- a_reads(n_cnt),
a_column_list(10).a_data(n_cnt), -- a_writes(n_cnt),
a_column_list(11).a_data(n_cnt), -- a_in_out(n_cnt),
a_column_list(12).a_data(n_cnt), -- a_partition_start(n_cnt),
a_column_list(13).a_data(n_cnt), -- a_partition_stop(n_cnt),
a_column_list(14).a_data(n_cnt), -- a_distribution(n_cnt),
a_column_list(15).a_data(n_cnt), -- a_last_mem_usage(n_cnt),
a_column_list(16).a_data(n_cnt), -- a_last_degree(n_cnt),
a_column_list(17).a_data(n_cnt), -- a_mem_opt(n_cnt),
a_column_list(18).a_data(n_cnt), -- a_mem_one(n_cnt),
a_column_list(19).a_data(n_cnt), -- a_last_tmp(n_cnt),
a_access_pred(n_cnt),
a_filter_pred(n_cnt),
a_dyn_sampl(n_cnt),
a_id_list(n_cnt);
else
fetch c_display_cursor into
a_column_list(1).a_data(n_cnt),
a_column_list(2).a_data(n_cnt),
a_column_list(3).a_data(n_cnt),
a_column_list(4).a_data(n_cnt),
a_column_list(5).a_data(n_cnt),
a_column_list(6).a_data(n_cnt),
a_column_list(7).a_data(n_cnt),
a_column_list(8).a_data(n_cnt),
a_column_list(9).a_data(n_cnt),
a_column_list(10).a_data(n_cnt),
a_column_list(11).a_data(n_cnt),
a_column_list(12).a_data(n_cnt),
a_column_list(13).a_data(n_cnt),
a_access_pred(n_cnt),
a_filter_pred(n_cnt),
a_dyn_sampl(n_cnt),
a_id_list(n_cnt);
end if;
end loop;
close c_display_cursor;
if a_column_list(1).a_data.count > 0 then
dbms_output.put_line('Plan hash value: ' || s_plan_hash);
dbms_output.put_line(chr(13));
n_row_size := 1;
for i in a_column_list.first..a_column_list.last loop
if a_column_list(i).b_is_number then
if a_column_list(i).a_data.count > 0 then
for j in a_column_list(i).a_data.first..a_column_list(i).a_data.last loop
begin
a_column_list(i).a_data(j) := display_cursor_format_number(a_column_list(i).a_data(j));
exception
when others then
dbms_output.put_line('Column:' || a_column_list(i).s_heading || ' Data: ' || a_column_list(i).a_data(j));
raise;
end;
end loop;
end if;
end if;
-- column size is greatest of max size of content + 2 (leading + trailing blanks) and size of column heading
a_column_list(i).n_max_size := greatest(get_max_size(a_column_list(i).a_data) + 2, length(a_column_list(i).s_heading) + 2);
a_column_list(i).b_has_data := not has_collection_only_nulls(a_column_list(i).a_data);
if a_column_list(i).b_has_data then
n_row_size := n_row_size + a_column_list(i).n_max_size + 1;
end if;
end loop;
-- Header
put_line_smart(in_string => lpad('-', n_row_size, '-'), in_line_size => max_line_size);
s_row := '';
for i in a_column_list.first..a_column_list.last loop
if a_column_list(i).b_has_data then
if a_column_list(i).s_alignment is null then
if a_column_list(i).b_is_number then
s_row := s_row || '|' || lpad(a_column_list(i).s_heading, a_column_list(i).n_max_size - 1) || ' ';
else
s_row := s_row || '|' || ' ' || rpad(a_column_list(i).s_heading, a_column_list(i).n_max_size - 1);
end if;
else
if a_column_list(i).s_alignment = 'RIGHT' then
s_row := s_row || '|' || lpad(a_column_list(i).s_heading, a_column_list(i).n_max_size - 1) || ' ';
else
s_row := s_row || '|' || ' ' || rpad(a_column_list(i).s_heading, a_column_list(i).n_max_size - 1);
end if;
end if;
end if;
end loop;
s_row := s_row || '|';
put_line_smart(in_string => s_row, in_line_size => max_line_size);
-- Data
put_line_smart(in_string => lpad('-', n_row_size, '-'), in_line_size => max_line_size);
for j in a_column_list(1).a_data.first..a_column_list(1).a_data.last loop
s_row := '';
for i in a_column_list.first..a_column_list.last loop
if a_column_list(i).b_has_data then
if a_column_list(i).b_is_number then
s_row := s_row || '|' || lpad(nvl(a_column_list(i).a_data(j), ' '), a_column_list(i).n_max_size - 1) || ' ';
else
s_row := s_row || '|' || ' ' || rpad(nvl(a_column_list(i).a_data(j), ' '), a_column_list(i).n_max_size - 1);
end if;
end if;
end loop;
s_row := s_row || '|';
put_line_smart(in_string => s_row, in_line_size => max_line_size);
end loop;
-- Footer
put_line_smart(in_string => lpad('-', n_row_size, '-'), in_line_size => max_line_size);
-- Predicate information
dbms_output.put_line(chr(13));
dbms_output.put_line('Predicate Information (identified by operation id):');
dbms_output.put_line('---------------------------------------------------');
for j in a_column_list(1).a_data.first..a_column_list(1).a_data.last loop
if a_access_pred(j) is not null or a_filter_pred(j) is not null then
s_output := lpad(to_char(to_number(a_id_list(j)), 'FM9999'), 4, ' ') || ' - ';
if a_access_pred(j) is not null then
put_line_smart(s_output || 'access(' || a_access_pred(j) || ')', lpad(' ', length(s_output), ' '));
end if;
if a_filter_pred(j) is not null then
if a_access_pred(j) is not null then
put_line_smart(lpad(' ', length(s_output), ' ') || 'filter(' || a_filter_pred(j) || ')', lpad(' ', length(s_output), ' '));
else
put_line_smart(s_output || 'filter(' || a_filter_pred(j) || ')', lpad(' ', length(s_output), ' '));
end if;
end if;
end if;
end loop;
--dbms_output.put_line('DEBUG:Begin Notes');
-- Notes section
if not a_column_list(4).b_has_data or a_dyn_sampl(1) = 'YES' then
dbms_output.put_line(chr(13));
dbms_output.put_line('Note');
dbms_output.put_line('-----');
end if;
if a_dyn_sampl(1) = 'YES' then
dbms_output.put_line(' - dynamic sampling used for this statement');
end if;
if not a_column_list(4).b_has_data then
dbms_output.put_line(' - Warning: basic plan statistics not available. These are only collected when:');
dbms_output.put_line(' * parameter ''statistics_level'' is set to ''ALL'', at session or system level');
end if;
else
dbms_output.put_line('SQL information could not be found for HASH_VALUE: ' || s_hash_value || ',CHILD_NUMBER: ' || s_child_num);
dbms_output.put_line('Please verify value of SQL address, hash_value and child_number;');
dbms_output.put_line('It could also be that the plan is no longer in cursor cache (check v$sql_plan)');
end if;
end loop;
end if;
exception
when others then
o_vc_return_flag := 'E' || '_' || sqlcode || '_' || sqlerrm;
dbms_output.put_line(o_vc_return_flag);
return;
end PRINTSQL;
/