FHEM Forum

FHEM => Automatisierung => Thema gestartet von: kadettilac89 am 22 März 2020, 10:33:20

Titel: DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: kadettilac89 am 22 März 2020, 10:33:20
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
Titel: Antw:DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: DS_Starter am 22 März 2020, 12:21:43
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
Titel: Antw:DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: kadettilac89 am 22 März 2020, 12:33:59
werde ich testen ... dachte mit dem unique sollte es auch funktionieren. Zum anderen Thema mache ich einen eigenen Post ..

danke dir
Titel: Antw:DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: DS_Starter am 22 März 2020, 12:37:08
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.
Titel: Antw:DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: kadettilac89 am 22 März 2020, 15:03:12
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.
Titel: Antw:DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: DS_Starter am 22 März 2020, 15:13:56
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
Titel: Antw:DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: kadettilac89 am 22 März 2020, 15:55:31
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.
Titel: Antw:DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: DS_Starter am 22 März 2020, 16:24:37
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 ...

Titel: Antw:DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: buliwyf am 22 Oktober 2020, 07:57:24
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?
Titel: Antw:DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: DS_Starter am 22 Oktober 2020, 08:45:24
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.
Titel: Antw:DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: buliwyf am 22 Oktober 2020, 12:51:50
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?
Titel: Antw:DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: DS_Starter am 22 Oktober 2020, 20:12:08
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  ;)
Titel: Antw:DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: abc2006 am 01 Februar 2021, 21:11:56
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
Titel: Antw:DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: DS_Starter am 01 Februar 2021, 21:43:07
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

Titel: Antw:DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: abc2006 am 02 Februar 2021, 09:12:37
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
Titel: Antw:DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: DS_Starter am 02 Februar 2021, 22:22:32
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
Titel: Antw:DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: abc2006 am 02 Februar 2021, 23:23:34
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
Titel: Antw:DBLog -- DBD::mysql::st execute failed: Duplicate entry
Beitrag von: DS_Starter am 02 Februar 2021, 23:42:01
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