[Postfixbuch-users] AMAVIS-NEW: MySQL LOCK Problem beim Löschen der DB-Daten
Christian Boltz
postfixbuch at cboltz.de
Do Jul 12 02:19:39 CEST 2007
Hallo Egon, hallo Leute,
dass die beste Spambekämpfung ein REJECT an der Haustür ist, hast Du ja
schon oft genug gesagt bekommen. Ich möchte mich da nicht wiederholen.
Ich beschränke mich deshalb in dieser Mail auf den MySQL-Part. Die
genannten Infos habe ich großteils ein paar netten Abenden bei Kris
Köhntopp zu verdanken :-)
Am Montag, 9. Juli 2007 schrieb Egon Gruber:
> Habe sämtliche Tabellen in Mysql (4.1.20) so angelegt wie in der
> README.sql beschrieben und
> in der Nacht (ab Mitternacht) werden folgende tägliche Löschvorgänge
> gestartet.
>
> Beschrieben in "2. Mailserver-Konferenz, Mai 2005" Seite 59
> http://www.ijs.si/software/amavisd/amavisd-new-magdeburg-20050519.pdf
> Meine 3 Fragen:
> 1. Gibt es da evtl. eine bessere Möglichkeit die DB-Daten zu löschen,
> ohne eine nächtliche Blockierung (DB-LOCK) des Mailtraffics
Du kannst zumindest einiges optimieren.
[Queries und Dauer umsortiert, zwecks besserer Übersicht]
> 1. DELETE FROM msgs WHERE UNIX_TIMESTAMP()-time_num > 7*24*60*60;
> 2. DELETE FROM msgs WHERE UNIX_TIMESTAMP()-time_num > 60*60 AND
> content IS NULL;
[...]
> Dabei starte ich den Löschvorgang jeweils um 00:40.
> Im einzelnen dauern die einzelnen Löschvorgänge ungefähr:
> 1. 1 h und 20 Minuten
> 2. 30 Minuten
Erste Optimierung ist ein Upgrade auf MySQL >= 5.1, weil der nächste
Schritt davon abhängt ;-)
Zweite Optimierung: Die Tabellen passend partitionieren, siehe dazu
http://dev.mysql.com/doc/refman/5.1/en/partitioning.html
Ich habe das noch nie gebraucht, daher liefere ich keine fertigen
Queries. Die Grundidee ist jedenfalls:
- Du kannst beim Anlegen der Partitionen Kriterien angeben, nach denen
in die Teil-Tabellen sortiert wird. In Deinem Fall wären der Timestamp
(1. und 2. Abfrage) und auch "content IS NULL" (2. Abfrage)
empfehlenswerte Sortierkriterien
- Falls "content IS NULL" nicht direkt verwendbar ist (musst Du testen),
empfiehlt sich ein Trigger bei INSERTs, der in einer Hilfsspalte true
oder false einträgt.
- Oder Du baust einen Trigger bei INSERTs, der eine Spalte "expires"
füllt (mit unterschiedlicher Lebensdauer abhängig davon, ob "content"
NULL ist oder nicht). Das dürfte die beste Lösch-Performance bringen.
In der Praxis heißt das, dass Du eine Teil-Tabelle pro Tag hast. Das
Einsortieren in diese Teil-Tabelle macht MySQL mehr oder weniger
automatisch.
Kommen wir zum nächtlichen Cron-Job. Der macht:
- Teil-Tabellen mit alten Daten (alles, das Du löschen willst) aus dem
Verbund "ausklinken" und löschen
- neue Teil-Tabelle für den nächsten Tag anlegen und passend einbinden
Ich wäre nicht überrascht, wenn Du damit die beiden Queries auf unter
1 Minute eindampfen könntest. ;-)
> 3. DELETE quarantine FROM quarantine LEFT JOIN msgs USING(mail_id)
> WHERE msgs.mail_id IS NULL;
> 3. 1 h und 30 Minuten
Zeig mal die Ausgabe von
EXPLAIN DELETE quarantine FROM quarantine LEFT JOIN msgs USING(mail_id)
WHERE msgs.mail_id IS NULL;
Außerdem würde mich interessieren, wieviele Datensätze in jeder Tabelle
liegen.
> 4 DELETE msgrcpt FROM msgrcpt LEFT JOIN msgs USING(mail_id) WHERE
> msgs.mail_id IS NULL;
> 4. 1 h und 10 Minuten
Auch hier bitte
EXPLAIN DELETE ...
und die Anzahl der Datensätze.
> 5. DELETE FROM maddr WHERE NOT EXISTS (SELECT sid FROM msgs WHERE
> sid=id) AND NOT EXISTS (SELECT rid FROM msgrcpt WHERE rid=id);
> 5. 10 Minuten
Auch hier bitte einmal
EXPLAIN DELETE ...
Ich warne allerdings im Voraus, dass Du bei dieser Query keine Stunde
einsparen kannst ;-))
Evtl. wäre es auch sinnvoll, das Ganze andersrum zu lösen.
Die derzeitige Query lautet "lösche alles ohne Gegenpart". Es muss also
für jeden Eintrag ein SELECT auf die Gegentabelle gemacht werden, um
sicherzustellen, dass der fragliche Eintrag nicht (mehr) existiert.
Evtl. wäre es besser, alle als "expired" eingestuften IDs zu löschen.
Das heißt auch, dass die jetzigen Queries 1 und 2 ganz zum Schluss
laufen müssen, weil Du die IDs für diese Query brauchst.
Ideallösung wäre ein DELETE-Trigger - ich weiß aber nicht, ob das
Löschen einer Teil-Tabelle (Queries 1 und 2) einen DELETE-Trigger
auslösen kann.
Da diese Query im Vergleich die schnellste ist, würde ich empfehlen,
erstmal die anderen Baustellen zu klären.
> 6. OPTIMIZE TABLE msgs, msgrcpt, maddr, quarantine;
> 6. 1 h und 10 Minuten
Kannst Du das mal für jede Tabelle einzeln messen?
(Mit etwas Glück hilft auch hier die Partitionierung.)
> 2. Wäre es von Vorteil den INDEX zuvor zu löschen
IMHO nicht. Es sei denn, Deine Löschaktion killt einen Großteil der
Datenmenge. (Ich weiß nicht, wo der genaue Anteil liegt, aber unter
(IMHO) 80% Löschkandidaten bringt das Löschen des Index wohl nichts.
Und außerdem muss er hinterher auch wieder erstellt werden...)
> 3. Hat jemand auch dasselbe Problem?
Ich verstecke meine Mails nicht in Datenbanken, daher: nein ;-)
Lesetipps:
- Die Online-Doku von MySQL ;-)
- http://mysqldump.azundris.com
Bei speziellen Fragen kann ein Besuch von #mysql auf irc.freenode.org
recht hilfreich sein.
Gruß
Christian Boltz
--
Der Schaden von privat benutzten Raubkopien entsteht absurderweise genau
der Konkurenz: Solange die Leute lieber ihre Raubkopie von Windows,
Office oder Photoshop benutzen, bekommen halt Linux, OpenOffice oder
Gimp keine Marktanteile. [Mirko Streckenbach in d.r.s.c.a]
Mehr Informationen über die Mailingliste Postfixbuch-users