Große Datenmengen filtern/löschen
lima-city → Forum → Programmiersprachen → PHP, MySQL & .htaccess
-
Hallo zusammen!
Schön mal wieder hier zu sein.
Ich habe folgende Herausforderung:
Es soll eine Tabelle mit Postleitzahlen bereinigt werden. Ausschlagebend für die Filterbedingung sind Chatnachrichten mit Postleitzahlen, die 24h lang nicht vorkamen.
Meine fixe Idee sieht jetzt wie folgt aus:
1. SQL-Abfrage, die alle Nachrichten der letzten 24h aufruft
2. Mit PHP alle PLZ sammeln und in eine monströse Abfrage packen
3. Diese Liste in ein monströses DELETE einfügen und starten
Das Problem:
Die Datenmengen sind enorm und ich kann nicht stundenlang die Datenbank bzw. auch die CPU (durch das PHP-Script) damit blockieren. Wir reden gerade von 114k Nachrichten in den letzten 24h und fast 10k Postleitzahlen. Die aus einer Tabelle mit 30k anderen Postleitzahlen gelöscht werden sollen. Wenn ich das jetzt in eine Query (á la PLZ = 1 OR PLZ = 2 ...) packe, weiß ich nichtmal, ob MySQL solange Query-Strings akzeptieren würde.
Die Frage:
Geht das einfacher? Gibt es vllt die Möglichkeit innerhalb der selben Query diese "Sammlung" an PLZ zu bekommen und direkt als Bedingung zu nehmen, ohne ein PHP-Script dazwischen zu brauchen?
Vielen Dank schonmal für jeden Tipp und jede Hilfe!
Viele Grüße
- VampireSilence -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage
-
Kannst du nicht anders vorgehen?
Bei jedem neuen Eintrag guckst du lediglich, ob es löschwürdige Einträge zur selben Postleitzahl gibt, führst nur diese Löschungen aus.
Dabei bleiben allerdings alte Einträge zu Postleitzahlen erhalten, bei denen es lange keine neuen Beiträge gibt.
Den Sachverhalt könntest du natürlich bei der Ausgabe der Beiträge diskriminieren, bei welcher nur dargestellt wird, was binnen der letzten vierundzwanzig Stunden passiert ist. -
Nein, das ist nicht das Ergebnis, das ich brauche. Ich versuche es nochmal anders zu beschreiben, vllt wird es dann klarer.
Ich möchte nachher nur noch diejenigen PLZ (die in einer seperaten Tabelle liegen) haben, von denen in den letzten 24h Nachrichten kamen. Erhalte ich also wie von dir vorgeschlagen eine Nachricht von dieser PLZ, ist sie in dem Augenblick ja wieder aktuell und muss dann nicht mehr gelöscht werden. -
Das war auch so gemeint, daß du erst beim Eintreffen eines neuen Betrags prüfst, ob es zur selben Postleitzahl alte Einträge gibt, die zu löschen wären.
So verteilt sich das Löschen eben auf viele Ereignisse und wird nicht auf einen Schlag erledigt.
Je nachdem, wie die Beiträge ausgegeben werden, kann es alternativ ja auch reichen, eine Prüfung für exakt eine Postleitzahl vorzunehmen, wenn überhaupt Beiträge zu der Postleitzahl zur Präsentation abgefragt werden.
Solange du keinen Vorgang hast, bei dem alle Beiträge beteiligt sind, kommt es auf eine Aktualisierung ja erst an, wenn eine Untermenge davon für irgendwas genutzt wird.
Erst dann ist es notwendig, die Aktualität dieser Untergruppe zu prüfen.
Weil du bei der angedeuteten Menge von Beiträgen ja vermutlich ohnehin nicht alle gleichzeitig für irgendwas nutzt, mußt du die ja auch nicht alle auf einen Schlag prüfen. -
Also du hast z.Bsp Einträge für A und wenn A seit 24h nicht vorgekommen ist soll alles mit A gelöscht werden?
Ich kann kein funktionierendes Beispiel bringen aber eventuell einige Teile die helfen könnten:
Du könntest doch sicherlich die PLZ über sql als Gruppe handhaben und dann wenn keiner der Einträge der Gruppe neuer als 24h alt ist alle löschen (Bzw lösche alle "A" wenn kein Datensatz innerhalb einer Gruppe "A" neuer als 24h ist)
https://stackoverflow.com/questions/11705996/possible-to-do-a-delete-with-a-having-clause
http://www.datenbanken-verstehen.de/sql-tutorial/sql-having-befehl/
https://stackoverflow.com/questions/63447/how-do-i-perform-an-if-then-in-an-sql-select
Da sollte sich doch sicherlich etwas mit bauen lassen.
Beitrag zuletzt geändert: 13.7.2019 22:08:53 von horstexplorer -
Es sollen keine Nachrichten gelöscht werden, es sollen nur PLZ gelöscht werden. Ich mache das jetzt mal ein bisschen plastischer, ich glaube das ist verständlicher.
TABELLE MIT PLZ (A) ID - PLZ 1 - 54241 2 - 16876 3 - 65475 ...
Es soll jetzt in Tabelle B nach PLZs geschaut werden. In diesem Minibeispiel fehlt die PLZ "65475". Diese PLZ kommt in Tabelle A nur ein einziges mal vor. Es gibt keine sonstigen Einträge. Und dieser eine einzige Eintrag von "65475" soll jetzt in Tabelle A gelöscht werden. Sodass nach dem Cleanup in Tabelle A nur noch PLZs sind, die in Nachrichten von Tabelle B vorkommen, die jünger als 24h sind. Es sollen keine Nachrichten gelöscht werden. Nur die PLZs in Tabelle A.TABELLE MIT NACHRICHTEN (B) ID - NACHRICHT - PLZ - etc ... 1 - Hallo - 54241 - ... 2 - Guten Tage - 16876 - ... 3 - Wie gehts ? - 54241 - ... ...
-
Ich habe da noch eine Idee:
Du kannst eigentlich auch Querys zusammen legen.
(Ich kann nicht überprüfen ob das so überhaupt funktionieren würde, aber evtl gibt das eine Richtung)
STMT0) SELECT plz FROM nachrichten WHERE age=älterals24h
STMTB) SELECT plz FROM nachrichten WHERE age=neuerals24h
Damit haben wir alle plzs welche älter und neuer als 24h sind. Wenn wir jetzt B von A abziehen sollten wir mit der Menge übrig bleiben die wir suchen.
Also wir wollen alle plzs die in A aber nicht in B vorkommen.
STMTC) SELECT plz FROM nachrichten WHERE age=älterals24h AND NOT plz=ALL(STMNTB)
Und dann müsste man das ganze noch aus der anderen Tabelle entfernen.
DELETE * FROM plzs WHERE plz=ANY(STMTC)
Vermutlich habe ich mich da irgendwo noch vertan, kann gut sein das Any/all falsch genutzt wird oder noch ganz andere sachen falsch sind. evtl muss man auch nen inner join nutzen, kann das gerade nicht testen.
-------------------------------------------------------------------------------------------------------
// Edit, das ganze scheint ganz so ähnlich zu funktionieren wie ich das dachte:
SQL
CREATE TABLE IF NOT EXISTS `plz` ( `id` int(6) unsigned NOT NULL, `plz` int(5) unsigned NOT NULL, PRIMARY KEY (`id`) ) DEFAULT CHARSET=utf8; INSERT INTO `plz` (`id`, `plz`) VALUES ('1', '11111'), ('2', '22222'), ('3', '33333'); CREATE TABLE IF NOT EXISTS `msgs` ( `id` int(6) unsigned NOT NULL, `plz` int(5) unsigned NOT NULL, `msg` TEXT NOT NULL, `age` int(2) unsigned NOT NULL, PRIMARY KEY (`id`) ) DEFAULT CHARSET=utf8; INSERT INTO `msgs` (`id`, `plz`, `age`, `msg`) VALUES ('1', '11111', '1', 'eins'), ('2', '22222', '25', 'zwei'), ('3', '33333', '27', 'drei'), ('4', '33333', '1', 'auchdrei');
Nur 22222 sollte gelöscht werden da 11111 erst age 1 ist und 33333 ein mal age < 24
SELECT * FROM plz WHERE plz=ALL(SELECT plz FROM msgs WHERE age>24 AND NOT plz=ANY(SELECT plz FROM msgs WHERE age<24));
Wie Delete dann funktioniert wird wohl raus zu finden sein
Beitrag zuletzt geändert: 15.7.2019 20:01:13 von horstexplorer -
Genau so hatte ich mir das vorgestellt, vielen Dank! Ich kannte die Befehle "any" und "all" nicht.
-
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage