MySQL, Datensätze begrenzen?

Gast #1264460
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.
#1264490
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.
Gast #1264500
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
#1264502
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.
Gast #1264506
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.
#1264522
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.
Gast #1264544
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.
Gast #1264548
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]
#1264572
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.
Gast #1264583
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?
Gast #1264628
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.
Gast #1264688
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)
Gast #1264721
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 ... ???
Gast #1264725
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.
Gast #1264729
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.
Gast #1264745
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!)
Gast #1264755
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)
Gast #1264783
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren