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