我创建了一个脚本来监控多个传感器值,它们从MySQL数据库读取它们,对它们进行一些计算,然后显示数据/图表。该脚本按设计工作,但执行速度非常慢(平均60秒以上)。
数据库表包含大约500K条记录,每5分钟添加20条条目。所以要么我的代码效率很低,要么就是大表。然而,我无法看到我如何改进代码分配,所以欢迎任何帮助。我没有包含图类类代码,因为删除图形对脚本执行时间没有任何影响。
下面我粘贴了代码以供审核。提前感谢任何提示!
的index.php
<html>
</head>
<style>
form
{
float:left;
}
p {
font-family: Verdana;
font-size: 12;
border: 0;
}
<?php
require_once('template.css');
?>
</style>
</head>
<body>
<?php
//Connect to MySQL DB
require_once('config.inc.php');
require_once('functions.inc.php');
$mysqli = new MySQLi("$dbhost", "$dbuser", "$dbpass", "$db");
require_once ('F:\wamp\www\winlog\phpgraphlib\phpgraphlib.php');
//interval selection forms
echo "<table><tr><td><p><b>Energieverbruik Volta in KW.</b><br>Kies Interval: </p>";
echo "<form name=\"interval\" action=\"\" method=\"post\"><input type=\"hidden\" name=\"interval\" value=\"300\"><input type=\"submit\" value=\"5 Min\"></form>";
echo "<form name=\"interval\" action=\"\" method=\"post\"><input type=\"hidden\" name=\"interval\" value=\"3600\"><input type=\"submit\" value=\"1 Uur\"></form>";
echo "<form name=\"interval\" action=\"\" method=\"post\"><input type=\"hidden\" name=\"interval\" value=\"86400\"><input type=\"submit\" value=\"24 Uur\"></form>";
echo "<form name=\"interval\" action=\"\" method=\"post\"><input type=\"hidden\" name=\"interval\" value=\"604800\"><input type=\"submit\" value=\"1 Week\"></form>";
echo "<form name=\"interval\" action=\"\" method=\"post\"><input type=\"hidden\" name=\"interval\" value=\"2419200\"><input type=\"submit\" value=\"1 Maand\"></form>";
echo "</td></tr></table>";
// $needles[] = "9679"; //Meeting Totaal
// $needles[] = "9680"; //Voeding A-FEED
// $needles[] = "9839"; //Voeding B-FEED
// $needles[] = "9840"; //Koeling
// $needles[] = "9841"; //INPUT UPS1
// $needles[] = "9843"; //VOEDING SDB ALG
// $needles[] = "9844"; //VERDEELKAST V01.UDB
$sensors = GetSensorIDs("1");
//Set interval from form of standard if not set
if(!isset($_POST['interval'])){
$interval = 86400;
$max = 1200;
}
else{
$interval = $_POST['interval'];
}
if($interval == 3600){
$max = 50;
}
if($interval == 86400){
$max = 1200;
}
if($interval == 604800){
$max = 7500;
}
if($interval == 300){
$max = 5;
}
//get timestamps for selected interval
$timestamps = GetTimestamps($interval);
echo "<table class=CSSTableGenerator>";
echo "<tr>";
echo "<td>Datum:</td>";
foreach($timestamps as $timestamp){
echo "<td><center>" . date("d/m/Y", $timestamp) . "<br>" . date("H:i", $timestamp) . "</center></td>";
}
echo "</tr>";
foreach($sensors as $sensor){
echo "<tr>";
$data = GetDataForSensor($sensor, $timestamps, "1");
$i = 0;
$old = 0;
foreach($data as $datapoint){
echo "<td align=\"right\">";
if($interval >= 86400){
$graph_timestamp = date("d/m",$datapoint['timestamp']);
}
else{
$graph_timestamp = date("d/m h:i",$datapoint['timestamp']);
}
if(!isset($old)){
$old = 0;
}
$new = $datapoint['value'];
$usage = $old - $new;
if($i != 0){
if($interval == 604800){
echo "<font color=\"gray\">" . round($old, 2) . "</font><br>";
}
echo round($usage, 2);
${"graphline".$sensor}[$graph_timestamp] = intval(round($usage, 2));
}
else{
echo GetSensorName($sensor);
}
$old = $new;
echo "</td>";
++$i;
}
echo "</tr>";
}
//PUE
echo "<tr>";
$i = 0;
foreach($timestamps as $timestamp){
if(!isset($total_old)){
$total_old = 0;
}
if(!isset($a_old)){
$a_old = 0;
}
if(!isset($b_old)){
$b_old = 0;
}
$PUEvars = GetDataForTimeStamp($timestamp, "1");
$PUE = ($PUEvars['9679'] - $total_old) / (($PUEvars['9680'] - $a_old) + ($PUEvars['9839'] - $b_old));
echo "<td><br><br>";
if($i != 0){
echo "<b>" . round($PUE, 3) . "</b>";
//pass data to array for graph
if($interval >= 86400){
$date = date("d/m",$timestamp);
}
else{
$date = date("d/m H:i",$timestamp);
}
$graph2_data[$date] = round($PUE, 2);
}
else{
echo "<b>PUE</b>";
}
echo "</td>";
$total_old = $PUEvars['9679'];
$a_old = $PUEvars['9680'];
$b_old = $PUEvars['9839'];
++$i;
}
echo "</tr>";
echo "</table>";
echo "Legende:<br>Meting Totaal: <font color=\"red\">ROOD</font><br>INPUT UPS1: <font color=\"green\">GROEN</font><br>A-FEED: <font color=\"blue\">BLAUW</font><br>B-FEED: <font color=\"purple\">PAARS</font><br>KOELING: <font color=\"aqua\">AQUA</font><br>";
//graphcolors black, silver, gray, white, maroon, red, purple, fuscia, green, lime, olive, navy, blue, aqua, teal
$graph = new PHPGraphLib(900,300,"img.png");
$graph->addData($graphline9679, $graphline9680, $graphline9839, $graphline9840, $graphline9841);
$graph->setTitle('Power in KWh');
$graph->setBars(false);
$graph->setLine(true);
$graph->setLineColor('red', 'blue', 'purple', 'aqua', 'teal');
$graph->setDataPoints(false);
$graph->setDataPointColor('maroon');
// $graph->setDataValues(true);
// $graph->setDataValueColor('maroon');
// $graph->setGoalLine(1.3);
$graph->setRange($max,0);
$graph->setGoalLineColor('red');
$graph->createGraph();
$unimg = time();
echo "<img src=\"img.png?$unimg\">";
$graph2 = new PHPGraphLib(900,300,"img2.png");
$graph2->addData($graph2_data);
$graph2->setTitle('PUE');
$graph2->setBars(false);
$graph2->setLine(true);
$graph2->setDataPoints(true);
$graph2->setDataPointColor('maroon');
$graph2->setDataValues(true);
$graph2->setDataValueColor('maroon');
$graph2->setGoalLine(1.3);
$graph2->setRange(2,1);
$graph2->setGoalLineColor('red');
$graph2->createGraph();
$unimg = time();
echo "<img src=\"img2.png?$unimg\">";
?>
</body>
</html>
functions.inc.php
<?php
function GetSensorName($sensor_id){
global $mysqli;
if($stmt1 = $mysqli->prepare("SELECT sensor_name FROM winlog_sensors WHERE sensor_id = ? ")){
$stmt1->bind_param("i", $sensor_id);
mysqli_stmt_execute($stmt1);
mysqli_stmt_store_result($stmt1);
mysqli_stmt_bind_result($stmt1, $sensor_name);
while (mysqli_stmt_fetch($stmt1)) {
$sensor_name = $sensor_name;
}
}
return $sensor_name;
}
function GetSensorIDs($category){
global $mysqli;
$sensors = array();
if($stmt1 = $mysqli->prepare("SELECT sensor_id FROM winlog_sensors WHERE category_id = ? ")){
$stmt1->bind_param("i", $category);
mysqli_stmt_execute($stmt1);
mysqli_stmt_store_result($stmt1);
mysqli_stmt_bind_result($stmt1, $sensor_id);
while (mysqli_stmt_fetch($stmt1)) {
$sensors[] = $sensor_id;
}
}
return $sensors;
}
function GetTimestamps($interval){
global $mysqli;
$timestamps = array();
if($interval == 604800){
if(date("w") == 5 AND date("H") >= 12){
$latest = intval(strtotime("today 12:00"));
}
else{
$latest = intval(strtotime("last friday 12:00"));
}
}
else{
$latest = intval(GetLatestTimestamp());
}
$timestamps[] = $latest;
$i = 0;
$n = 1;
while($i < 24 AND $n < 50){
$deduct = intval($interval) * $n;
$q_timestamp = $latest - $deduct;
//Get calculated timestamp from DC
if($stmt1 = $mysqli->prepare("SELECT DISTINCT timestamp FROM winlog_data WHERE timestamp = ? LIMIT 1")){
$stmt1->bind_param("i", $q_timestamp);
mysqli_stmt_execute($stmt1);
mysqli_stmt_store_result($stmt1);
mysqli_stmt_bind_result($stmt1, $db_timestamp);
$exists = 0;
while (mysqli_stmt_fetch($stmt1)) {
$timestamps[] = intval($db_timestamp);
$exists = 1;
++$i;
}
//if it does not exist, take the previous one
if($exists == 0){
if($stmt1 = $mysqli->prepare("SELECT DISTINCT timestamp FROM winlog_data WHERE timestamp < ? ORDER BY timestamp DESC LIMIT 1")){
$stmt1->bind_param("i", $q_timestamp);
mysqli_stmt_execute($stmt1);
mysqli_stmt_store_result($stmt1);
mysqli_stmt_bind_result($stmt1, $db_timestamp);
$exists = 0;
while (mysqli_stmt_fetch($stmt1)) {
$timestamps[] = intval($db_timestamp);
++$i;
}
}
}
}
++$n;
}
return $timestamps;
}
function GetLatestTimestamp(){
global $mysqli;
$timestamps = array();
if($stmt1 = $mysqli->prepare("SELECT DISTINCT timestamp FROM winlog_data ORDER BY timestamp DESC LIMIT 1")){
mysqli_stmt_execute($stmt1);
mysqli_stmt_store_result($stmt1);
mysqli_stmt_bind_result($stmt1, $timestamp);
while (mysqli_stmt_fetch($stmt1)) {
$timestamp = $timestamp;
}
}
return $timestamp;
}
function GetPreviousTimestamp($timestamp){
global $mysqli;
$timestamps = array();
if($stmt1 = $mysqli->prepare("SELECT DISTINCT timestamp FROM winlog_data WHERE timestamp < ? ORDER BY timestamp DESC LIMIT 1")){
$stmt1->bind_param("i", $timestamp);
mysqli_stmt_execute($stmt1);
mysqli_stmt_store_result($stmt1);
mysqli_stmt_bind_result($stmt1, $prev_timestamp);
while (mysqli_stmt_fetch($stmt1)) {
$prev_timestamp = $prev_timestamp;
}
}
return $prev_timestamp;
}
function GetDataForTimeStamp($timestamp, $category){
global $mysqli;
$data = array();
$exists = 0;
$start_ts = $timestamp;
$stop_ts = $timestamp +1;
if($stmt2 = $mysqli->prepare("SELECT wd.value, wd.sensor_id FROM winlog_data wd, winlog_sensors ws WHERE ws.sensor_id = wd.sensor_id AND wd.timestamp >= ? AND wd.timestamp <= ? AND ws.category_id = ? ")){
$stmt2->bind_param("iii", $start_ts, $stop_ts, $category);
mysqli_stmt_execute($stmt2);
mysqli_stmt_store_result($stmt2);
mysqli_stmt_bind_result($stmt2, $value, $sensor_id);
while (mysqli_stmt_fetch($stmt2)) {
$data[$sensor_id] = $value;
$exists = 1;
$data['timestamp'] = $timestamp;
}
}
return $data;
}
function GetDataForSensor($sensor_id, $timestamps, $category){
global $mysqli;
$data = array();
$i = 0;
$highest = 0;
foreach($timestamps as $q_timestamp){
if(!isset($lowest)){
$lowest = $q_timestamp;
}
if($q_timestamp > $highest){
$highest = $q_timestamp;
}
if($q_timestamp < $lowest){
$lowest = $q_timestamp;
}
}
if($stmt2 = $mysqli->prepare("SELECT DISTINCT wd.value, wd.timestamp FROM winlog_data wd, winlog_sensors ws WHERE wd.sensor_id = ? AND wd.timestamp >= ? AND wd.timestamp <= ? AND ws.category_id = ? ORDER BY wd.timestamp DESC")){
$stmt2->bind_param("iiii", $sensor_id, $lowest, $highest, $category);
mysqli_stmt_execute($stmt2);
mysqli_stmt_store_result($stmt2);
mysqli_stmt_bind_result($stmt2, $value, $timestamp);
while (mysqli_stmt_fetch($stmt2)) {
foreach($timestamps as $q_timestamp){
if($q_timestamp == $timestamp){
$data[$i]['value'] = $value;
$data[$i]['timestamp'] = $q_timestamp;
}
}
++$i;
}
}
return $data;
}
?>
答案 0 :(得分:2)
使用Indexes
索引用于快速查找具有特定列值的行。如果没有索引,MySQL必须从第一行开始,然后读取整个表以查找相关行。表越大,成本越高。如果表中有相关列的索引,MySQL可以快速确定要在数据文件中间寻找的位置,而无需查看所有数据。这比按顺序读取每一行要快得多。
如何在SQL中创建索引:
以下是我们之前的示例在Employee_Name列上创建索引的实际SQL的样子:
CREATE INDEX name_index
ON Employee (Employee_Name)
如何在SQL中创建多列索引:
我们还可以在Employee表中的两个列上创建索引,如下面的SQL所示:
CREATE INDEX name_index
ON Employee (Employee_Name, Employee_Age)
答案 1 :(得分:1)
首先确保您的数据库表已正确编入索引:您的时间戳表应在“timestamp”字段上有一个索引。您的winlog_sensors表应该包含sensor_id和category_id的索引。
如果索引无法帮助您尝试分析脚本并查看确切占用时间的内容。你可以用Xdebug做到这一点,但这需要一些练习。我最喜欢的工具是NewRelic,有它的缺点,但是提供了一个很好的脚本执行细分,所以你可以看到它是你的查询或你的代码是否应该受到责备。