Hallo Heiko,
Zitat von: DS_Starter am 06 März 2020, 16:28:24
Beim Import stört das nicht wenn du in der DB history einen primary key gesetzt hast, sodass keine doppelten Datensätze entstehen. (Ich glaube den hast du wenn ich mich nicht irre.)
Auf diese Diskussion hin hatte ich nun Zeit und wollte mir mein Setup nochmal ansehen.
Ich hatte mal einen Index drauf, der ist aber durch Migrationen oder Neuinstallation scheinbar verschwunden. Ich habe dann versucht, den Standard-Index "Search_Idx" auf "unique" zu setzen. Dann ist es nicht möglich Sätze einzufügen obwohl diese schon vorhanden sind. Soweit der Plan. Es gab etliche Dubletten. Nach aufräumen habe ich nun dem Index ein Unique aufgezwungen.
Nun erhalte ich aber bei regelmäßig Probleme wegen doppelten Einträgen. Wenn ich den Cache mit den Sätzen nach dem Fehler ansehe sind da Sätze drin die auch schon auf der DB sind. Sollte nicht sein oder? List des Devices s. unten, und 4 Fälle sowie Log im Verbose-Level 5 sind im angehängten Archiv. History.csv ist jeweils was vom Cache schon auf der DB ist. Auffällig ist, dass es bei den 4 Fällen die ich näher angesehen habe immer mit addLog-Einträgen ist. Addlog mach ich stündlich.
Solange der Cache einen doppelten Satz enthält wird auch später nichts mehr auf die DB geschrieben, der Cache wächst und wächst.
Ich kann sicher mit der Comitsteuerung die als Attibut vorliegt das Problem sicher lösen, aber mich würde die Ursache interessieren, dich sicher auch.
Was mit auch noch aufgefallen ist, wenn ich "set myDbLog exportCache" per "at" einplane dann funktioniert es, wenn ich das aber im Timer-Modul (88_Timer.pm) einplane dann ist die Date zwar vorhanden, jedoch 0-KB groß, trotz Cache > 0. Idee? Wenn nicht mach ich ggf. einen eigenen Post dazu.
Internals:
COLUMNS field length used for Device: 64, Type: 64, Event: 512, Reading: 64, Value: 128, Unit: 32
CONFIGURATION ./db.conf
DEF ./db.conf .*:.*
FUUID 5c575e13-f33f-4fe4-58eb-90f49cbf9c65024a
FVERSION 93_DbLog.pm:v4.9.10-s21087/2020-01-31
MODE asynchronous
MODEL MYSQL
NAME myDbLog
NR 35
NTFY_ORDER 50-myDbLog
PID 3654
REGEXP .*:.*
STATE connected
TYPE DbLog
UTF8 1
dbconn mysql:database=fhem;host=mysql;port=3306
dbuser fhem
HELPER:
COLSET 1
DEVICECOL 64
EVENTCOL 512
OLDSTATE connected
PACKAGE main
READINGCOL 64
TC current
TH history
TYPECOL 64
UNITCOL 32
VALUECOL 128
VERSION 4.9.10
Helper:
DBLOG:
countHistory:
myDbLog:
TIME 1584866460.17094
VALUE 943201
myDbLogRemote:
TIME 1584866460.1715
VALUE 943201
READINGS:
2020-03-22 10:20:44 CacheUsage 2
2020-03-22 10:20:25 NextSync 2020-03-22 10:23:55 or if CacheUsage 500 reached
2020-03-21 20:53:02 countCurrent 0
2020-03-22 09:41:00 countHistory 943201
2020-03-22 10:07:59 lastCachefile /opt/fhem/backup/db/cache_myDbLog_2020-03-22_10-07-59 (13 cache rows exported)
2020-03-22 10:20:25 state connected
Attributes:
DbLogInclude countHistory
DbLogSelectionMode Include
asyncMode 1
bulkInsert 1
cacheEvents 1
comment valuefn { if ($DEVICETYPE eq 'speedtest' && $READING eq 'ping' && not $VALUE =~ /^-?\d+(?:\.\d+)?$/) { $VALUE = 0; } }
event-on-change-reading
countHistory,state,CacheUsage,background_processing_time
event-on-change-reading countHistory,state,CacheUsage
expimpdir /opt/fhem/backup/db/
group DB-Log
room Server
showNotifyTime 0
showproctime 0
syncInterval 210
valueFn { if ($DEVICE eq 'speedtest' && $READING eq 'ping' && not $VALUE =~ /^-?\d+(?:\.\d+)?$/) { $VALUE = 999; } }
verbose 5
Moin,
ZitatNun erhalte ich aber bei regelmäßig Probleme wegen doppelten Einträgen. Wenn ich den Cache mit den Sätzen nach dem Fehler ansehe sind da Sätze drin die auch schon auf der DB sind. Sollte nicht sein oder?
und
ZitatSolange der Cache einen doppelten Satz enthält wird auch später nichts mehr auf die DB geschrieben, der Cache wächst und wächst.
Ich kann sicher mit der Comitsteuerung die als Attibut vorliegt das Problem sicher lösen, aber mich würde die Ursache interessieren, dich sicher auch.
Ja, ich kenne auch schon den Grund bzw. Lösung. :)
Das Modul unterstützt einen
primary Key, nicht den unique Key.
Wird der Key nicht erkannt, verwendet DbLog den "normalen" Schreibmodus.
Man sieht es auch schön im Log:
2020.03.22 08:30:10.510 4: DbLog myDbLog -> ################################################################
2020.03.22 08:30:10.510 4: DbLog myDbLog -> ### New database processing cycle - asynchronous ###
2020.03.22 08:30:10.510 4: DbLog myDbLog -> ################################################################
....
2020.03.22 08:30:10.526 4: DbLog myDbLog -> Primary Key used in history: none
2020.03.22 08:30:10.526 4: DbLog myDbLog -> Primary Key used in current: none
....
Der Cache wächst weil die Daten im Normalfall als Transaktion behandelt werden, alle oder keine. Mit dem commitMode -Attribut kann man das steuern, kennst du ja schon.
Du müsstest also einen PK anlegen, dann passt das.
Zitat
Was mit auch noch aufgefallen ist, wenn ich "set myDbLog exportCache" per "at" einplane dann funktioniert es, wenn ich das aber im Timer-Modul (88_Timer.pm) einplane dann ist die Date zwar vorhanden, jedoch 0-KB groß, trotz Cache > 0. Idee? Wenn nicht mach ich ggf. einen eigenen Post dazu.
Nee, keine Idee. Würde mich aber auch interessieren weil ich mir das neue Timer-Modul auch mal anschauen wollte.
Wenn du einen neuen Thread aufmachst sehe ich das ja.
LG,
Heiko
werde ich testen ... dachte mit dem unique sollte es auch funktionieren. Zum anderen Thema mache ich einen eigenen Post ..
danke dir
Zitatdachte mit dem unique sollte es auch funktionieren
Solltest du Statements kennen, die eine Unique key sowohl bei MySQL, als auch bei SQLite und PostgreSQL sicher erkennen, kann ich auch dafür eine Unterstützung einbauen. Momentan nur PK.
Zitat von: DS_Starter am 22 März 2020, 12:37:08
Solltest du Statements kennen, die eine Unique key sowohl bei MySQL, als auch bei SQLite und PostgreSQL sicher erkennen, kann ich auch dafür eine Unterstützung einbauen. Momentan nur PK.
Mit meiner Antwort "mit dem unique sollte es auch funktionieren" meinte ich auf der DB die dubletten zu verhindern. Ich hatte deinen Code nicht angesehen wie du prüfst.
Meinst du sowas s. u.? Müsste reichen um zu prüfen ob ein unique-Index über die 3 Felder existiert. Ob zuverlässig weiß ich nicht, könnte releaseabhängig sein. Ist aber mehr als nur ein einfacher Select, du müsstest prüfen ob die Felder mit unique vorkommen. Und bei allen 3 DB-Typen unterschiedlich. Ob es lohnt musst du entscheiden :)
MySQL
show index from history
Im Ergebnis gibt es eine Spalte "Non_Unique" die besagt ob der Index "Unique" ist. Ich denke damit wird alles zurückgeliefert, Name, Felder, Sequence ...
Postgresql
feld "indexdef" in Tabelle "pg_indexes". Da ist die Information als Text in dem einen Feld. String "unique" und felder sind auch drin. Link s. u. ...
https://www.postgresqltutorial.com/postgresql-indexes/postgresql-list-indexes/
SQlite
Ähnlich MySQL
Select * FROM sqlite_master AS o,
pragma_index_list(o.name) AS p,
pragma_index_info(p.name)
WHERE o.type = 'table'
ORDER BY tbl_name, seqno;
https://www.sqlite.org/pragma.html#pragma_index_list
Btw.: das Problem mit dem Timer-Modul habe ich gelöst. Ich mache commitCache und im Anschluss direkt ein export_Cache, da ist scheinbar der erste Befehl noch nicht ganz abgearbeitet bevor ich exportieren will. Mit einem Sleep 1 zwischen beiden Befehlen funktioniert es. Hat nichts mit Timer-Modul zu tun.
Ja danke, ich schau mal. Ist eben die krux, gibt nichts einheitliches. :(
Hatte auch schonmal geforscht, war aber irgendwie stecken geblieben. Vielleicht hatte ich damals einfach keine Lust mehr. ::)
LG,
Heiko
Wird jetzt etwas OT aber ... was spricht dagegen per Default
- den Suchindex immer als Primary-Key anzulegen? Schon im Script beim anlegen der DB?
- den Insert immer mit Zusatz "ignore" zu machen?
Doppelte Sätze mit gleichem TS kann Fhem sowieso nicht korrekt verarbeiten. Zumindest nicht in Plots. Und auch so ... wie soll ein Reading zum selben Zeitpunkt unterschiedliche Werte besitzen ... "Schrödingers Katze" :)
Dadurch wäre die Datenqualität sichergestellt und der Sourcecode einfacher.
Zitat
Wird jetzt etwas OT aber ... was spricht dagegen per Default
- den Suchindex immer als Primary-Key anzulegen? Schon im Script beim anlegen der DB?
- den Insert immer mit Zusatz "ignore" zu machen?
Nichts denke ich. Dann würde auch automatisch ignore greifen, muss man sonst nichts ändern.
Müsste man nochmal durchdenken ...
Mit verbose 3 (Standard) gibt es dann immer Warnungen. Ist nicht schlimm -> verbose 2 einstellen, aber gerade Anfänger sind dann mit Sicherheit irritiert und glauben etwas falsch gemacht zu haben. Das erhöht vermutlich wieder die Frequenz der Meldungen hier und den Supportaufwand.
ZitatUnd auch so ... wie soll ein Reading zum selben Zeitpunkt unterschiedliche Werte besitzen
Naja, ist nicht ganz richtig. Wir haben ja als kleinste Zeiteinheit 1 Sekunde. Änderungen die unter einer Sekunde liegen sind somit "gleich", wobei nciht wirklich korrekt wenn man Millisekunden berücksichtigen würde.
Aber das wohl eher eine theoretische Betrachtung ...
Hi,
erstmal der Versuch das Thema nochmal aufzuwärmen.
Ich habe genau das gleiche Problem.
Wenn ich async aktiviere wird nichts in die DB gelogged aufgrund von Duplicates im Cache.
Im Sync Modus werden die Daten bis auf den duplicate geschrieben.
Wie kann es passieren, dass duplicate sim Cache entstehen und wie kann ich die Datenbank ändern damit sie duplicates "weiter" fasst?
Würde es ausreichen einen Primary Key zu erstellen?
PRIMARY KEY (`DEVICE`, `READING`, `TIMESTAMP`),
Oder wäre das hier besser?
ALTER TABLE history DROP INDEX Search_Idx, ADD UNIQUE KEY `Search_Idx` (`TIMESTAMP`,`READING`,`DEVICE`,´STATE´)
Ich bin für jede Hilfe Dankbar.
Im Async Modus würde ja solange zwischengespeichert bis #Zugriff auf die Datenbank wieder möglich ist. d.h. auch bei einem Neustart der Datenbank würden die Einträge gepuffert. Sehe ich das richtig?
ZitatWie kann es passieren, dass duplicate sim Cache entstehen
Kann z.B. passieren wenn Readings innerhalb einer Sekunde gleiche Werte mit Events werfen. Die kleinste Zeiteinheit in unseren Datenbanken in FHEM ist aber 1 Sekunde. Diese Datensätze haben dann den gleichen Timestamp und werden als Dubletten behandelt.
Den PK anlegen ist eine Variante, z.B. so:
DELETE FROM fhem.history WHERE TIMESTAMP IN (SELECT MAX(TIMESTAMP) FROM fhem.history GROUP BY TIMESTAMP, DEVICE, READING HAVING COUNT(*) > 1);
ALTER TABLE fhem.history ADD PRIMARY KEY(TIMESTAMP, DEVICE, READING);
(Wenn es schon Dubletten in der DB gibt, lässt sich kein PK anlegen)
Kein Unique Key anlegen, der wird z.Z. vom Modul nicht unterstützt.
Alternativ kannst du auch den CommitMode umschalten mit dem Attribut:
set <> commitMode ac:on_ta:off
Damit sollten auch nur die Dubletten im Cache verbleiben. Den Cache kann man mit purgeCache löschen.
Zitat
Im Async Modus würde ja solange zwischengespeichert bis #Zugriff auf die Datenbank wieder möglich ist. d.h. auch bei einem Neustart der Datenbank würden die Einträge gepuffert. Sehe ich das richtig?
Ja, stimmt so.
Hi und vielen Dank für die schnelle Antwort.
Müsste man den Primary Key nicht not auf z.b. Value ausweiten?
Das dürfte die Wahrscheinlichkeit von Dubletten noch weiter reduzieren und dürften von de rDatenbank nicht mehr abgelehnt werden oder?
Zitat
Müsste man den Primary Key nicht not auf z.b. Value ausweiten?
Das könnte man m.M. nach zwar machen, aber es wäre vermutlich übertrieben.
Man muß ja auch berücksichtigen, dass ein Index Speicherplatz und Ressourcen benötigt. Im Extremfall braucht der Index ebenso viel Platz in der DB wie die Daten selbst. Darüber hinaus braucht das DBMS auch Power um den Index bei Datenänderungen zu verwalten und zu aktualisieren.
Möglicherweise erreicht man dann das Gegenteil von dem was man erreichen wollte ... eine performante DB...
Ausprobieren kann man natürlich alles :) Glückiicherweise kann man so einen Index ja auch wieder löschen ;)
Moin,
ich häng mich hier nochmal kurz ran:
phpmyadmin unterstützt editieren von Tabellen nur noch mit einer unique-spalte.
Jetzt bin ich wieder dran, den unterschied zwischen pk und unique-key zu verstehen ...
Dabei kam mir der Gedanke:
Wäre es nicht sinnvoll, bei der installation von DbLog direkt einen pk anzulegen und im ConfigCheck auch den Rat zu geben, diesen anzulegen?
Was mich aber gerade mehr beschäftigt:
Ich könnte ja - danke der oben gegebenen Antwort - jetzt einen pk anlegen.
in den Attributen steht auch
noSupportPK
attr <device> noSupportPK [1|0]
Deactivates the support of a set primary key by the module.
Da meine Datenbank gerade mit dem Löschen von duplikaten beschäftigt ist, hab ich Zeit drüber nachzudenken, warum ich den Support eines PK durch das Modul deaktivieren wollen könnte... und, welchen Vorteil die Verwendung eines PK durch das Modul hat?
Vielleicht könntest du mich ja kurz erhellen...
Danke,
stephan
ZitatWäre es nicht sinnvoll, bei der installation von DbLog direkt einen pk anzulegen und im ConfigCheck auch den Rat zu geben, diesen anzulegen?
Bei neuen Installation wäre es durchaus sinnvoll. Aber im ConfigCheck eher weniger weil normalerweise im Bestand bereits doppelte DS vorhanden sind und der Supportaufwand zu groß wäre wenn jeder (nicht DB Admin) der darüber stolpert versucht das hinzubekommen und es nicht schafft. Die Fragen kommen dann hier warum wie was wo nicht geht usw. usf. ...
Zitat
... warum ich den Support eines PK durch das Modul deaktivieren wollen könnte...
Das braucht man im Normalfall nicht. Es war/ist für bestimmte Fehleranalysen bestimmt, wie das Modul mit/ohne Support mit der jeweiligen DB arbeitet, den PK erkennt etc. ....
Zitat
und, welchen Vorteil die Verwendung eines PK durch das Modul hat?
Der Code ist auf die Erkennung und Verwendung eines PK abgestimmt. Wenn es nicht so wäre kämen entsprechende Fehlermeldungen im Log.
Grüße,
Heiko
Zitat von: DS_Starter am 01 Februar 2021, 21:43:07
weil normalerweise im Bestand bereits doppelte DS vorhanden sind und der Supportaufwand zu groß wäre wenn jeder (nicht DB Admin) der darüber stolpert versucht das hinzubekommen und es nicht schafft.
Man könnte ja
set DbLog createPrimaryKey
einführen, der dann zuerst einen delDoublets ausführt und danach den PK erzeugt. Dann hätte der Anwender keine Probleme. Aber Ich vermute, der Supportaufwand würde trotzdem steigen. Solange sich keiner beschwert, dass er mit phpmyadmin nicht mehr ran kommt ... ;)
Zitat von: DS_Starter am 01 Februar 2021, 21:43:07
Der Code ist auf die Erkennung und Verwendung eines PK abgestimmt. Wenn es nicht so wäre kämen entsprechende Fehlermeldungen im Log.
Das beantwortet meine Frage noch nicht ganz. Klar kämen Fehlermeldungen wenn DbLog versuchen würde, zwei gleiche Datensätze einzufügen.
Heisst das, der "Primary Key Support" besteht "nur" darin, dass das Modul mit den Fehlermeldungen umgehen kann und den doppelten Datensatz verwirft?
Oder ändert sich da noch anderes Verhalten?
Ich werds wohl mal versuchen :)
Danke und Grüße,
Stephan
Zitat
Man könnte ja
Code: [Auswählen]
set DbLog createPrimaryKey
einführen, der dann zuerst einen delDoublets ausführt und danach den PK erzeugt.
Nicht im DbLog, aber im DbRep. Dort gibt es für "normale" Index bereits Pflegeroutinen. Aber es bleiben ein paar Dinge. Zum Beispiel darf kein Logging während des Bereinigens laufen, d.h. der User _muß_ asynchron eingestellt haben. Datenbanken können groß sein, was auf einem PI auch wieder zu Performanceproblemen bei diesen Manipulationen führen kann und sicherlich noch viele Situationen mehr was den Support auf den Plan ruft....
ZitatDas beantwortet meine Frage noch nicht ganz. Klar kämen Fehlermeldungen wenn DbLog versuchen würde, zwei gleiche Datensätze einzufügen.
Heisst das, der "Primary Key Support" besteht "nur" darin, dass das Modul mit den Fehlermeldungen umgehen kann und den doppelten Datensatz verwirft?
Nein, es werden andere SQL's verwendet. Weiterhin kann ein gesetzter PK auch den normalen Search_Idx ersetzten. Beides braucht man nicht.
Grüße,
Heiko
Zitat von: DS_Starter am 02 Februar 2021, 22:22:32
Zum Beispiel darf kein Logging während des Bereinigens laufen
ja.... an dem Punkt bin ich grade.
Hab jetzt erstmal meine Datenbank von der HDD auf ein btrfs-SSD-Volume umgezogen. Damit läuft da hoffentlich schonmal einiges schneller (nein, bin nicht auf dem Raspi).
Dabei habe ich die Fähigkeiten der cacheFiles benutzt, und mich dran erinnert, wie ich da vor einigen Jahren mir rumgetestet hab.
Seitdem lief es problemlos und ich hab heute mal wieder großen Respekt vor deiner Arbeit bekommen.
Ich habe mysql gestoppt, daraufhin loggt DbLog ja in den Cache (und ich kann das in eine Datei exportieren). Sobald die Datenbank wieder läuft, schreibt DbLog wieder in die Datenbank. (funktioniert einwandfrei, echt cool!. Ich bräuchte jetzt aber eine Möglichkeit, DbLog dazu zu bewegen, die Daten nicht zu schreiben, bis ich die Doublets entfernt und einen PK erzeugt habe.
Gibts dafür einen Parameter/Attribut? Sowas wie
attr DbLog SchreibNixInDieDatenbankAuchWennSieVerfügbarIst 1
?
reopen [n] ist mir zu gefährlich, weil ich nicht weiss, wie lange die db braucht.
Wäre aber auch nur ein "nettes Feature", ich ändere die Daten im config-File, das hat den gewünschten Effekt (DbLog sammelt weiter Meldungen, schreibt aber nicht in die Datenbank)
Zitat
Nein, es werden andere SQL's verwendet. Weiterhin kann ein gesetzter PK auch den normalen Search_Idx ersetzten. Beides braucht man nicht.
[/quote]
danke für die Info!
Viele Grüße,
Stephan
Zitat
Gibts dafür einen Parameter/Attribut? Sowas wie
Code: [Auswählen]
attr DbLog SchreibNixInDieDatenbankAuchWennSieVerfügbarIst 1
?
reopen [n] ist mir zu gefährlich, weil ich nicht weiss, wie lange die db braucht.
Momentan gibt es nur das reopen XX. Ich weiß ein active/deactive nach dem Vorbils des AT-Moduls wäre sicherlich hilfreich.
Vielleicht baue ich das noch ein (habe schon lange nichts am DbLog gearbeitet).
Du könntest reopen ja auf ein Jahr setzen. Sollte vorerst reichen. ;)
GN,
Heiko