3 * performance monitoring and tuning.
5 * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
8 * @link https://adodb.org Project's web site and documentation
9 * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
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
18 * @copyright 2000-2013 John Lim
19 * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
22 if (!defined('ADODB_DIR')) include_once(dirname(__FILE__
).'/adodb.inc.php');
23 include_once(ADODB_DIR
.'/tohtml.inc.php');
25 define( 'ADODB_OPT_HIGH', 2);
26 define( 'ADODB_OPT_LOW', 1);
28 global $ADODB_PERF_MIN;
29 $ADODB_PERF_MIN = 0.05; // log only if >= minimum number of secs to run
32 // returns in K the memory of current process, or 0 if not known
33 function adodb_getmem()
35 if (function_exists('memory_get_usage'))
36 return (integer) ((memory_get_usage()+
512)/1024);
40 if ( strncmp(strtoupper(PHP_OS
),'WIN',3)==0) {
43 exec('tasklist /FI "PID eq ' . $pid. '" /FO LIST', $output);
44 return substr($output[5], strpos($output[5], ':') +
1);
48 exec("ps --pid $pid --no-headers -o%mem,size", $output);
49 if (sizeof($output) == 0) return 0;
51 $memarr = explode(' ',$output[0]);
52 if (sizeof($memarr)>=2) return (integer) $memarr[1];
57 // avoids localization problems where , is used instead of .
58 function adodb_round($n,$prec)
60 return number_format($n, $prec, '.', '');
63 /* obsolete: return microtime value as a float. Retained for backward compat */
64 function adodb_microtime()
66 return microtime(true);
70 function adodb_log_sql(&$connx,$sql,$inputarr)
72 $perf_table = adodb_perf
::table();
73 $connx->fnExecute
= false;
74 $a0 = microtime(true);
75 $rs = $connx->Execute($sql,$inputarr);
76 $a1 = microtime(true);
78 if (!empty($connx->_logsql
) && (empty($connx->_logsqlErrors
) ||
!$rs)) {
79 global $ADODB_LOG_CONN;
81 if (!empty($ADODB_LOG_CONN)) {
82 $conn = $ADODB_LOG_CONN;
83 if ($conn->databaseType
!= $connx->databaseType
)
84 $prefix = '/*dbx='.$connx->databaseType
.'*/ ';
92 $conn->_logsql
= false; // disable logsql error simulation
93 $dbT = $conn->databaseType
;
98 $errM = $connx->ErrorMsg();
99 $errN = $connx->ErrorNo();
100 $conn->lastInsID
= 0;
101 $tracer = substr('ERROR: '.htmlspecialchars($errM),0,250);
107 $conn->debug
= false;
108 if (!is_object($rs) ||
$rs->dataProvider
== 'empty')
109 $conn->_affected
= $conn->affected_rows(true);
110 $conn->lastInsID
= @$conn->Insert_ID();
113 if (isset($_SERVER['HTTP_HOST'])) {
114 $tracer .= '<br>'.$_SERVER['HTTP_HOST'];
115 if (isset($_SERVER['PHP_SELF'])) $tracer .= htmlspecialchars($_SERVER['PHP_SELF']);
117 if (isset($_SERVER['PHP_SELF'])) $tracer .= '<br>'.htmlspecialchars($_SERVER['PHP_SELF']);
118 //$tracer .= (string) adodb_backtrace(false);
120 $tracer = (string) substr($tracer,0,500);
122 if (is_array($inputarr)) {
123 if (is_array(reset($inputarr))) $params = 'Array sizeof='.sizeof($inputarr);
125 // Quote string parameters so we can see them in the
126 // performance stats. This helps spot disabled indexes.
127 $xar_params = $inputarr;
128 foreach ($xar_params as $xar_param_key => $xar_param) {
129 if (gettype($xar_param) == 'string')
130 $xar_params[$xar_param_key] = '"' . $xar_param . '"';
132 $params = implode(', ', $xar_params);
133 if (strlen($params) >= 3000) $params = substr($params, 0, 3000);
139 if (is_array($sql)) $sql = $sql[0];
140 if ($prefix) $sql = $prefix.$sql;
141 $arr = array('b'=>strlen($sql).'.'.crc32($sql),
142 'c'=>substr($sql,0,3900), 'd'=>$params,'e'=>$tracer,'f'=>adodb_round($time,6));
144 $saved = $conn->debug
;
147 $d = $conn->sysTimeStamp
;
148 if (empty($d)) $d = date("'Y-m-d H:i:s'");
149 if ($conn->dataProvider
== 'oci8' && $dbT != 'oci8po') {
150 $isql = "insert into $perf_table values($d,:b,:c,:d,:e,:f)";
151 } else if ($dbT == 'mssqlnative' ||
$dbT == 'odbc_mssql' ||
$dbT == 'informix' ||
strncmp($dbT,'odbtp',4)==0) {
153 if ($dbT == 'informix') $sql2 = substr($sql2,0,230);
155 $sql1 = $conn->qstr($arr['b']);
156 $sql2 = $conn->qstr($arr['c']);
157 $params = $conn->qstr($arr['d']);
158 $tracer = $conn->qstr($arr['e']);
160 $isql = "insert into $perf_table (created,sql0,sql1,params,tracer,timer) values($d,$sql1,$sql2,$params,$tracer,$timer)";
161 if ($dbT == 'informix') $isql = str_replace(chr(10),' ',$isql);
164 if ($dbT == 'db2') $arr['f'] = (float) $arr['f'];
165 $isql = "insert into $perf_table (created,sql0,sql1,params,tracer,timer) values( $d,?,?,?,?,?)";
168 global $ADODB_PERF_MIN;
169 if ($errN != 0 ||
$time >= $ADODB_PERF_MIN) {
170 if($conn instanceof ADODB_mysqli
&& $conn->_queryID
) {
171 mysqli_free_result($conn->_queryID
);
173 $ok = $conn->Execute($isql,$arr);
174 if($conn instanceof ADODB_mysqli
&& $conn->_queryID
){
175 mysqli_free_result($conn->_queryID
);
180 $conn->debug
= $saved;
183 $conn->_logsql
= true;
185 $err2 = $conn->ErrorMsg();
186 $conn->_logsql
= true; // enable logsql error simulation
187 $perf = NewPerfMonitor($conn);
189 if ($perf->CreateLogTable()) $ok = $conn->Execute($isql,$arr);
191 $ok = $conn->Execute("create table $perf_table (
195 params varchar(3000),
197 timer decimal(16,6))");
200 ADOConnection
::outp( "<p><b>LOGSQL Insert Failed</b>: $isql<br>$err2</p>");
201 $conn->_logsql
= false;
204 $connx->_errorMsg
= $errM;
205 $connx->_errorCode
= $errN;
207 $connx->fnExecute
= 'adodb_log_sql';
213 The settings data structure is an associative array that database parameter per element.
215 Each database parameter element in the array is itself an array consisting of:
217 0: category code, used to group related db parameters
219 a. sql string to retrieve value, eg. "select value from v\$parameter where name='db_block_size'",
220 b. array holding sql string and field to look for, e.g. array('show variables','table_cache'),
221 c. a string prefixed by =, then a PHP method of the class is invoked,
222 e.g. to invoke $this->GetIndexValue(), set this array element to '=GetIndexValue',
223 2: description of the database parameter
228 var $color = '#F0F0F0';
229 var $table = '<table border=1 bgcolor=white>';
230 var $titles = '<tr><td><b>Parameter</b></td><td><b>Value</b></td><td><b>Description</b></td></tr>';
232 var $tablesSQL = false;
233 var $cliFormat = "%32s => %s \r\n";
234 var $sql1 = 'sql1'; // used for casting sql1 to text for mssql
236 var $helpurl = '<a href="https://adodb.org/dokuwiki/doku.php?id=v5:performance:logsql">LogSQL help</a>';
237 var $createTableSQL = false;
238 var $maxLength = 2000;
240 /** @var array Settings data. */
243 // Sets the tablename to be used
244 static function table($newtable = false)
248 if (!empty($newtable)) $_table = $newtable;
249 if (empty($_table)) $_table = 'adodb_logsql';
253 // returns array with info to calculate CPU Load
258 cpu 524152 2662 2515228 336057010
259 cpu0 264339 1408 1257951 168025827
260 cpu1 259813 1254 1257277 168031181
263 intr 890153570 868093576 6 0 4 4 0 6 1 2 0 0 0 124 0 8098760 2 13961053 0 0 0 0 0 0 0 0 0 0 0 0 0 16 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
264 disk_io: (3,0):(3144904,54369,610378,3090535,50936192) (3,1):(3630212,54097,633016,3576115,50951320)
270 // Algorithm is taken from
271 // http://social.technet.microsoft.com/Forums/en-US/winservergen/thread/414b0e1b-499c-411e-8a02-6a12e339c0f1/
272 if (strncmp(PHP_OS
,'WIN',3)==0) {
273 static $FAIL = false;
274 if ($FAIL) return false;
276 $objName = "winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\CIMV2";
277 $myQuery = "SELECT * FROM Win32_PerfFormattedData_PerfOS_Processor WHERE Name = '_Total'";
280 @$objWMIService = new COM($objName);
281 if (!$objWMIService) {
290 foreach($objWMIService->ExecQuery($myQuery) as $objItem) {
291 $info[0] = $objItem->PercentProcessorTime();
294 } catch(Exception
$e) {
296 echo $e->getMessage();
303 // Algorithm - Steve Blinch (BlitzAffe Online, http://www.blitzaffe.com)
304 $statfile = '/proc/stat';
305 if (!file_exists($statfile)) return false;
307 $fd = fopen($statfile,"r");
308 if (!$fd) return false;
310 $statinfo = explode("\n",fgets($fd, 1024));
312 foreach($statinfo as $line) {
313 $info = explode(" ",$line);
314 if($info[0]=="cpu") {
315 array_shift($info); // pop off "cpu"
316 if(!$info[0]) array_shift($info); // pop off blank space (if any)
325 /* NOT IMPLEMENTED */
330 total: used: free: shared: buffers: cached:
331 Mem: 1055289344 917299200 137990144 0 165437440 599773184
332 Swap: 2146775040 11055104 2135719936
340 Inact_dirty: 322856 kB
341 Inact_clean: 24256 kB
342 Inact_target: 168316 kB
347 SwapTotal: 2096460 kB
349 Committed_AS: 348732 kB
355 Remember that this is client load, not db server load!
360 $info = $this->_CPULoad();
361 if (!$info) return false;
363 if (strncmp(PHP_OS
,'WIN',3)==0) {
364 return (integer) $info[0];
366 if (empty($this->_lastLoad
)) {
368 $this->_lastLoad
= $info;
369 $info = $this->_CPULoad();
372 $last = $this->_lastLoad
;
373 $this->_lastLoad
= $info;
375 $d_user = $info[0] - $last[0];
376 $d_nice = $info[1] - $last[1];
377 $d_system = $info[2] - $last[2];
378 $d_idle = $info[3] - $last[3];
380 //printf("Delta - User: %f Nice: %f System: %f Idle: %f<br>",$d_user,$d_nice,$d_system,$d_idle);
382 $total=$d_user+
$d_nice+
$d_system+
$d_idle;
383 if ($total<1) $total=1;
384 return 100*($d_user+
$d_nice+
$d_system)/$total;
388 function Tracer($sql)
390 $perf_table = adodb_perf
::table();
391 $saveE = $this->conn
->fnExecute
;
392 $this->conn
->fnExecute
= false;
394 global $ADODB_FETCH_MODE;
395 $save = $ADODB_FETCH_MODE;
396 $ADODB_FETCH_MODE = ADODB_FETCH_NUM
;
397 if ($this->conn
->fetchMode
!== false) $savem = $this->conn
->SetFetchMode(false);
399 $sqlq = $this->conn
->qstr($sql);
400 $arr = $this->conn
->GetArray(
401 "select count(*),tracer
402 from $perf_table where sql1=$sqlq
407 $s .= '<h3>Scripts Affected</h3>';
408 foreach($arr as $k) {
409 $s .= sprintf("%4d",$k[0]).' '.strip_tags($k[1]).'<br>';
413 if (isset($savem)) $this->conn
->SetFetchMode($savem);
414 $ADODB_CACHE_MODE = $save;
415 $this->conn
->fnExecute
= $saveE;
420 Explain Plan for $sql.
421 If only a snippet of the $sql is passed in, then $partial will hold the crc32 of the
424 function Explain($sql,$partial=false)
429 function InvalidSQL($numsql = 10)
432 if (isset($_GET['sql'])) return;
433 $s = '<h3>Invalid SQL</h3>';
434 $saveE = $this->conn
->fnExecute
;
435 $this->conn
->fnExecute
= false;
436 $perf_table = adodb_perf
::table();
437 $rs = $this->conn
->SelectLimit("select distinct count(*),sql1,tracer as error_msg from $perf_table where tracer like 'ERROR:%' group by sql1,tracer order by 1 desc",$numsql);//,$numsql);
438 $this->conn
->fnExecute
= $saveE;
440 $s .= rs2html($rs,false,false,false,false);
442 return "<p>$this->helpurl. ".$this->conn
->ErrorMsg()."</p>";
449 This script identifies the longest running SQL
451 function _SuspiciousSQL($numsql = 10)
453 global $ADODB_FETCH_MODE;
455 $perf_table = adodb_perf
::table();
456 $saveE = $this->conn
->fnExecute
;
457 $this->conn
->fnExecute
= false;
459 if (isset($_GET['exps']) && isset($_GET['sql'])) {
460 $partial = !empty($_GET['part']);
461 echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n";
464 if (isset($_GET['sql'])) return;
467 $save = $ADODB_FETCH_MODE;
468 $ADODB_FETCH_MODE = ADODB_FETCH_NUM
;
469 if ($this->conn
->fetchMode
!== false) $savem = $this->conn
->SetFetchMode(false);
470 //$this->conn->debug=1;
471 $rs = $this->conn
->SelectLimit(
472 "select avg(timer) as avg_timer,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer
474 where {$this->conn->upperCase}({$this->conn->substr}(sql0,1,5)) not in ('DROP ','INSER','COMMI','CREAT')
475 and (tracer is null or tracer not like 'ERROR:%')
477 order by 1 desc",$numsql);
478 if (isset($savem)) $this->conn
->SetFetchMode($savem);
479 $ADODB_FETCH_MODE = $save;
480 $this->conn
->fnExecute
= $saveE;
482 if (!$rs) return "<p>$this->helpurl. ".$this->conn
->ErrorMsg()."</p>";
483 $s = "<h3>Suspicious SQL</h3>
484 <font size=1>The following SQL have high average execution times</font><br>
485 <table border=1 bgcolor=white><tr><td><b>Avg Time</b><td><b>Count</b><td><b>SQL</b><td><b>Max</b><td><b>Min</b></tr>\n";
486 $max = $this->maxLength
;
488 $sql = $rs->fields
[1];
489 $raw = urlencode($sql);
490 if (strlen($raw)>$max-100) {
491 $sql2 = substr($sql,0,$max-500);
492 $raw = urlencode($sql2).'&part='.crc32($sql);
494 $prefix = "<a target=sql".rand()." href=\"?hidem=1&exps=1&sql=".$raw."&x#explain\">";
496 if ($this->explain
== false ||
strlen($prefix)>$max) {
497 $suffix = ' ... <i>String too long for GET parameter: '.strlen($prefix).'</i>';
500 $s .= "<tr><td>".adodb_round($rs->fields
[0],6)."<td align=right>".$rs->fields
[2]."<td><font size=-1>".$prefix.htmlspecialchars($sql).$suffix."</font>".
501 "<td>".$rs->fields
[3]."<td>".$rs->fields
[4]."</tr>";
504 return $s."</table>";
508 function CheckMemory()
514 function SuspiciousSQL($numsql=10)
516 return adodb_perf
::_SuspiciousSQL($numsql);
519 function ExpensiveSQL($numsql=10)
521 return adodb_perf
::_ExpensiveSQL($numsql);
526 This reports the percentage of load on the instance due to the most
527 expensive few SQL statements. Tuning these statements can often
528 make huge improvements in overall system performance.
530 function _ExpensiveSQL($numsql = 10)
532 global $ADODB_FETCH_MODE;
534 $perf_table = adodb_perf
::table();
535 $saveE = $this->conn
->fnExecute
;
536 $this->conn
->fnExecute
= false;
538 if (isset($_GET['expe']) && isset($_GET['sql'])) {
539 $partial = !empty($_GET['part']);
540 echo "<a name=explain></a>".$this->Explain($_GET['sql'],$partial)."\n";
543 if (isset($_GET['sql'])) return;
546 $save = $ADODB_FETCH_MODE;
547 $ADODB_FETCH_MODE = ADODB_FETCH_NUM
;
548 if ($this->conn
->fetchMode
!== false) $savem = $this->conn
->SetFetchMode(false);
550 $rs = $this->conn
->SelectLimit(
551 "select sum(timer) as total,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer
553 where {$this->conn->upperCase}({$this->conn->substr}(sql0,1,5)) not in ('DROP ','INSER','COMMI','CREAT')
554 and (tracer is null or tracer not like 'ERROR:%')
557 order by 1 desc",$numsql);
558 if (isset($savem)) $this->conn
->SetFetchMode($savem);
559 $this->conn
->fnExecute
= $saveE;
560 $ADODB_FETCH_MODE = $save;
561 if (!$rs) return "<p>$this->helpurl. ".$this->conn
->ErrorMsg()."</p>";
562 $s = "<h3>Expensive SQL</h3>
563 <font size=1>Tuning the following SQL could reduce the server load substantially</font><br>
564 <table border=1 bgcolor=white><tr><td><b>Load</b><td><b>Count</b><td><b>SQL</b><td><b>Max</b><td><b>Min</b></tr>\n";
565 $max = $this->maxLength
;
567 $sql = $rs->fields
[1];
568 $raw = urlencode($sql);
569 if (strlen($raw)>$max-100) {
570 $sql2 = substr($sql,0,$max-500);
571 $raw = urlencode($sql2).'&part='.crc32($sql);
573 $prefix = "<a target=sqle".rand()." href=\"?hidem=1&expe=1&sql=".$raw."&x#explain\">";
575 if($this->explain
== false ||
strlen($prefix>$max)) {
579 $s .= "<tr><td>".adodb_round($rs->fields
[0],6)."<td align=right>".$rs->fields
[2]."<td><font size=-1>".$prefix.htmlspecialchars($sql).$suffix."</font>".
580 "<td>".$rs->fields
[3]."<td>".$rs->fields
[4]."</tr>";
583 return $s."</table>";
587 Raw function to return parameter value from $settings.
589 function DBParameter($param)
591 if (empty($this->settings
[$param])) return false;
592 $sql = $this->settings
[$param][1];
593 return $this->_DBParameter($sql);
597 Raw function returning array of poll parameters
599 function PollParameters()
601 $arr[0] = (float)$this->DBParameter('data cache hit ratio');
602 $arr[1] = (float)$this->DBParameter('data reads');
603 $arr[2] = (float)$this->DBParameter('data writes');
604 $arr[3] = (integer) $this->DBParameter('current connections');
609 Low-level Get Database Parameter
611 function _DBParameter($sql)
613 $savelog = $this->conn
->LogSQL(false);
614 if (is_array($sql)) {
615 global $ADODB_FETCH_MODE;
619 if (sizeof($sql)>2) $pos = $sql[2];
621 if (sizeof($sql)>3) $coef = $sql[3];
624 $save = $ADODB_FETCH_MODE;
625 $ADODB_FETCH_MODE = ADODB_FETCH_NUM
;
626 if ($this->conn
->fetchMode
!== false) $savem = $this->conn
->SetFetchMode(false);
628 $rs = $this->conn
->Execute($sql1);
630 if (isset($savem)) $this->conn
->SetFetchMode($savem);
631 $ADODB_FETCH_MODE = $save;
634 $keyf = reset($rs->fields
);
635 if (trim($keyf) == $key) {
636 $ret = $rs->fields
[$pos];
637 if ($coef) $ret *= $coef;
644 $this->conn
->LogSQL($savelog);
647 if (strncmp($sql,'=',1) == 0) {
648 $fn = substr($sql,1);
651 $sql = str_replace('$DATABASE',$this->conn
->database
,$sql);
652 $ret = $this->conn
->GetOne($sql);
653 $this->conn
->LogSQL($savelog);
660 Warn if cache ratio falls below threshold. Displayed in "Description" column.
662 function WarnCacheRatio($val)
664 if ($val < $this->warnRatio
)
665 return '<font color=red><b>Cache ratio should be at least '.$this->warnRatio
.'%</b></font>';
671 $perf_table = adodb_perf
::table();
672 $this->conn
->Execute("delete from $perf_table where created<".$this->conn
->sysTimeStamp
);
674 /***********************************************************************************************/
675 // HIGH LEVEL UI FUNCTIONS
676 /***********************************************************************************************/
679 function UI($pollsecs=5)
681 global $ADODB_LOG_CONN;
683 $perf_table = adodb_perf
::table();
687 if ($conn->host
&& $conn->database
) $app .= ', db=';
688 $app .= $conn->database
;
690 if ($app) $app .= ', ';
691 $savelog = $this->conn
->LogSQL(false);
692 $info = $conn->ServerInfo();
693 if (isset($_GET['clearsql'])) {
696 $this->conn
->LogSQL($savelog);
698 if (!isset($_SESSION['ADODB_PERF_SQL'])) $nsql = $_SESSION['ADODB_PERF_SQL'] = 10;
699 else $nsql = $_SESSION['ADODB_PERF_SQL'];
701 $app .= $info['description'];
704 if (isset($_GET['do'])) $do = $_GET['do'];
705 else if (isset($_POST['do'])) $do = $_POST['do'];
706 else if (isset($_GET['sql'])) $do = 'viewsql';
709 if (isset($_GET['nsql'])) {
710 if ($_GET['nsql'] > 0) $nsql = $_SESSION['ADODB_PERF_SQL'] = (integer) $_GET['nsql'];
712 echo "<title>ADOdb Performance Monitor on $app</title><body bgcolor=white>";
713 if ($do == 'viewsql') $form = "<td><form># SQL:<input type=hidden value=viewsql name=do> <input type=text size=4 name=nsql value=$nsql><input type=submit value=Go></td></form>";
714 else $form = "<td> </td>";
716 $allowsql = !defined('ADODB_PERF_NO_RUN_SQL');
717 global $ADODB_PERF_MIN;
718 $app .= " (Min sql timing \$ADODB_PERF_MIN=$ADODB_PERF_MIN secs)";
720 if (empty($_GET['hidem']))
721 echo "<table border=1 width=100% bgcolor=lightyellow><tr><td colspan=2>
722 <b><a href=https://adodb.org/dokuwiki/doku.php?id=v5:performance:performance_index>ADOdb</a> Performance Monitor</b> <font size=1>for $app</font></tr><tr><td>
723 <a href=?do=stats><b>Performance Stats</b></a> <a href=?do=viewsql><b>View SQL</b></a>
724 <a href=?do=tables><b>View Tables</b></a> <a href=?do=poll><b>Poll Stats</b></a>",
725 $allowsql ?
' <a href=?do=dosql><b>Run SQL</b></a>' : '',
733 if (empty($ADODB_LOG_CONN))
734 echo "<p> <a href=\"?do=viewsql&clearsql=1\">Clear SQL Log</a><br>";
735 echo $this->HealthCheck();
736 //$this->conn->debug=1;
737 echo $this->CheckMemory();
740 $self = htmlspecialchars($_SERVER['PHP_SELF']);
741 echo "<iframe width=720 height=80%
742 src=\"{$self}?do=poll2&hidem=1\"></iframe>";
746 $this->Poll($pollsecs);
750 if (!$allowsql) break;
755 if (empty($_GET['hidem']))
756 echo " <a href=\"?do=viewsql&clearsql=1\">Clear SQL Log</a><br>";
757 echo($this->SuspiciousSQL($nsql));
758 echo($this->ExpensiveSQL($nsql));
759 echo($this->InvalidSQL($nsql));
762 echo $this->Tables(); break;
768 Runs in infinite loop, returning real-time statistics
770 function Poll($secs=5)
772 $this->conn
->fnExecute
= false;
773 //$this->conn->debug=1;
774 if ($secs <= 1) $secs = 1;
775 echo "Accumulating statistics, every $secs seconds...\n";flush();
776 $arro = $this->PollParameters();
782 $arr = $this->PollParameters();
784 $hits = sprintf('%2.2f',$arr[0]);
785 $reads = sprintf('%12.4f',($arr[1]-$arro[1])/$secs);
786 $writes = sprintf('%12.4f',($arr[2]-$arro[2])/$secs);
787 $sess = sprintf('%5d',$arr[3]);
789 $load = $this->CPULoad();
790 if ($load !== false) {
791 $oslabel = 'WS-CPU%';
792 $osval = sprintf(" %2.1f ",(float) $load);
797 if ($cnt %
10 == 0) echo " Time ".$oslabel." Hit% Sess Reads/s Writes/s\n";
799 echo date('H:i:s').' '.$osval."$hits $sess $reads $writes\n";
802 if (connection_aborted()) return;
810 Returns basic health check in a command line interface
812 function HealthCheckCLI()
814 return $this->HealthCheck(true);
819 Returns basic health check as HTML
821 function HealthCheck($cli=false)
823 $saveE = $this->conn
->fnExecute
;
824 $this->conn
->fnExecute
= false;
825 if ($cli) $html = '';
826 else $html = $this->table
.'<tr><td colspan=3><h3>'.$this->conn
->databaseType
.'</h3></td></tr>'.$this->titles
;
830 foreach($this->settings
as $name => $arr) {
831 if ($arr === false) break;
833 if (!is_string($name)) {
834 if ($cli) $html .= " -- $arr -- \n";
835 else $html .= "<tr bgcolor=$this->color><td colspan=3><i>$arr</i> </td></tr>";
839 if (!is_array($arr)) break;
842 if (sizeof($arr)>2) $desc = $arr[2];
843 else $desc = ' ';
846 if ($category == 'HIDE') continue;
848 $val = $this->_DBParameter($how);
850 if ($desc && strncmp($desc,"=",1) === 0) {
851 $fn = substr($desc,1);
852 $desc = $this->$fn($val);
855 if ($val === false) {
856 $m = $this->conn
->ErrorMsg();
859 if (is_numeric($val) && $val >= 256*1024) {
860 if ($val %
(1024*1024) == 0) {
863 } else if ($val %
1024 == 0) {
867 //$val = htmlspecialchars($val);
870 if ($category != $oldc) {
872 //$bgc = ($bgc == ' bgcolor='.$this->color) ? ' bgcolor=white' : ' bgcolor='.$this->color;
874 if (strlen($desc)==0) $desc = ' ';
875 if (strlen($val)==0) $val = ' ';
877 $html .= str_replace(' ','',sprintf($this->cliFormat
,strip_tags($name),strip_tags($val),strip_tags($desc)));
880 $html .= "<tr$bgc><td>".$name.'</td><td>'.$val.'</td><td>'.$desc."</td></tr>\n";
884 if (!$cli) $html .= "</table>\n";
885 $this->conn
->fnExecute
= $saveE;
890 function Tables($orderby='1')
892 if (!$this->tablesSQL
) return false;
894 $savelog = $this->conn
->LogSQL(false);
895 $rs = $this->conn
->Execute($this->tablesSQL
.' order by '.$orderby);
896 $this->conn
->LogSQL($savelog);
897 $html = rs2html($rs,false,false,false,false);
902 function CreateLogTable()
904 if (!$this->createTableSQL
) return false;
906 $table = $this->table();
907 $sql = str_replace('adodb_logsql',$table,$this->createTableSQL
);
908 $savelog = $this->conn
->LogSQL(false);
909 $ok = $this->conn
->Execute($sql);
910 $this->conn
->LogSQL($savelog);
911 return ($ok) ?
true : false;
918 $PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']);
919 $sql = isset($_REQUEST['sql']) ?
$_REQUEST['sql'] : '';
921 if (isset($_SESSION['phplens_sqlrows'])) $rows = $_SESSION['phplens_sqlrows'];
924 if (isset($_REQUEST['SMALLER'])) {
926 if ($rows < 3) $rows = 3;
927 $_SESSION['phplens_sqlrows'] = $rows;
929 if (isset($_REQUEST['BIGGER'])) {
931 $_SESSION['phplens_sqlrows'] = $rows;
936 <form method
="POST" action
="<?php echo $PHP_SELF ?>">
938 <td
> Form size
: <input type
="submit" value
=" < " name
="SMALLER"><input type
="submit" value
=" > > " name
="BIGGER">
941 <input type
="submit" value
=" Run SQL Below " name
="RUN"><input type
=hidden name
=do value
=dosql
>
944 <td colspan
=2><textarea rows
=<?php
print $rows; ?
> name
="sql" cols
="80"><?php
print htmlspecialchars($sql) ?
></textarea
>
951 if (!isset($_REQUEST['sql'])) return;
954 if (substr($sql,strlen($sql)-1) === ';') {
956 $sqla = $this->SplitSQL($sql);
961 foreach($sqla as $sqls) {
963 if (!$sqls) continue;
966 print "<p>".htmlspecialchars($sqls)."</p>";
969 $savelog = $this->conn
->LogSQL(false);
970 $rs = $this->conn
->Execute($sqls);
971 $this->conn
->LogSQL($savelog);
972 if ($rs && is_object($rs) && !$rs->EOF
) {
974 while ($rs->NextRecordSet()) {
975 print "<table width=98% bgcolor=#C0C0FF><tr><td> </td></tr></table>";
979 $e1 = (integer) $this->conn
->ErrorNo();
980 $e2 = $this->conn
->ErrorMsg();
981 if (($e1) ||
($e2)) {
982 if (empty($e1)) $e1 = '-1'; // postgresql fix
983 print ' '.$e1.': '.$e2;
985 print "<p>No Recordset returned<br></p>";
991 function SplitSQL($sql)
993 $arr = explode(';',$sql);
997 /************************************************************************/
1000 * Reorganise multiple table-indices/statistics/..
1001 * OptimizeMode could be given by last Parameter
1005 * optimizeTables( 'tableA');
1008 * optimizeTables( 'tableA', 'tableB', 'tableC');
1011 * optimizeTables( 'tableA', 'tableB', ADODB_OPT_LOW);
1014 * @param string table name of the table to optimize
1015 * @param int mode optimization-mode
1016 * <code>ADODB_OPT_HIGH</code> for full optimization
1017 * <code>ADODB_OPT_LOW</code> for CPU-less optimization
1018 * Default is LOW <code>ADODB_OPT_LOW</code>
1019 * @author Markus Staab
1020 * @return Returns <code>true</code> on success and <code>false</code> on error
1022 function OptimizeTables()
1024 $args = func_get_args();
1025 $numArgs = func_num_args();
1027 if ( $numArgs == 0) return false;
1029 $mode = ADODB_OPT_LOW
;
1030 $lastArg = $args[ $numArgs - 1];
1031 if ( !is_string($lastArg)) {
1033 unset( $args[ $numArgs - 1]);
1036 foreach( $args as $table) {
1037 $this->optimizeTable( $table, $mode);
1042 * Reorganise the table-indices/statistics/.. depending on the given mode.
1043 * Default Implementation throws an error.
1045 * @param string table name of the table to optimize
1046 * @param int mode optimization-mode
1047 * <code>ADODB_OPT_HIGH</code> for full optimization
1048 * <code>ADODB_OPT_LOW</code> for CPU-less optimization
1049 * Default is LOW <code>ADODB_OPT_LOW</code>
1050 * @author Markus Staab
1051 * @return Returns <code>true</code> on success and <code>false</code> on error
1053 function OptimizeTable( $table, $mode = ADODB_OPT_LOW
)
1055 ADOConnection
::outp( sprintf( "<p>%s: '%s' not implemented for driver '%s'</p>", __CLASS__
, __FUNCTION__
, $this->conn
->databaseType
));
1060 * Reorganise current database.
1061 * Default implementation loops over all <code>MetaTables()</code> and
1062 * optimize each using <code>optmizeTable()</code>
1064 * @author Markus Staab
1065 * @return Returns <code>true</code> on success and <code>false</code> on error
1067 function optimizeDatabase()
1069 $conn = $this->conn
;
1070 if ( !$conn) return false;
1072 $tables = $conn->MetaTables( 'TABLES');
1073 if ( !$tables ) return false;
1075 foreach( $tables as $table) {
1076 if ( !$this->optimizeTable( $table)) {