Mijn vraag
In een applicatie waarin ik process variablen log in een MySQL database begin ik last te krijgen mijn raspberry performance. Er draait hier nu een machine ongeveer een halfjaar en heeft ongeveer 3 miljoen records verzameld. Dat wil zeggen ca 500.000 records per maand. Het zal mooi zijn als de applicatie het over een paar jaar ook nog functioneel is
Ik heb de volgende vragen:
- Is er nog wat te optimaliseren aan mijn queries/wijze van afhandelen (zie "Wat ik al gevonden of geprobeerd heb")
- Zou Partitionieren van de tabel een optie zijn? Zo ja, welke methode zal voor mijn toepassing het beste zijn en levert het in mijn geval ook performance winst op?
- Gezien een raspberry met 1GB geheugen geen query beest is
wat zou geschiktere hardware zijn? Ik zou graag over 5 jaar (met 30 miljoen records) de query in pak em beet 1 sec willen kunnen uit voeren.
Relevante software en hardware die ik gebruik
HW: Raspberry Pi 3b+ of eigenlijk een RevPi+ 32GB (deze: https://revolution.kunbus.de/shop/en/revpi-connect-plus)
SW: PHP 7.3, Maria 10.3.22, Apache 2.4.38
Wat ik al gevonden of geprobeerd heb
mijn Methods:
Mijn test code:
wat het volgende resultaat oplevert:
De "V2" method heb ik als blinde gok er tussen gegooid ik dacht misschien dat de "query in query" (de officiële term is mij niet bekend) veel performance koste van de mariadb server. Maar blijkbaar maakt het niet veel uit.
De "query in query" doe ik om voor de grafieken, gemaakt met ChartJS, van maximaal bij voorbeeld maximaal 400 data punten te geven. Zodat ik de "periode" van de grafiek flexibel kan gebruiken. zoals in het voor beeld pak ik 3 maanden, maar het kan ook van de afgelopen 2 uur zijn. Dat wil zeggen:
Ik doe eerst een "count" query van de geselecteerde "logwaarde" en "periode"
Vervolgens bepaal ik de skip met:
In een applicatie waarin ik process variablen log in een MySQL database begin ik last te krijgen mijn raspberry performance. Er draait hier nu een machine ongeveer een halfjaar en heeft ongeveer 3 miljoen records verzameld. Dat wil zeggen ca 500.000 records per maand. Het zal mooi zijn als de applicatie het over een paar jaar ook nog functioneel is
Ik heb de volgende vragen:
- Is er nog wat te optimaliseren aan mijn queries/wijze van afhandelen (zie "Wat ik al gevonden of geprobeerd heb")
- Zou Partitionieren van de tabel een optie zijn? Zo ja, welke methode zal voor mijn toepassing het beste zijn en levert het in mijn geval ook performance winst op?
- Gezien een raspberry met 1GB geheugen geen query beest is
Relevante software en hardware die ik gebruik
HW: Raspberry Pi 3b+ of eigenlijk een RevPi+ 32GB (deze: https://revolution.kunbus.de/shop/en/revpi-connect-plus)
SW: PHP 7.3, Maria 10.3.22, Apache 2.4.38
Wat ik al gevonden of geprobeerd heb
mijn Methods:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
| /** * getElementLogData_Bulk, haal de log data van een element uit de DB * * @param string $element het element nummer ("307.S20") * @param int $eenheid eenheid voor het filter (een sensor kan meerdere eenheden hebben) * @param int $start unix timestamp, start tijd van het filter * @param int $end unix timestamp, eind tijd van het filter * @param int $skip grote data sets kun je er voor kiezen om records over te slaan * @return array associated array van de data punten binnen het filter * @throws Exception */ public static function getElementLogData_Bulk($element, $eenheid, $start, $end, $skip=1) { $db = static::getLoggerDB(); if ($skip > 1) { $sql = "SELECT * FROM ( SELECT @row := @row +1 AS rownum, `LogDataWaarde`, `LogDataTimeStamp` FROM ( SELECT @row :=0) r, plc_logdata WHERE LogDataElementNr='$element' AND LogDataEenheidNr=$eenheid AND (LogDataTimeStamp BETWEEN FROM_UNIXTIME('$start') AND FROM_UNIXTIME('$end'))) ranked WHERE rownum % $skip = 1 "; } else { $sql = "SELECT LogDataWaarde, LogDataTimeStamp FROM plc_logdata WHERE LogDataElementNr='$element' AND LogDataEenheidNr='$eenheid' AND (LogDataTimeStamp BETWEEN FROM_UNIXTIME('$start') AND FROM_UNIXTIME('$end'))"; } echo "<pre>"; print_r($sql); echo "</pre>"; $stmt = $db->query($sql); $return = $stmt->fetchAll(PDO::FETCH_ASSOC); if (count($return) > 0) { return $return; } else { return []; } } public static function getElementLogData_BulkV2($element, $eenheid, $start, $end, $skip=1) { $db = static::getLoggerDB(); $start = date("Y-m-d H:i:s", $start); $end = date("Y-m-d H:i:s", $end); $sql = "SELECT LogDataWaarde, LogDataTimeStamp FROM plc_logdata WHERE LogDataElementNr='$element' AND LogDataEenheidNr='$eenheid' AND (LogDataTimeStamp BETWEEN '$start' AND '$end')"; echo "<pre>"; print_r($sql); echo "</pre>"; $stmt = $db->query($sql); $return = []; $i = 0; foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $record) { if ($i==0 || ($i % $skip) == 0) { $return[] = $record; } $i++; } if (count($return) > 0) { return $return; } else { return []; } } |
Mijn test code:
PHP:
1
2
3
4
5
6
7
8
9
| $start1 = hrtime (true); $result1 = Graph::getElementLogData_Bulk("307.S70",0, strtotime("2020-05-26 10:00:00"), time(), 500); $end1 = hrtime (true); echo 'Bulk orig' . round(($end1 - $start1)/1e+9,3) . ' sec. <br><br> '; $start2 = hrtime (true); $result2 = Graph::getElementLogData_BulkV2("307.S70",0, strtotime("2020-05-26 10:00:00"), time(), 500); $end2 = hrtime (true); echo 'Bulk V2 ' . round(($end2 - $start2)/1e+9, 3). ' sec'; |
wat het volgende resultaat oplevert:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| SELECT * FROM ( SELECT @row := @row +1 AS rownum, `LogDataWaarde`, `LogDataTimeStamp` FROM ( SELECT @row :=0 ) r, plc_logdata WHERE LogDataElementNr='307.S70' AND LogDataEenheidNr=0 AND (LogDataTimeStamp BETWEEN FROM_UNIXTIME('1590480000') AND FROM_UNIXTIME('1598437522')) ) ranked WHERE rownum % 500 = 1 Bulk orig 4.637 sec. SELECT LogDataWaarde, LogDataTimeStamp FROM plc_logdata WHERE LogDataElementNr='307.S70' AND LogDataEenheidNr='0' AND (LogDataTimeStamp BETWEEN '2020-05-26 10:00:00' AND '2020-08-26 12:25:30') Bulk test 4.692 sec |
De "V2" method heb ik als blinde gok er tussen gegooid ik dacht misschien dat de "query in query" (de officiële term is mij niet bekend) veel performance koste van de mariadb server. Maar blijkbaar maakt het niet veel uit.
De "query in query" doe ik om voor de grafieken, gemaakt met ChartJS, van maximaal bij voorbeeld maximaal 400 data punten te geven. Zodat ik de "periode" van de grafiek flexibel kan gebruiken. zoals in het voor beeld pak ik 3 maanden, maar het kan ook van de afgelopen 2 uur zijn. Dat wil zeggen:
Ik doe eerst een "count" query van de geselecteerde "logwaarde" en "periode"
Vervolgens bepaal ik de skip met:
PHP:
1
2
3
4
5
| if ($count > 400) { $skip = round($count / 400); } else { $skip = 1; } |