Forum: PC-Programmierung MySQL, Datensätze begrenzen?


von Markus (Gast)


Lesenswert?

Wie kann ich bei Mysql die Anzahl der Datensätze begrenzen?
Also ich möchte gerne für eine Messwertaufzeichnung gerne der Tabelle 
sagen, dass sie maximal 1000 Einträge haben darf, wenn ein neuer mit 
INSERT hinzugefügt wird, dann soll automatisch der älteste gelöscht 
werden.

Hintergrund: Ringbuffer für Messwertaufzeichnung.

Geht das überhaupt?
Oder muss ich das in der Applikation selbst programieren?

Danke für eure Hilfe.

Gruß Markus.

von Peter (Gast)


Lesenswert?

soweit ich weiss geht es nicht. Da musst du dich schon selber drum 
kümmern.

Aber eine DB ist dazu da Daten zu speichern - also warum der Geiz?

von Markus (Gast)


Lesenswert?

300 Messwerte * 1440 Minuten/Tag  365 Tage  5 Jahre = 788400000 
Datensätze

Das schafft mein PC nicht !!!!

von Peter (Gast)


Lesenswert?

wenn jeder datensatz 100Byte gross ist sind das auch bloss 80GB. Das 
schafft heute schon jeder REchner in 5Jahren erst recht.

von (prx) A. K. (prx)


Lesenswert?

Regelmässig sinngemäss
  delete from mytable where logtime < current timestamp - 1 day
laufen lassen und gut ist (oder so ähnlich, weiss grad nicht wie das in 
mysql heisst).

In der Luxusvariante machst du sowas via Trigger.

von Εrnst B. (ernst)


Lesenswert?

Vielleicht ist mysql dann nicht die richtige Wahl für dein Projekt.
schau dir z.B. mal RRDTOOL an, das ist für round-robin-databases, genau 
dein Anwendungsfall.
Da hast du für kurz zurückliegende Zeiträume (1000 Messungen) eine hohe 
Auflösung, kannst aber trotzdem noch den gesamten Zeitraum (5 Jahre) 
überblicken.

Und passende Tools zum graphischen Darstellen gibts auch gleich dazu.

von (prx) A. K. (prx)


Lesenswert?

Yep, rrdtool ist dafür besser geeignet.

von Markus (Gast)


Lesenswert?

@Peter:
Mein Rechner ist: Atom-CPU, 32GB SSD Disk, keine bewegten Teile, soll 
autark 10 Jahre ganz alleine laufen! Nix Rechnertausch, kein User, 
völlig autark.

@Ernst:
Das geht nicht. Die Applikation ist schon fast fertig. Nur noch die 
"Kleinigkeit" mit der Aufzeichnung.

@A.K., alle:
Da würden sich Trigger "AFTER INSERT" eignen. Ich hab die nur noch nie 
benutzt. Kann mir bitte jemand posten, wie sowas aussehen könnte?

Vielen Dank

von (prx) A. K. (prx)


Lesenswert?

Wirst dir erst einmal überlegen müssen, wie man rauskriegt was der 
älteste Eintrag ist. Denn ausser dir kennt niemand die Tabelle.

Wenn das nicht immer genau 1000 Einträge sein müssen und eine Timestamp 
drin ist, du also nach Alter gehen kannst, wird das deutlich einfacher 
(siehe oben). Auf exakt 1000 Einträge zu begrenzen ist glaube ich etwas 
haariger. Mit sequentieller ID geht das, aber nur, wenn darin garantiert 
keine Löcher auftreten, was je nach Arbeitsweise und 
Transaktionsverfahren nicht so sicher ist.

von Peter (Gast)


Lesenswert?

ich kann nur etwas allgemeines zu Triggern sagen.

Das ganze sind SQL Befehle (Proceduren) die Ausgeführt werden wenn ein 
Datensatz geändert/eingefügt/gelöscht wurden.

Du müsstest sinnvoller weise ein ID Spalte haben die bei jedem Einfügen 
um 1 Hochgezählt wird ( autoident).

Der Tigger macht dann

delete from XXX where ID < ( select max(ID) from XXX )-1000

damit hast du immer 1000 Einträge in der db.

aber durch das löschen kann es passieren das das ganze einfügen von 
Datensätzen etwas verzögert wird.

von (prx) A. K. (prx)


Lesenswert?

Peter schrieb:

> Du müsstest sinnvoller weise ein ID Spalte haben die bei jedem Einfügen
> um 1 Hochgezählt wird ( autoident).

Yep. Ausser wenn er irgendwann auf die Idee kommt, die Tabelle manuell 
zu reparieren und mal mittendrin einen Eintrag löscht. Dann sind es eine 
Weile lang nur noch 999. Auch bei Verwendung von Transaktionen kannst du 
nicht unbedingt darauf setzen, dass keine Löcher entstehen.

Aber bei der hier anzunehmenden einfachsten Verwendung ist das wohl kein 
Problem.

Aber wenn das konstant in regelmässigen Intervallen reinkommt, ist Zeit 
ohnehin einfacher.

von Markus (Gast)


Lesenswert?

Ich hab mir hier ein Befehl zusammengebaggert, klappt aber nicht.
1
DELETE FROM aufz_1 ORDER BY Datum LIMIT SELECT (COUNT(Datum) - 3) AS X FROM aufz_1

Damit würden die letzten 3 Datensätze erhalten bleiben.
Aber irgendwie kann der das LIMIT nicht aus der SELECT Anweisung holen.

von (prx) A. K. (prx)


Lesenswert?

Ohne die Tabellenstruktur (und ggf. die mysql Version) zu kennen kann 
dir niemand wirklich konkret helfen, sondern nur Allgemeines absondern.

von Markus (Gast)


Lesenswert?

Ja, das ist die Tabelle:

[c]CREATE TABLE `tracker`.`aufz_1` (
`Datum` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
`Wert` DOUBLE NOT NULL
) ENGINE = InnoDB;
ALTER TABLE `aufz_1` ADD INDEX ( `Datum` ) ;
ALTER TABLE `aufz_1` ADD INDEX ( `Wert` );
[c]

von Markus (Gast)


Lesenswert?

MySQL: das aktuelle XAMPP Paket V5.1

von (prx) A. K. (prx)


Lesenswert?

Bau dir eine where clause, die auf der Basis von "Datum" alle veralteten 
Einträge liefert. Das funktioniert in jeden SQL ein bischen anders, so 
dass ich mysql grad nicht parat habe, geht da aber garantiert auch.

Entweder indem mit der aktuellen Zeit abzüglich irgendwas verglichen 
wird, oder wenn die Differenz zur aktuellen Zeit zu gross wird.

Und wenn du das hast, dann ist der Schritt zu
   create trigger ... after insert delete from ... where ...
nicht mehr weit.

von Dieter E. (netdieter) Benutzerseite


Lesenswert?

Ich würde das asynchron machen.
Was spricht dagegen ein SQLSkript per Scheduler z.B ein mal am Tag aus 
zu führen.
Das kuckt einfach auf geeignete Weise nach welche Sätze verworfen werden 
können und gut ist.

von Markus (Gast)


Lesenswert?

Ich hab mal das versucht, aber ich kann nicht sagen ob es tut.
mein Apache/phpMyAdmin ist abgeschmiert (50% Rechenlast)
1
DELIMITER |
2
3
CREATE TRIGGER aufz_1_trg BEFORE INSERT ON aufz_1
4
BEGIN
5
  DECLARE dt TIMESTAMP;
6
  SELECT Datum INTO dt FROM aufz_1 ORDER BY Datum DESC LIMIT 2,1;
7
  DELETE FROM aufz_1 WHERE Datum < dt;
8
END;
9
|
10
11
DELIMITER ;
Könnte das gehen?

von Peter (Gast)


Lesenswert?

wass willst du dennn immer mit dem Limit das ist hier fehl am platz.

SELECT Datum INTO dt FROM aufz_1 ORDER BY Datum DESC LIMIT 2,1;

du willst damit ja den ältesten datensatz löschen, richtig?

dann mach

delete from aufz_1 where Datum = ( select min(Datum) from aufz_1 );

Aber damit hast du nicht sichergestellt das dann immer 1000 Datensätze 
drin sind, die löschst halt immer einen wenn einer eingefügt wird.

von Markus (Gast)


Lesenswert?

Ich hab noch was anderes gemacht, also eine Kombination aus dem was oben 
gezeigt wurde:
1
DELIMITER |
2
3
CREATE TRIGGER aufz_1_trg BEFORE INSERT ON aufz_1
4
BEGIN
5
  DECLARE i INT DEFAULT 0;
6
  SELECT COUNT(Datum) INTO i FROM aufz_1;
7
  WHILE i > 3 DO
8
    DELETE FROM aufz_1 WHERE Datum = (SELECT MIN(Datum) FROM aufz_1);
9
    SET i = i - 1;
10
  END WHILE; 
11
END;|
12
13
DELIMITER ;

Was ist an dem Code falsch, warum geht das nicht?
Muss die Tabelle von einem bestimmten Typ sein? MyISAM, InnoDB, usw.?
(Jetzt hab ich auch kein LIMIT mehr drin)

von Peter (Gast)


Lesenswert?

was kommt denn für eine Fehlermeldung?

von Markus (Gast)


Lesenswert?

Irgend was stimmt in der Zeile 2 nicht. Ich hab den Script nun so 
geändert:
1
CREATE TRIGGER `aufz_1_trg` AFTER INSERT ON `aufz_1`
2
 FOR EACH ROW BEGIN
3
  DECLARE i INT DEFAULT 0;
4
  DECLARE dt TIMESTAMP;
5
  SELECT COUNT(Datum) INTO i FROM aufz_1;
6
  WHILE i > 3 DO
7
    SELECT MIN(Datum) INTO dt FROM aufz_1;
8
    DELETE FROM aufz_1 WHERE Datum = dt;
9
    SET i = i - 1;
10
  END WHILE; 
11
END
12
//

Jetzt füge ich mit INSERT Datensätz hinzu, und sobald ich den 5. 
Datensatz hinzufügen möchte kommt diese Fehlermeldung:

#1442 - Can't update table 'aufz_1' in stored function/trigger because 
it is already used by statement which invoked this stored 
function/trigger.

Hmmm ... ???

von Peter (Gast)


Lesenswert?

scheint eine begrenzung in mysql zu sein, das man ein Tabelle im Tigger 
nicht ändern kann.

Ich würde, wie oben schon erwähnt, einfach nachts ein job laufen lassen 
der alle Datensätze älter als 24Stunden löscht. Ob nun 1000 oder 5000 in 
der DB sind ist ja egal.

von Markus (Gast)


Lesenswert?

Ich wollte es halt "Perfekt" haben, egal von was für einem Client die DB 
bedient wird...
... Und ich hab grad ein paar Minuten Zeit mich fortzubilden.

Möglichst viel die Datenbank automatisch machen lassen.

von Peter (Gast)


Lesenswert?

Dann nimm eine "richtige" Datenbank. Da du eh unter windows arbeitest 
kannst du ja auch den SQL-Server von MS nehmen.

Der kann automatisiert jobs in der DB ausführen und das mit dem Tigger 
geht dann auch.

MYSQL ist zwar schön, aber kommt noch nicht an die grossen DBs ran.

(die Expressversion von MS-SQL2008 ist kostenlos!)

von Markus (Gast)


Lesenswert?

Früher hatte ich Interbsae benutzt, da hat sowas auch geklappt.

von Markus (Gast)


Lesenswert?

Meinte Interbase von Borland

von Peter (Gast)


Lesenswert?

naja Interbase ist heute wirklich veraltet - es läuft nicht sauber wenn 
mehr als 1CPU vorhanden ist.
Es wird ja unter den Namen Firebird weiter entwickelt, aber so richt 
schön finde ich sie auch nicht. Ab ein paar 100Mbyte datenbank größe 
lässt die Performance recht stark nach. (oder ich weiss nicht wie man 
das ding optimieren kann)

von Markus (Gast)


Lesenswert?

Ja, seit dem ich MySQL mit Lazarus und native Komponenten verwende ist 
ein anderes Programm 10x schneller. Interbase >> tschüss. Damals, vor 
vielen Jahren war die Anbindung von Interbase an Delphi um Welten 
besser, erst jetzt ist mit "ZeosDBO" die Verwendung von MySQL super 
einfach geworden.
Die ADO Komponenten sind einfach Schrott und viel langsamer.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.