Kann ich so nicht bestätigen, ging recht problemlos, soweit ich mich erinnere…
Das zweite Problem ist dass es scheinbar nicht möglich ist die zweite DB-Version parallel zu installieren. Ich wollte eigentlich die neue Datenbank dann gleichzeitig aufbauen wärend ich mit der alten weiter arbeite. Die müssten nicht gleichzeitig laufen.
doch, das geht. Mit untersch. Data-Verzeichnissen und unterschiedlichen Ports. Das ist auch das, was Debian beim Upgrade macht: es installiert die neue DB in einem anderen Verzeichnis und auf einem anderen Port und dann laufen beide. Man kann das auf N Versionen ausdehnen, kein Problem.
Nach einigen experimeten habe ich das mit PostgreSql 8.1 zum laufen gebracht und meine Datenbestände konvertiert. Beide Datenbankversion habe ich nicht gleichzeitig zum laufen gebracht macht aber auch nix. Die neue Version ist schon deutlich schneller aber auch nicht schnell genug. Es bleibt keine Luft für die Anfragen die vom Online-Shop kommen. Der DB-Server ist voll auf mit dem aktualisieren des Datenbestandes beschäftigt. Zum Jahresanfang kommen immer viele Produkte auf den Markt und andere werden eingestellt. Das hat in vier Wochen ca 1,6 Mio. neue Producte ergeben. Das einfügen ist kein Problem zusammengerechnet mit Parsen der XML-Daten ist das in ca 4Tagen erledigt. Beim entsorgen der alten Datensatzversionen schaft er ca. 1.400 Producte pro Stunde das sind im gleichen Zeitraum ca 950.000 Product Löschungen und 1,6 Mio. neuanlagen. Wesentlich günstiger als mit der alten Version aber immer noch zu langsam. Man muß aber dazu erwähnen dass mein schnelles Raidsystem wegen Hardwaredefekt ausgefallen ist und deshalb momentan alles auf einer einzelnen Platte läuft. Wenn das Raidsystem wieder Online ist sollte sich das Verhältnis noch mal deutlich verbessern.
Ich habe noch einige Zeit über das Problem der Parallelisierung nachgedacht. Ein großes Probelem sind ja die Platten zugriffe weil Arsch langsam im vergleich zum Arbeitsspeicher. In der Aktuellen c’t ist ein Artikel über die Parallelisierung von Dateizugriffen. Es gibt da einige neue Filesysteme die so was können (z.B. IBMs General Parallel File System (GPFS) oder das freie Parallel Virtual File System (PVFS)).
Ich habe ein bischen in der PostgreSql Doku gelesen bin mir aber wegen meiner bescheidenen Englischkenntnisse nicht ganz sicher ob ich richtig gelesen habe. Ist es möglich auf einem Datenbankcluster (das Teil das man mit initdb anlegt) mehrere postmaster Prozesse zugreifen zu lassen oder mach die sich dann gegenseitig Daten kaputt?
Wenn das ginge könnte man mit z.B. PVFS die Dateizugriffe parallelisieren und die Verarbeitung der Product-Updates bzw. die Zugriffe vom Online-Shop über verschiedene Server abarbeiten lassen. Wäre eine geniale Lösung bin mir eben nur nicht sicher ob das mit den mehrfachen postmastern geht.
Vielleicht weiß ja da jemand mehr dazu?
Gruß
Alexander
P.S. So gehts nicht, ein netter Zeitgenosse hat mir ein Übersetzung des fraglichen Dokuteils per Mail zugesandt. Eigentlich unverständlich warum es die Postgres-Entwickler nicht vorgesehen haben. Da die Datenbank zum schreiben von Daten ja so die Sätze sperrt wäre es auch kein Problem mit mehreren Prozessen zu arbeiten und eine möglichkeit zur Parallelisierung würde man praktisch geschenkt dazu bekommen. Da diese möglichkeit einen gewissen Einfluß auf die schnelligkeit hätte könnte man ja über eine konfig Option wählen ob mans braucht oder nicht.
Etwas spät aber doch:
Wenn du mit vielen inserts arbeites deaktivierde das Auto-Commit und und fahre einen Commit-Frequenz von ca. 1000 das hilft extrem. Nur inserts kannst du auch beschleunigen indem du vorher die indizes dropst und nachher wieder anlegst.
Ansonsten hilfts dir nur mehrere platten zu verwenden (such mal am ein bischen am Dachboden ) und die Tablespaces aufzuteilen. Oder kauf ein Satz Solid State disks, die kosten doch heute e nicht mehr die Welt (Geizhals-Preisvergleich :: Österreich) - auf jeden Fall weniger als ein neuer Server.
Chris
PS Ich habe 3mio sätze am Tag und arbeite mit einem P4 und es geht auch.
PPS Nur so eine Idee, schon mal versucht ein Software Raid0 zu machen wobei die eine “Platte” eine RAM-Disk ist?
Ach und noch zu deiner Frage wegen anderen Datenbanken. Sybase soll sowas können, die haben aber leider im Gegensatz zu Oracle keine Gratis Developer Version. Ansonsten kommt es darauf an wie deine Daten aufgebaut sind. Wenn du mit einer Oo sprache arbeitest ist eine Objekt Datenbak für dich vielleicht passender. Die sprache heisst dann nicht mehr SQL sondern OQL. Die Cache (InterSystems.de - InterSystems ) hat eine freie Developer Lizenz.
mein Hauptproblem sind nicht die inserts sondern das Löschen alter Produktversionen bzw. eine Suchfunktion mit der ich nach bestimmten Produkten suchen kann (Antwortzeiten verdienen derzeit nicht den Namen). Ein Produkt (Bücher, CDs, oder DVDs) verteilt seine gesamten Daten über ca. 35 Tabellen. Die Tabellen sind per RI verknüpft und abhängige Datensätze werden auch per RI gelöscht. Die abhängen Tabellen haben alle einen Index der auch zum löschen benutzt wird dieser ist aber nicht eindeutig da es in den untergeordneten Tabellen pro Produkt mehrer Datensätze geben kann. Ob das zusätzliche anlegen eines eindeutigen Indexes in jeder Tabelle der Datenbank helfen würde weiss ich nicht, glaube es aber nicht, da ein scan des nicht eindeutigen indexes ja nicht zu umgehen ist.
Der Gesamtbestand umfast zur Zeit ca. 5 Mio. Produkte. Die hälfte sind alte Versionen die gelöscht werden könnten wo ich aber mit dem Löschen nicht hinterher komme. Derzeit brauche ich für das Löschen von 10.000 Produkten ca. 30 Stunden. Im moment setze ich für jedes Produkt einen delete ab. Ich wollte jetzt mal Versuchen ob das löschen von mehreren Produkten in einem delete schneller geht. Dann könnte die Datenbank wenn sie schlau ist mit einem index scan die relevanten Datensätze für mehrere Produkte finden. Also wenn ich den delete so aufbaue:
delete from product where myproductnr = ‘1’ or myproductnr = ‘2’… usw.
und z.B. 20 Produkte gleichzeitig lösche die DB nur einen index scan macht würde das nur noch ein 20igstel der Zeit brauchen. Soweit zumindest meine Theorie. Ob hier Theorie und Praxis das gleiche Ergebnis liefern ist mir unbekannt. Ich denke aber einen Versuch ist es Wert.
Noch was zum Thema inserts: Diese werden aus XML-Daten generiert. Das Parsen der XML-Dateien macht jetzt ein zweiter Rechner und sendet dann per Netzwerk die SQL-Inserts zur Datenbank. Diese Inserts werden in einer Transaktion ausgeführt und erst commitet wenn eine XML-Datei mit ca.13MB Daten = mehrere tausend Produkte fertig verarbeitet wurde. Auf diese Art schaffe ich 1 Mio. Produkte in relativ kurzer Zeit aber länger als ein Tag. Bitte aber nicht vergessen dass die Datenbank inserts, deletes und selects zum suchen nach Produkten tagsüber parallel ausführen muß.
Das mit dem Software-Raid0 habe ich schon mal Versucht aber ohne RAM-Disk sondern nur mit Platten.
Was ist eigentlich der Vorteil der Solid State Disks mir sagt die Bezeichnung gerade nichts?
Nachdem ich jetzt in die Realisierung mit Postgress viel arbeit investiert habe will ich eigentlich nicht mehr die Datenbank wechseln. Was ich aber noch versuchen werde ist mit pvfs die Filesystemzugriffe auf mehrere Rechner zu verteilen und damit zu parallelisieren ich denke das bringt mir mehr als die DB zu wechseln.
Danke für Deine Tipps und Hilfe die kann ich zur Zeit immer noch gut brauchen zu dem Thema.
Viele Grüße aus einem regnerischen Bad Aibling
Alexander
Also beim Löschen ist es so, dass dir ein Index nur begrenzt hilft weil dieser ja nachgeführt werden muss. Das heisst immer wenn du löscht müssen auch alle Indizes aller betroffenen Tabellen upgedatet werden und das kostet viel Zeit. Wir hatten in der Firma mal ein ähnliches Problem mit dem Data Ware House und haben es wie folgt gelöst. Zunächst haben wir eine Stored-Procedure angelegt die folgendes macht:
1.) Von der Mutter Tabelle alle Primary Keys der zu löschenden Einträge in einen Cursor lesen.
2.) Alle Indizes bis auf die Primary Keys (dadurch sind auch die Foreign Keys abgesichert) droppen
3.) Ein Delete Cascade auf jeden Satz im Cursur in einer Transaktion durchführen (wir haben je nach Speicherbedarf alle paar Tausend commitet)
4.) Die Indizes neu anlegen
Wenn du das mit dem Filesystem hinbringst wäre ich sehr gespannt wie das geht, vielleicht kannst du das dann mal dazu posten.
Solid State Disks sind früher mar Laufwerke gewesen in denen eine Batterie und ein paar RAM-Keks drin steckten. Das war natürlich nicht nur sau schnell sondern auch sau teuer. Heute nimmt man dazu Flash speicher Medien und einen grosen Cache. Hybride haben dann noch eine “echte” Festplatte und es werden dann die Daten aus dem schnellen Cache/Flash “bei Gelegenheit” auf die Magnet scheibe geschrieben. Je nach Qualität habe ich mit sochen Dingern im Raid0 schon Windoof in 6 sec. booten sehen, das bringt dir auf FileAccess Basis auf jeden Fall eine Menge. Auch Mainframes punkten durch ihren hohen I/O Durchsatz mehr als mit den MIPs (nur meine Meinung).
Auch viele Grüsse, aber aus dem verregneten Zürich
Chris
Chris: Ich habe das jetzt mit einem C++ Progrämmchen gemacht. Alle zu löschenden Produkte in einem Cursor und dann der reihe nach löschen. Primary-Keys gibts bei den Untergeordneten Tabellen nicht. Nur die Roottabelle hat einen bei den Untergeordneten Tabellen kann es pro MyProductNr mehrere Datensätze geben.
Wenn ich dann die Indizes Lösche muß ich doch auch die RI entfernen dann geht doch kein Delete Cascade mehr oder?
Ist eine “Stored-Procedure” von der Performence besser als ein C++ Programm ich kenne mich mit denen nämlich nicht aus und würde daher den Weg über C++ bevorzugen. Wenns aber nenneswerte Vorteile bringt müsste ich es halt lernen.
Das C++ Progrämmchen läuft halt ohne Unterbrechung neben allen anderen aktivitäten da es so nie hinterher kommt. Alle paar Wochen Starte ich es neu dann wird auch der Cursor neu aufgebaut.
Noch ein Nachtrag: Commits mache ich nach 500 gelöschten Produkten.
Ach nochwas: Mit den Mainframes hast Du sicher nicht unrecht. Deshalb hab ich ja nach pvfs gesucht.
ads: Im prinzip ja ich könnte Dir für kurze Zeit einen reinen lese User einrichten. Aber gerne nicht, das liegt an dem Datenüberlassungsvertrag den ich für die Daten habe. Was bräuchtest Du denn für Infos oder Ausgaben von SQLs die könnte ich ja machen und hier Posten oder eine Datei schreiben und zur Verfügung stellen.
Der Unterschied zwischen einer Stored Procedure und einem Zugriff per Programm ist, dass die SP direkt im Server abgearbeitet wird. Man spart sich also den Traffic, um die Daten zu übertragen (plus die Latenzzeiten dafür).
Aber ob du das nun mit einem C-Programm oder einem Perl-Script abarbeitest, sollte zeitlich gesehen keinen Unterschied mehr ausmachen.
und einen (oder mehrere kinder) table:
create table bar(
bar_id serial8,
foo_id int8,
content
primary key(bar_id),
foreign key(foo_id) references foo(foo_id) on delete cascade
);
durch den primary key in foo ist der foreign key in bar gesichert. ich habe es zwar nie versucht, aber ich glaube das backend lässt dich diesen index gar nicht droppen. aber wenn du indexe auf z.b. content hast, solltest du diese vorher droppen. eine plpgsql funktion hat den vorteil, dass du dir das ganze gedöns mit datenbankverbindung und etwaige translation z.b. odbc sparst. spruch von meinem meister: “was das backend machen kann, soll gefälligst das backend machen.”
ja genau RI = Referntielle Integrität ich weiss immer nicht wie mans schreibt deshalb die Abkürzung.
Die Tabellen wurden so aufgebaut nur halt insgesammt 45 nicht 35 hatte ich falsch im Kopf:
create table ProductKey -- Master-Tabelle od. Root-Tabelle
(
MyProductNr bigint,
OnixRecordReference text,
OnixMessageSender text,
ModTime timestamp DEFAULT CURRENT_TIMESTAMP,
primary key (MyProductNr)
);
create index KeyProductDelete on ProductKey (OnixRecordReference, OnixMessageSender);
create index KeyProductDelete1 on ProductKey (ModTime, OnixSentDate);
create table ProductTitle
(
MyProductNr bigint,
TitleText text,
ModTime timestamp DEFAULT CURRENT_TIMESTAMP
);
create index KeyProductTitle on ProductTitle (MyProductNr);
alter table ProductTitle add foreign key (MyProductNr) references ProductKey (MyProductNr) on delete cascade;
Also zum aufbauen des Cursors mit den zu löschenden Producten werden die Keys “KeyProductDelete” und “KeyProductDelete1” gebraucht. Nachdem dieser aufgebaut ist könnte ich dann diese zwei und den Key “KeyProductTitle” droppen und mit dem Löschen beginnen.
Kann das droppen der Keys innerhalb der Transaktion erfolgen in der ich den Cursor aufbaue oder muß das auserhalb erfolgen.
Nochmal Nachtrag: ODBC benutze ich nicht aber dein Meister hat im schon nicht unrecht ich habe das Programm bisher auf dem DB-Server laufen lassen also Kommunikation über Unix-Domain-Sockets sollte also nicht zu viel Verzögerung verursachen.
aus eigener Erfahrung würde ich dir empfehlen, ein Raid-System mit möglichst vielen Spindeln auszuprobieren. Die Geschwindigkeit des Controlers und der Platten ist dabei sekundär - wichtig ist, dass viele parallel laufen und sich die Last verteilt.
Ich weiss nicht wie gross deine DB ist und ob du ein Problem hast, deine Daten aus der Hand zu geben, ich könnte dir aber ggf. testweise für ein paar Tage ca. 40 GB auf meinem “Einfacharray” mit 8 alten Server-SCSI-HDDs (Ebay, Gesamtpreis rund 300 Euro) zur Verfügung stellen und dort einen Dump einspielen (wäre zu Testzwecken ja auch kein Problem, einen älteren Dump zu verwenden).
danke für das nette Angebot aber ich darf die Daten nicht aus der Hand geben. Da Produkte nicht so schnell wieder vom Markt verschwinden wäre selbst ein einige Monate alter Datenbestand noch gröstenteils aktuell. Nur neue Produkte würden halt fehlen.
Ich habe eine Zeitlang auch ein Software Raid 0 mit 3 Platten benutzt. Der geschwindigkeitsvorteil ist eindeutig. Allerdings sind mir die von IBM stammenden SCSI-Platten Ultrastar DDYS-T18350 die ich auch von E-Bay hatte am laufenden Band ausgefallen und bis zum erreichen einer akzeptablen Geschwindigkeit fehlte immer noch sehr viel. Ich weiss nicht ob Du gebrauchte oder neue Platten benutzt bei mir waren es gebrauchte, das nur noch als Anmerkung wegen der Ausfälle.
Da es nicht viel Aufwand ist werde ich mal das mit dem droppen der Keys probieren und hoffentlich macht sich das deutlich bemerkbar. Es wundert mich zwar dass die Pflege eines Index so lange dauern soll weil ja der Datensatz sowieso gesucht wird und dann ja nur durch ein Flag als gelöscht markiert wird. Ich nehme mal an ein Index wird genauso gepflegt wie eine Datentabelle. Aber da es sich ja um einige Millionen vorgänge handelt summieren sich natürlich auch kleine Einsparungen zu beträchtlichen Zeiten.
Ich kann über Ausfälle nicht wirklich was sagen - mein Array arbeitet erst seit ein paar Monaten, mit 18GB-Gebrauchtplatten. Ich habe nochmal 10 identische auf Vorrat gekauft, bisher ist aber nichts ausgefallen. Ich hab mich allerdings vorher bei den Experten unseres Rechenzentrums kundig gemacht, auf welche Plattentypen man verzichten sollte und wie das Array aufgebaut werden sollte. IBM stellt übrigens schon lange keine HDDs mehr selber her (die Fertigung war früher sogar in Deutschland - ich bin öfter mal in den alten Hallen in Mainz unterwegs), sondern kauft nur noch von verschiedenen Drittherstellern zu.
Der bisher einzige Ausfall ist ein Softwaredefekt am RAID 0-Array, verursacht durch einen Blitzschlag mit folgendem Stromausfall - der Raid-Controller arbeitet mit 64MB R/W-Cache, es ist also nicht weiter verwunderlich, wenn bei einem Stromausfall Daten und ggf. auch die Integrität des RAID-Array verloren gehen.
Ich habe kein SLA zu erfüllen und bin auch mit 97 Prozent Verfügbarkeit noch zufrieden, habe dafür aber auch kein Geld für vernünftige Hardware…
Ich weiss nicht, wie zentralisiert deine Datenstruktur aussieht bzw. in wievielen Spalten man Daten oder Produktnamen z.B. durch einen MD5-Hash maskieren könnte - ggf. wäre sowas eine Option für dich.
An die möglichkeit die Daten zu maskieren hatte ich auch schon gedacht. Nur bei der Masse > 5Mio. Produkte. Da mir meine Rechenleistung so schon nicht reicht wir das schwierig. Die Datenbank ist im Moment ca. 26 GB groß.
Wenn Dich die Datenbankstruktur interessiert könnte ich Dir das SQL-File für die Erzeugung zusenden.
Im Prinzip könntest Du für Versuche auch ein kleines script nehmen das zufällige Daten genneriert. Denn ein Download von 26GB ist auch nicht unbedingt schnell.
wenn nur ein feld maskiert werden muss, wäre ein dl in der tat kein problem. - du müsstest halt bei dir die table kopieren und das entsprechende feld maskieren und dann alles bis auf die “geheime” table dumpen.
ich hänge an einer 72MBit-Leitung - mit grösseren downloads hab ich kein problem (aber du vielleicht). Da ich nicht weiss, wie die daten verknüpft sind, müsstest du ggf das problem des maskierens sinnoll lösen, wenn dir der versuch den aufwand wert ist.
im moment habe ich gut über 90 gb auf dem array frei - so schnell wird das auch nicht weniger.
Ich habe jetzt noch etwas gerechnet, du sprichst am Anfang von 100.000 Updates die Woche. Das heisst, du hast ca. alle 10 Sekunden ein Update, sehe ich das richtig? Kannst du ermitteln, wie lange (in Sekunden) so ein Update dauert?
Und eine andere Frage: wieviele Suchanfragen gehen da effektiv auf die Datenbank ein … und wie lange dauern diese im Schnitt?
Die Produkt-Updates sind für die Datenbank inserts und die gehen sehr schnell. Eine genaue Zeit kann ich Dir dazu aber nicht sagen. 100.000 neue Produkte einfügen geht in etwa zwei Tagen.
Im moment gehen da abgesehen von den Produkt-Updates und dem Prozess der 24/7 die alten Daten löscht nur noch die Anfragen von mir ein und manchmal läuft ein Programm das für ein paar hundert Produkte bestimmte Daten selektiert und in eine Textdatei schreibt um diese in einer anderen Datenbank zu verwenden. Das soll und darf aber nicht so bleiben. Wenn ich eine Anfrage an die Datenbank mache kommte es auf die gesuchten informationen an. Eine Suche nach einer Artikel-Nr. ist in psql ein select auf eine Tabelle und der dauert um eine Sekunde. Eine Suche nach dem Namen des Autors oder Herstellers dauer um die 80-150 Sekunden und eine Abfrage nach einem Stichwort in der Produktbeschreibung dauert mehrere 100 Sekunden.
Die Zeiten sind für einen Select auf die jeweilige Tabelle mit der psql Timing Funktion gemessen. In einer realen Anwendung bleibt es halt nicht bei einem select da ich hier z.B. für die Anzeige eines Produkts Daten aus 5-10 Tabellen suchen muß. Abgesehen davon auch noch mehrer Kunden gleichzeitig suchen werden.
Hier auch mal die neuesten Messdaten zum löschen der alten Produkt-Versionen. Wie ich weiter oben in diesem Thread schon mal geschrieben habe ist das zerlegen der XML-Daten und die Generierung der Inserts jetzt auf einem zweiten Rechner. Wenn die Datenbank sonst nichts zu tun hat werden in knapp einer Stunde 1000 alt Verionen gelöscht. Das ist schon wesentlich besser aber leider immer noch viel zu langsam. Bei nachrechnen kommt man zwar auf nur 6 Sekunden pro Datensatz aber wie bereits geschrieben geht das nur wenn der Datenbankserver sonst nichts macht.
Das heisst immer noch, das ein Insert rund 2.5 Sekunden braucht. Wo verliert die Datenbank denn dort Zeit? Das sollte eigentlich schneller gehen und nutzt du eigentlich prepared Queries?
Wenn ich eine Anfrage an die Datenbank mache kommte es auf die gesuchten informationen an. Eine Suche nach einer Artikel-Nr. ist in psql ein select auf eine Tabelle und der dauert um eine Sekunde.
Kannst du uns dafür eine EXPLAIN ANALYZE Ausgabe zeigen?
Eine Suche nach dem Namen des Autors oder Herstellers dauer um die 80-150 Sekunden und eine Abfrage nach einem Stichwort in der Produktbeschreibung dauert mehrere 100 Sekunden.
Gut, das dürfte sicherlich daran liegen, das du mit ILIKE suchst und %% vorne und hinten stehen hast, oder? Dabei sind dann keinerlei Optimierungen möglich. Kennst du eigentlich tsearch2?
Wenn die Datenbank sonst nichts zu tun hat werden in knapp einer Stunde 1000 alt Verionen gelöscht. Das ist schon wesentlich besser aber leider immer noch viel zu langsam.
3-4 Sekunden pro Datensatz …
Hast du dafür mal auch ein EXPLAIN ANALYZE?
Nicht ganz die 100.000 Produkt-Updates besteht aus 45 Tabellen also ca 100.000 * 45 = 4.500.000 Inserts. 48 Stunden durch 4,5 Mio. ist deutlich unter 2.5 Sekunden.
Das mit dem like ‘%…%’ ist richtig. t_search2 kenne ich dem Namen nach benutze es aber nicht.
3-4 Sekunden pro Produkt nicht pro Datensatz. Auch hier etwa 45. Es sind nicht immer alle vorhanden dafür können aber andere auch mehr haben.
Die Explains mach ich mal heute Abend und kopiere sie dann hier rein.