Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
/**
3
 * Library for basic performance monitoring and tuning
4
 *
5
 * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
6
 *
7
 * @package ADOdb
8
 * @link https://adodb.org Project's web site and documentation
9
 * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
10
 *
11
 * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause
12
 * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,
13
 * any later version. This means you can use it in proprietary products.
14
 * See the LICENSE.md file distributed with this source code for details.
15
 * @license BSD-3-Clause
16
 * @license LGPL-2.1-or-later
17
 *
18
 * @copyright 2000-2013 John Lim
19
 * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
20
 */
21
 
22
// security - hide paths
23
if (!defined('ADODB_DIR')) die();
24
 
25
 
26
class perf_oci8 extends adodb_perf{
27
 
28
	var $noShowIxora = 15; // if the sql for suspicious sql is taking too long, then disable ixora
29
 
30
	var $tablesSQL = "select segment_name as \"tablename\", sum(bytes)/1024 as \"size_in_k\",tablespace_name as \"tablespace\",count(*) \"extents\" from sys.user_extents
31
	   group by segment_name,tablespace_name";
32
 
33
	var $version;
34
 
35
	var $createTableSQL = "CREATE TABLE adodb_logsql (
36
		  created date NOT NULL,
37
		  sql0 varchar(250) NOT NULL,
38
		  sql1 varchar(4000) NOT NULL,
39
		  params varchar(4000),
40
		  tracer varchar(4000),
41
		  timer decimal(16,6) NOT NULL
42
		)";
43
 
44
	var $settings = array(
45
	'Ratios',
46
		'data cache hit ratio' => array('RATIOH',
47
			"select round((1-(phy.value / (cur.value + con.value)))*100,2)
48
			from v\$sysstat cur, v\$sysstat con, v\$sysstat phy
49
			where cur.name = 'db block gets' and
50
			      con.name = 'consistent gets' and
51
			      phy.name = 'physical reads'",
52
			'=WarnCacheRatio'),
53
 
54
		'sql cache hit ratio' => array( 'RATIOH',
55
			'select round(100*(sum(pins)-sum(reloads))/sum(pins),2)  from v$librarycache',
56
			'increase <i>shared_pool_size</i> if too ratio low'),
57
 
58
		'datadict cache hit ratio' => array('RATIOH',
59
		"select
60
           round((1 - (sum(getmisses) / (sum(gets) +
61
   		 sum(getmisses))))*100,2)
62
		from  v\$rowcache",
63
		'increase <i>shared_pool_size</i> if too ratio low'),
64
 
65
		'memory sort ratio' => array('RATIOH',
66
		"SELECT ROUND((100 * b.VALUE) /DECODE ((a.VALUE + b.VALUE),
67
       0,1,(a.VALUE + b.VALUE)),2)
68
FROM   v\$sysstat a,
69
       v\$sysstat b
70
WHERE  a.name = 'sorts (disk)'
71
AND    b.name = 'sorts (memory)'",
72
	"% of memory sorts compared to disk sorts - should be over 95%"),
73
 
74
	'IO',
75
		'data reads' => array('IO',
76
		"select value from v\$sysstat where name='physical reads'"),
77
 
78
	'data writes' => array('IO',
79
		"select value from v\$sysstat where name='physical writes'"),
80
 
81
	'Data Cache',
82
 
83
		'data cache buffers' => array( 'DATAC',
84
		"select a.value/b.value  from v\$parameter a, v\$parameter b
85
			where a.name = 'db_cache_size' and b.name= 'db_block_size'",
86
			'Number of cache buffers. Tune <i>db_cache_size</i> if the <i>data cache hit ratio</i> is too low.'),
87
		'data cache blocksize' => array('DATAC',
88
			"select value from v\$parameter where name='db_block_size'",
89
			'' ),
90
 
91
	'Memory Pools',
92
		'Mem Max Target (11g+)' => array( 'DATAC',
93
		"select value from v\$parameter where name = 'memory_max_target'",
94
			'The memory_max_size is the maximum value to which memory_target can be set.' ),
95
	'Memory target (11g+)' => array( 'DATAC',
96
		"select value from v\$parameter where name = 'memory_target'",
97
			'If memory_target is defined then SGA and PGA targets are consolidated into one memory_target.' ),
98
		'SGA Max Size' => array( 'DATAC',
99
		"select nvl(value,0)/1024.0/1024 || 'M' from v\$parameter where name = 'sga_max_size'",
100
			'The sga_max_size is the maximum value to which sga_target can be set.' ),
101
	'SGA target' => array( 'DATAC',
102
		"select nvl(value,0)/1024.0/1024 || 'M'  from v\$parameter where name = 'sga_target'",
103
			'If sga_target is defined then data cache, shared, java and large pool size can be 0. This is because all these pools are consolidated into one sga_target.' ),
104
	'PGA aggr target' => array( 'DATAC',
105
		"select nvl(value,0)/1024.0/1024 || 'M' from v\$parameter where name = 'pga_aggregate_target'",
106
			'If pga_aggregate_target is defined then this is the maximum memory that can be allocated for cursor operations such as sorts, group by, joins, merges. When in doubt, set it to 20% of sga_target.' ),
107
	'data cache size' => array('DATAC',
108
			"select value from v\$parameter where name = 'db_cache_size'",
109
			'db_cache_size' ),
110
		'shared pool size' => array('DATAC',
111
			"select value from v\$parameter where name = 'shared_pool_size'",
112
			'shared_pool_size, which holds shared sql, stored procedures, dict cache and similar shared structs' ),
113
		'java pool size' => array('DATAJ',
114
			"select value from v\$parameter where name = 'java_pool_size'",
115
			'java_pool_size' ),
116
		'large pool buffer size' => array('CACHE',
117
			"select value from v\$parameter where name='large_pool_size'",
118
			'this pool is for large mem allocations (not because it is larger than shared pool), for MTS sessions, parallel queries, io buffers (large_pool_size) ' ),
119
 
120
		'dynamic memory usage' => array('CACHE', "select '-' from dual", '=DynMemoryUsage'),
121
 
122
		'Connections',
123
		'current connections' => array('SESS',
124
			'select count(*) from sys.v_$session where username is not null',
125
			''),
126
		'max connections' => array( 'SESS',
127
			"select value from v\$parameter where name='sessions'",
128
			''),
129
 
130
	'Memory Utilization',
131
		'data cache utilization ratio' => array('RATIOU',
132
			"select round((1-bytes/sgasize)*100, 2)
133
			from (select sum(bytes) sgasize from sys.v_\$sgastat) s, sys.v_\$sgastat f
134
			where name = 'free memory' and pool = 'shared pool'",
135
		'Percentage of data cache actually in use - should be over 85%'),
136
 
137
		'shared pool utilization ratio' => array('RATIOU',
138
		'select round((sga.bytes/case when p.value=0 then sga.bytes else to_number(p.value) end)*100,2)
139
		from v$sgastat sga, v$parameter p
140
		where sga.name = \'free memory\' and sga.pool = \'shared pool\'
141
		and p.name = \'shared_pool_size\'',
142
		'Percentage of shared pool actually used - too low is bad, too high is worse'),
143
 
144
		'large pool utilization ratio' => array('RATIOU',
145
			"select round((1-bytes/sgasize)*100, 2)
146
			from (select sum(bytes) sgasize from sys.v_\$sgastat) s, sys.v_\$sgastat f
147
			where name = 'free memory' and pool = 'large pool'",
148
		'Percentage of large_pool actually in use - too low is bad, too high is worse'),
149
		'sort buffer size' => array('CACHE',
150
			"select value from v\$parameter where name='sort_area_size'",
151
			'max in-mem sort_area_size (per query), uses memory in pga' ),
152
 
153
		/*'pga usage at peak' => array('RATIOU',
154
		'=PGA','Mb utilization at peak transactions (requires Oracle 9i+)'),*/
155
	'Transactions',
156
		'rollback segments' => array('ROLLBACK',
157
			"select count(*) from sys.v_\$rollstat",
158
			''),
159
 
160
		'peak transactions' => array('ROLLBACK',
161
			"select max_utilization  tx_hwm
162
    		from sys.v_\$resource_limit
163
    		where resource_name = 'transactions'",
164
			'Taken from high-water-mark'),
165
		'max transactions' => array('ROLLBACK',
166
			"select value from v\$parameter where name = 'transactions'",
167
			'max transactions / rollback segments < 3.5 (or transactions_per_rollback_segment)'),
168
	'Parameters',
169
		'cursor sharing' => array('CURSOR',
170
			"select value from v\$parameter where name = 'cursor_sharing'",
171
			'Cursor reuse strategy. Recommended is FORCE (8i+) or SIMILAR (9i+). See <a href=http://www.praetoriate.com/oracle_tips_cursor_sharing.htm>cursor_sharing</a>.'),
172
		/*
173
		'cursor reuse' => array('CURSOR',
174
			"select count(*) from (select sql_text_wo_constants, count(*)
175
  from t1
176
 group by sql_text_wo_constants
177
having count(*) > 100)",'These are sql statements that should be using bind variables'),*/
178
		'index cache cost' => array('COST',
179
			"select value from v\$parameter where name = 'optimizer_index_caching'",
180
			'=WarnIndexCost'),
181
		'random page cost' => array('COST',
182
			"select value from v\$parameter where name = 'optimizer_index_cost_adj'",
183
			'=WarnPageCost'),
184
	'Waits',
185
		'Recent wait events' => array('WAITS','select \'Top 5 events\' from dual','=TopRecentWaits'),
186
//		'Historical wait SQL' => array('WAITS','select \'Last 2 days\' from dual','=TopHistoricalWaits'), -- requires AWR license
187
	'Backup',
188
		'Achivelog Mode' => array('BACKUP', 'select log_mode from v$database', '=LogMode'),
189
 
190
		'DBID' => array('BACKUP','select dbid from v$database','Primary key of database, used for recovery with an RMAN Recovery Catalog'),
191
		'Archive Log Dest' => array('BACKUP', "SELECT NVL(v1.value,v2.value)
192
FROM v\$parameter v1, v\$parameter v2 WHERE v1.name='log_archive_dest' AND v2.name='log_archive_dest_10'", ''),
193
 
194
		'Flashback Area' => array('BACKUP', "select nvl(value,'Flashback Area not used') from v\$parameter where name=lower('DB_RECOVERY_FILE_DEST')", 'Flashback area is a folder where all backup data and logs can be stored and managed by Oracle. If Error: message displayed, then it is not in use.'),
195
 
196
		'Flashback Usage' => array('BACKUP', "select nvl('-','Flashback Area not used') from v\$parameter where name=lower('DB_RECOVERY_FILE_DEST')", '=FlashUsage', 'Flashback area usage.'),
197
 
198
		'Control File Keep Time' => array('BACKUP', "select value from v\$parameter where name='control_file_record_keep_time'",'No of days to keep RMAN info in control file.  Recommended set to x2 or x3 times the frequency of your full backup.'),
199
		'Recent RMAN Jobs' => array('BACKUP', "select '-' from dual", "=RMAN"),
200
 
201
		//		'Control File Keep Time' => array('BACKUP', "select value from v\$parameter where name='control_file_record_keep_time'",'No of days to keep RMAN info in control file. I recommend it be set to x2 or x3 times the frequency of your full backup.'),
202
      'Storage', 'Tablespaces' => array('TABLESPACE', "select '-' from dual", "=TableSpace"),
203
		false
204
 
205
	);
206
 
207
 
208
	function __construct(&$conn)
209
	{
210
	global $gSQLBlockRows;
211
 
212
		$gSQLBlockRows = 1000;
213
		$savelog = $conn->LogSQL(false);
214
		$this->version = $conn->ServerInfo();
215
		$conn->LogSQL($savelog);
216
		$this->conn = $conn;
217
	}
218
 
219
	function LogMode()
220
	{
221
		$mode = $this->conn->GetOne("select log_mode from v\$database");
222
 
223
		if ($mode == 'ARCHIVELOG') return 'To turn off archivelog:<br>
224
	<pre><font size=-2>
225
        SQLPLUS> connect sys as sysdba;
226
        SQLPLUS> shutdown immediate;
227
 
228
        SQLPLUS> startup mount exclusive;
229
        SQLPLUS> alter database noarchivelog;
230
        SQLPLUS> alter database open;
231
</font></pre>';
232
 
233
		return 'To turn on archivelog:<br>
234
	<pre><font size=-2>
235
        SQLPLUS> connect sys as sysdba;
236
        SQLPLUS> shutdown immediate;
237
 
238
        SQLPLUS> startup mount exclusive;
239
        SQLPLUS> alter database archivelog;
240
        SQLPLUS> archive log start;
241
        SQLPLUS> alter database open;
242
</font></pre>';
243
	}
244
 
245
	function TopRecentWaits()
246
	{
247
 
248
		$rs = $this->conn->Execute("select * from (
249
		select event, round(100*time_waited/(select sum(time_waited) from v\$system_event where wait_class <> 'Idle'),1) \"% Wait\",
250
    total_waits,time_waited, average_wait,wait_class from v\$system_event where wait_class <> 'Idle' order by 2 desc
251
	) where rownum <=5");
252
 
253
		$ret = rs2html($rs,false,false,false,false);
254
		return "&nbsp;<p>".$ret."&nbsp;</p>";
255
 
256
	}
257
 
258
	function TopHistoricalWaits()
259
	{
260
		$days = 2;
261
 
262
		$rs = $this->conn->Execute("select * from (   SELECT
263
         b.wait_class,B.NAME,
264
        round(sum(wait_time+TIME_WAITED)/1000000) waitsecs,
265
        parsing_schema_name,
266
        C.SQL_TEXT, a.sql_id
267
FROM    V\$ACTIVE_SESSION_HISTORY A
268
        join V\$EVENT_NAME B  on  A.EVENT# = B.EVENT#
269
       join V\$SQLAREA C  on  A.SQL_ID = C.SQL_ID
270
WHERE   A.SAMPLE_TIME BETWEEN sysdate-$days and sysdate
271
       and parsing_schema_name not in ('SYS','SYSMAN','DBSNMP','SYSTEM')
272
GROUP BY b.wait_class,parsing_schema_name,C.SQL_TEXT, B.NAME,A.sql_id
273
order by 3 desc) where rownum <=10");
274
 
275
		$ret = rs2html($rs,false,false,false,false);
276
		return "&nbsp;<p>".$ret."&nbsp;</p>";
277
 
278
	}
279
 
280
	function TableSpace()
281
	{
282
 
283
		$rs = $this->conn->Execute(
284
	"select tablespace_name,round(sum(bytes)/1024/1024) as Used_MB,round(sum(maxbytes)/1024/1024) as Max_MB, round(sum(bytes)/sum(maxbytes),4) * 100 as PCT
285
	from dba_data_files
286
   group by tablespace_name order by 2 desc");
287
 
288
		$ret = "<p><b>Tablespace</b>".rs2html($rs,false,false,false,false);
289
 
290
		$rs = $this->conn->Execute("select * from dba_data_files order by tablespace_name, 1");
291
		$ret .= "<p><b>Datafile</b>".rs2html($rs,false,false,false,false);
292
 
293
		return "&nbsp;<p>".$ret."&nbsp;</p>";
294
	}
295
 
296
	function RMAN()
297
	{
298
		$rs = $this->conn->Execute("select * from (select start_time, end_time, operation, status, mbytes_processed, output_device_type
299
			from V\$RMAN_STATUS order by start_time desc) where rownum <=10");
300
 
301
		$ret = rs2html($rs,false,false,false,false);
302
		return "&nbsp;<p>".$ret."&nbsp;</p>";
303
 
304
	}
305
 
306
	function DynMemoryUsage()
307
	{
308
		if (@$this->version['version'] >= 11) {
309
			$rs = $this->conn->Execute("select component, current_size/1024./1024 as \"CurrSize (M)\" from  V\$MEMORY_DYNAMIC_COMPONENTS");
310
 
311
		} else
312
			$rs = $this->conn->Execute("select name, round(bytes/1024./1024,2) as \"CurrSize (M)\" from  V\$sgainfo");
313
 
314
 
315
		$ret = rs2html($rs,false,false,false,false);
316
		return "&nbsp;<p>".$ret."&nbsp;</p>";
317
	}
318
 
319
	function FlashUsage()
320
	{
321
        $rs = $this->conn->Execute("select * from  V\$FLASH_RECOVERY_AREA_USAGE");
322
		$ret = rs2html($rs,false,false,false,false);
323
		return "&nbsp;<p>".$ret."&nbsp;</p>";
324
	}
325
 
326
	function WarnPageCost($val)
327
	{
328
		if ($val == 100 && $this->version['version'] < 10) $s = '<font color=red><b>Too High</b>. </font>';
329
		else $s = '';
330
 
331
		return $s.'Recommended is 20-50 for TP, and 50 for data warehouses. Default is 100. See <a href=http://www.dba-oracle.com/oracle_tips_cost_adj.htm>optimizer_index_cost_adj</a>. ';
332
	}
333
 
334
	function WarnIndexCost($val)
335
	{
336
		if ($val == 0 && $this->version['version'] < 10) $s = '<font color=red><b>Too Low</b>. </font>';
337
		else $s = '';
338
 
339
		return $s.'Percentage of indexed data blocks expected in the cache.
340
			Recommended is 20 (fast disk array) to 30 (slower hard disks). Default is 0.
341
			 See <a href=http://www.dba-oracle.com/oracle_tips_cbo_part1.htm>optimizer_index_caching</a>.';
342
		}
343
 
344
	function PGA()
345
	{
346
 
347
		//if ($this->version['version'] < 9) return 'Oracle 9i or later required';
348
	}
349
 
350
	function PGA_Advice()
351
	{
352
		$t = "<h3>PGA Advice Estimate</h3>";
353
		if ($this->version['version'] < 9) return $t.'Oracle 9i or later required';
354
 
355
		$rs = $this->conn->Execute('select a.MB,
356
			case when a.targ = 1 then \'<<= Current \'
357
			when a.targ < 1  or a.pct <= b.pct then null
358
			else
359
			\'- BETTER than Current by \'||round(a.pct/b.pct*100-100,2)||\'%\' end as "Percent Improved",
360
	a.targ as  "PGA Size Factor",a.pct "% Perf"
361
	from
362
       (select round(pga_target_for_estimate/1024.0/1024.0,0) MB,
363
              pga_target_factor targ,estd_pga_cache_hit_percentage pct,rownum as r
364
              from v$pga_target_advice) a left join
365
       (select round(pga_target_for_estimate/1024.0/1024.0,0) MB,
366
              pga_target_factor targ,estd_pga_cache_hit_percentage pct,rownum as r
367
              from v$pga_target_advice) b on
368
      a.r = b.r+1 where
369
          b.pct < 100');
370
		if (!$rs) return $t."Only in 9i or later";
371
	//	$rs->Close();
372
		if ($rs->EOF) return $t."PGA could be too big";
373
 
374
		return $t.rs2html($rs,false,false,true,false);
375
	}
376
 
377
	function Explain($sql,$partial=false)
378
	{
379
		$savelog = $this->conn->LogSQL(false);
380
		$rs = $this->conn->SelectLimit("select ID FROM PLAN_TABLE");
381
		if (!$rs) {
382
			echo "<p><b>Missing PLAN_TABLE</b></p>
383
<pre>
384
CREATE TABLE PLAN_TABLE (
385
  STATEMENT_ID                    VARCHAR2(30),
386
  TIMESTAMP                       DATE,
387
  REMARKS                         VARCHAR2(80),
388
  OPERATION                       VARCHAR2(30),
389
  OPTIONS                         VARCHAR2(30),
390
  OBJECT_NODE                     VARCHAR2(128),
391
  OBJECT_OWNER                    VARCHAR2(30),
392
  OBJECT_NAME                     VARCHAR2(30),
393
  OBJECT_INSTANCE                 NUMBER(38),
394
  OBJECT_TYPE                     VARCHAR2(30),
395
  OPTIMIZER                       VARCHAR2(255),
396
  SEARCH_COLUMNS                  NUMBER,
397
  ID                              NUMBER(38),
398
  PARENT_ID                       NUMBER(38),
399
  POSITION                        NUMBER(38),
400
  COST                            NUMBER(38),
401
  CARDINALITY                     NUMBER(38),
402
  BYTES                           NUMBER(38),
403
  OTHER_TAG                       VARCHAR2(255),
404
  PARTITION_START                 VARCHAR2(255),
405
  PARTITION_STOP                  VARCHAR2(255),
406
  PARTITION_ID                    NUMBER(38),
407
  OTHER                           LONG,
408
  DISTRIBUTION                    VARCHAR2(30)
409
);
410
</pre>";
411
			return false;
412
		}
413
 
414
		$rs->Close();
415
	//	$this->conn->debug=1;
416
 
417
		if ($partial) {
418
			$sqlq = $this->conn->qstr($sql.'%');
419
			$arr = $this->conn->GetArray("select distinct sql1 from adodb_logsql where sql1 like $sqlq");
420
			if ($arr) {
421
				foreach($arr as $row) {
422
					$sql = reset($row);
423
					if (crc32($sql) == $partial) break;
424
				}
425
			}
426
		}
427
 
428
		$s = "<p><b>Explain</b>: ".htmlspecialchars($sql)."</p>";
429
 
430
		$this->conn->BeginTrans();
431
		$id = "ADODB ".microtime();
432
 
433
		$rs = $this->conn->Execute("EXPLAIN PLAN SET STATEMENT_ID='$id' FOR $sql");
434
		$m = $this->conn->ErrorMsg();
435
		if ($m) {
436
			$this->conn->RollbackTrans();
437
			$this->conn->LogSQL($savelog);
438
			$s .= "<p>$m</p>";
439
			return $s;
440
		}
441
		$rs = $this->conn->Execute("
442
		select
443
  '<pre>'||lpad('--', (level-1)*2,'-') || trim(operation) || ' ' || trim(options)||'</pre>'  as Operation,
444
  object_name,COST,CARDINALITY,bytes
445
		FROM plan_table
446
START WITH id = 0  and STATEMENT_ID='$id'
447
CONNECT BY prior id=parent_id and statement_id='$id'");
448
 
449
		$s .= rs2html($rs,false,false,false,false);
450
		$this->conn->RollbackTrans();
451
		$this->conn->LogSQL($savelog);
452
		$s .= $this->Tracer($sql,$partial);
453
		return $s;
454
	}
455
 
456
	function CheckMemory()
457
	{
458
		if ($this->version['version'] < 9) return 'Oracle 9i or later required';
459
 
460
		 $rs = $this->conn->Execute("
461
select  a.name Buffer_Pool, b.size_for_estimate as cache_mb_estimate,
462
	case when b.size_factor=1 then
463
   		'&lt;&lt;= Current'
464
	 when a.estd_physical_read_factor-b.estd_physical_read_factor > 0.001 and b.estd_physical_read_factor<1 then
465
		'- BETTER than current by ' || round((1-b.estd_physical_read_factor)/b.estd_physical_read_factor*100,2) || '%'
466
	else ' ' end as RATING,
467
   b.estd_physical_read_factor \"Phys. Reads Factor\",
468
   round((a.estd_physical_read_factor-b.estd_physical_read_factor)/b.estd_physical_read_factor*100,2) as \"% Improve\"
469
   from (select size_for_estimate,size_factor,estd_physical_read_factor,rownum  r,name from v\$db_cache_advice order by name,1) a ,
470
   (select size_for_estimate,size_factor,estd_physical_read_factor,rownum r,name from v\$db_cache_advice order by name,1) b
471
   where a.r = b.r-1 and a.name = b.name
472
  ");
473
		if (!$rs) return false;
474
 
475
		/*
476
		The v$db_cache_advice utility show the marginal changes in physical data block reads for different sizes of db_cache_size
477
		*/
478
		$s = "<h3>Data Cache Advice Estimate</h3>";
479
		if ($rs->EOF) {
480
			$s .= "<p>Cache that is 50% of current size is still too big</p>";
481
		} else {
482
			$s .= "Ideal size of Data Cache is when %BETTER gets close to zero.";
483
			$s .= rs2html($rs,false,false,false,false);
484
		}
485
		return $s.$this->PGA_Advice();
486
	}
487
 
488
	/*
489
		Generate html for suspicious/expensive sql
490
	*/
491
	function tohtml(&$rs,$type)
492
	{
493
		$o1 = $rs->FetchField(0);
494
		$o2 = $rs->FetchField(1);
495
		$o3 = $rs->FetchField(2);
496
		if ($rs->EOF) return '<p>None found</p>';
497
		$check = '';
498
		$sql = '';
499
		$s = "\n\n<table border=1 bgcolor=white><tr><td><b>".$o1->name.'</b></td><td><b>'.$o2->name.'</b></td><td><b>'.$o3->name.'</b></td></tr>';
500
		while (!$rs->EOF) {
501
			if ($check != $rs->fields[0].'::'.$rs->fields[1]) {
502
				if ($check) {
503
					$carr = explode('::',$check);
504
					$prefix = "<a href=\"?$type=1&sql=".rawurlencode($sql).'&x#explain">';
505
					$suffix = '</a>';
506
					if (strlen($prefix)>2000) {
507
						$prefix = '';
508
						$suffix = '';
509
					}
510
 
511
					$s .=  "\n<tr><td align=right>".$carr[0].'</td><td align=right>'.$carr[1].'</td><td>'.$prefix.$sql.$suffix.'</td></tr>';
512
				}
513
				$sql = $rs->fields[2];
514
				$check = $rs->fields[0].'::'.$rs->fields[1];
515
			} else
516
				$sql .= $rs->fields[2];
517
			if (substr($sql,strlen($sql)-1) == "\0") $sql = substr($sql,0,strlen($sql)-1);
518
			$rs->MoveNext();
519
		}
520
		$rs->Close();
521
 
522
		$carr = explode('::',$check);
523
		$prefix = "<a target=".rand()." href=\"?&hidem=1&$type=1&sql=".rawurlencode($sql).'&x#explain">';
524
		$suffix = '</a>';
525
		if (strlen($prefix)>2000) {
526
			$prefix = '';
527
			$suffix = '';
528
		}
529
		$s .=  "\n<tr><td align=right>".$carr[0].'</td><td align=right>'.$carr[1].'</td><td>'.$prefix.$sql.$suffix.'</td></tr>';
530
 
531
		return $s."</table>\n\n";
532
	}
533
 
534
	// code thanks to Ixora.
535
	// http://www.ixora.com.au/scripts/query_opt.htm
536
	// requires oracle 8.1.7 or later
537
	function SuspiciousSQL($numsql=10)
538
	{
539
		$sql = "
540
select
541
  substr(to_char(s.pct, '99.00'), 2) || '%'  load,
542
  s.executions  executes,
543
  p.sql_text
544
from
545
  (
546
    select
547
      address,
548
      buffer_gets,
549
      executions,
550
      pct,
551
      rank() over (order by buffer_gets desc)  ranking
552
    from
553
      (
554
	select
555
	  address,
556
	  buffer_gets,
557
	  executions,
558
	  100 * ratio_to_report(buffer_gets) over ()  pct
559
	from
560
	  sys.v_\$sql
561
	where
562
	  command_type != 47 and module != 'T.O.A.D.'
563
      )
564
    where
565
      buffer_gets > 50 * executions
566
  )  s,
567
  sys.v_\$sqltext  p
568
where
569
  s.ranking <= $numsql and
570
  p.address = s.address
571
order by
572
  1 desc, s.address, p.piece";
573
 
574
  		global $ADODB_CACHE_MODE;
575
  		if (isset($_GET['expsixora']) && isset($_GET['sql'])) {
576
				$partial = empty($_GET['part']);
577
				echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n";
578
		}
579
 
580
		if (isset($_GET['sql'])) return $this->_SuspiciousSQL($numsql);
581
 
582
		$s = '';
583
		$timer = time();
584
		$s .= $this->_SuspiciousSQL($numsql);
585
		$timer = time() - $timer;
586
 
587
		if ($timer > $this->noShowIxora) return $s;
588
		$s .= '<p>';
589
 
590
		$save = $ADODB_CACHE_MODE;
591
		$ADODB_CACHE_MODE = ADODB_FETCH_NUM;
592
		if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
593
 
594
		$savelog = $this->conn->LogSQL(false);
595
		$rs = $this->conn->SelectLimit($sql);
596
		$this->conn->LogSQL($savelog);
597
 
598
		if (isset($savem)) $this->conn->SetFetchMode($savem);
599
		$ADODB_CACHE_MODE = $save;
600
		if ($rs) {
601
			$s .= "\n<h3>Ixora Suspicious SQL</h3>";
602
			$s .= $this->tohtml($rs,'expsixora');
603
		}
604
 
605
		return $s;
606
	}
607
 
608
	// code thanks to Ixora.
609
	// http://www.ixora.com.au/scripts/query_opt.htm
610
	// requires oracle 8.1.7 or later
611
	function ExpensiveSQL($numsql = 10)
612
	{
613
		$sql = "
614
select
615
  substr(to_char(s.pct, '99.00'), 2) || '%'  load,
616
  s.executions  executes,
617
  p.sql_text
618
from
619
  (
620
    select
621
      address,
622
      disk_reads,
623
      executions,
624
      pct,
625
      rank() over (order by disk_reads desc)  ranking
626
    from
627
      (
628
	select
629
	  address,
630
	  disk_reads,
631
	  executions,
632
	  100 * ratio_to_report(disk_reads) over ()  pct
633
	from
634
	  sys.v_\$sql
635
	where
636
	  command_type != 47 and module != 'T.O.A.D.'
637
      )
638
    where
639
      disk_reads > 50 * executions
640
  )  s,
641
  sys.v_\$sqltext  p
642
where
643
  s.ranking <= $numsql and
644
  p.address = s.address
645
order by
646
  1 desc, s.address, p.piece
647
";
648
		global $ADODB_CACHE_MODE;
649
  		if (isset($_GET['expeixora']) && isset($_GET['sql'])) {
650
			$partial = empty($_GET['part']);
651
			echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n";
652
		}
653
		if (isset($_GET['sql'])) {
654
			 $var = $this->_ExpensiveSQL($numsql);
655
			 return $var;
656
		}
657
 
658
		$s = '';
659
		$timer = time();
660
		$s .= $this->_ExpensiveSQL($numsql);
661
		$timer = time() - $timer;
662
		if ($timer > $this->noShowIxora) return $s;
663
 
664
		$s .= '<p>';
665
		$save = $ADODB_CACHE_MODE;
666
		$ADODB_CACHE_MODE = ADODB_FETCH_NUM;
667
		if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
668
 
669
		$savelog = $this->conn->LogSQL(false);
670
		$rs = $this->conn->Execute($sql);
671
		$this->conn->LogSQL($savelog);
672
 
673
		if (isset($savem)) $this->conn->SetFetchMode($savem);
674
		$ADODB_CACHE_MODE = $save;
675
 
676
		if ($rs) {
677
			$s .= "\n<h3>Ixora Expensive SQL</h3>";
678
			$s .= $this->tohtml($rs,'expeixora');
679
		}
680
 
681
		return $s;
682
	}
683
 
684
	function clearsql()
685
	{
686
		$perf_table = adodb_perf::table();
687
	// using the naive "delete from $perf_table where created<".$this->conn->sysTimeStamp will cause the table to lock, possibly
688
	// for a long time
689
		$sql =
690
"DECLARE cnt pls_integer;
691
BEGIN
692
	cnt := 0;
693
	FOR rec IN (SELECT ROWID AS rr FROM $perf_table WHERE created<SYSDATE)
694
	LOOP
695
	  cnt := cnt + 1;
696
	  DELETE FROM $perf_table WHERE ROWID=rec.rr;
697
	  IF cnt = 1000 THEN
698
	  	COMMIT;
699
		cnt := 0;
700
	  END IF;
701
	END LOOP;
702
	commit;
703
END;";
704
 
705
		$ok = $this->conn->Execute($sql);
706
	}
707
 
708
}