MySQL Performance auf großen Tabellen

MySQL, PostgreSQL, SQLite
moppi
Posts: 368
Joined: 2003-02-15 11:16

MySQL Performance auf großen Tabellen

Post by moppi » 2005-03-26 11:36

Hallo,

seit ein paar Tagen habe ich ein Problem mit meinem MySQL Server. DAS System ist ein Art Portal Apache und Datenbank sind 2 voneinander getrennte Systeme. MySQL wurde aus Performancegründen statisch compiliert und enthält nur den latin1 Zeichensatz. Des weiteren ist kein SSL support eingebaut kein INNO und BERKDB Support.

In Spitzenzeiten werden 500-1000 Querys an das Gerät gesendet, es handelt sich um einen Dual Xeon Pentium4 mit 3Ghz.

Solange es sich bei den Abfragen um reine SELECT's handelt ist das auch kein Problem, jedoch gibt es in diesem System ein Nachrichtensystem und dies ist "noch" in einer Tabelle. Dort werden ENUM Felder gesetzt die nach dem Primärschlüssel aufgesucht werden. Teilweise brauchen diese UPDATES recht lange, dazu kommt das in dieser Zeit die Tabelle gesperrt ist und andere UPDATE's warten müssen. Dadurch werden neue Threads kreiirt und das Gerät ist sehr schnell voll ausgelastet und geht komplett in die Knie.
Darauf folgt dann das der Client die Message erhält das keine Prozesse mehr erstellt werden können weil der RAM nicht ausreicht. Ich habe auf dem Gerät auf SWAP verzichtet und der Kernel enthält auch nicht diese Verwaltung dafür, da dies System 2 GB hat an RAM und alles wirklich sehr minal installiert ist es laufen keine anderen Dienste darauf ausser SSH und MySQL.

Ich habe natürlich das MySQL Handbuch mehrere Tage gewälzt und habe etliche Parameter wie ThreadCache und SortBuffer angepasst. Querycache integriert usw. Das tut zwar einiges nur hilft es nicht das Problem zu lösen. Wie kann ich dennoch die Performance von diesen großen Tabellen verbessern?

Vielen Dank für jegliche Inspiration
Daniel

outofbound
Posts: 470
Joined: 2002-05-14 13:02
Location: Karlsruhe City

Re: MySQL Performance auf großen Tabellen

Post by outofbound » 2005-03-27 13:36

Queryanalyse machen und diese optimieren.
Geg.falls die DB- Struktur überdenken.

Was für updates werden denn da gefahren? Wie
viele Indices liegen auf den Tabellen?

Theoretisch könnte dir noch row- level- locking helfen,
aber mit mysql siehts schlecht aus.

Gruss,

Out

moppi
Posts: 368
Joined: 2003-02-15 11:16

Re: MySQL Performance auf großen Tabellen

Post by moppi » 2005-03-27 15:52

Hallo,

es existiert ein Primärschlüssel als Autoincrement INT Feld wonach ENUM Felder umgelegt werden.
Der Index ist ca 700MB groß. Diese Tabelle enthält auch noch BLOB Felder die z.T. 1Kb und mehr haben. Würde es nicht Sinn machen die Tabelle zu splitten? Ich frage deshalb da kein MySQL Slave verfügbar ist um das eben mal zu testen, d.h. das System steht schon unter permanenter Arbeit. Und ich bin leider auch kein Datenbankexperte. :)

Vielen Dank
Daniel

golloza
Posts: 23
Joined: 2005-01-03 17:27

Re: MySQL Performance auf großen Tabellen

Post by golloza » 2005-03-27 17:49

InnoDB wäre einen Versuch wert, das kann zeilenweise locken, dafür wohl allgemein langsamer.

moppi
Posts: 368
Joined: 2003-02-15 11:16

Re: MySQL Performance auf großen Tabellen

Post by moppi » 2005-03-27 17:54

Die Frage die sich mir stellt das ich keinen Sinn sehen darin Spalten zu sperren.
Wäre es nicht sinnvoller die Tabellen mir Primarschlüssel und dem Enum Feld was öfter bearbeitet wird extern auszulegen?
Zumindest diese Daten die Permanent verändert werden aus der Tabelle mit den VARCHAR und BLOB Feldern zu trennen müsste doch Sinn machen?

outofbound
Posts: 470
Joined: 2002-05-14 13:02
Location: Karlsruhe City

Re: MySQL Performance auf großen Tabellen

Post by outofbound » 2005-03-27 22:37

Vorsicht, Spalten und ZeilenLocks nicht verwechseln!!!!!!

Moppi, das Primärproblem ist erstmal rauszufinden wo der Engpass liegt.
Sollte es die IO sein (Oft bei Datenbanken), dann hilft dir wahrscheinlich nur ein Umstieg auf ein anderes RDBS, z.B. PostgreSQL, welches Tablespaces unterstützt. Damit könntest du die IO verteilen.

Datenbankoptimierungen sind ein ziemlich komplexes Thema, ich würde mal schätzen dass man 90 % der Lastprobleme über Queryoptimizing beseitigen kann, 5 % über "mehr RAM" und die restlichen 5 % über "Tweaken" von Serversoft- und -hardware. Ohne deinen Tabellenaufbau und die jeweiligen Querys kann man dazu jedoch nur sehr ungenau Aussagen treffen, da man hier individuell unterscheiden muss.

Es könnte z.B. sein dass ein ändern von ENUM auf (Native) INT einiges an Performance raushaut, weil intern eine Konvertierung stattfindet. Ein anderer Fall könnten die Indices sein, dann kann es wiederum sein dass einfach die Cachingstrategie fehlschlägt weil du sequentielle Scans drin hast und und und und und....

Somit gilt: Beispiele liefern. ;)

Gruss,

Out

outofbound
Posts: 470
Joined: 2002-05-14 13:02
Location: Karlsruhe City

Re: MySQL Performance auf großen Tabellen

Post by outofbound » 2005-03-27 22:42

Nachtrag: Das aufspalten der Tabellen dürfgte eigentlich nix bringen, weil nur wirklich benötigte Daten von der Platte gekratzt werden. Was nicht in der Ergebnismenge benötigt wird sortiert der Optimizer normalerweise raus.

Evtl. bringt es auch auf einer Tabelle mit vielen Updates etwas, die Indices erst vor den SELECTs anlegen zu lassen und danach wieder zu droppen, damit die nicht bei jedem Update wieder angelegt werden müssen.
Bei so grossen Daten hast du evtl. auch Cachingprobleme, d.h, du müsstest dich in das verhalten der MySQL einlesen, ich weiss jedoch nicht, ob Mysql sowas wie (mru) und (lru) kennt.

Die Querys mal mit "EXPLAIN" anzuschauen und den Output zu analysieren wäre auch ein Ansatz.

Das ist aber alles mehr oder weniger Schwarze Magie und Intuition, ohne
das genau Datenbankbild kann man da wenig machen.

Ich hoffe ich hab dir ein bisserl geholfen,

Gruss,

Out

PS: Wo issn die Edit- Funktion geblieben???

moppi
Posts: 368
Joined: 2003-02-15 11:16

Re: MySQL Performance auf großen Tabellen

Post by moppi » 2005-03-27 22:53

Ich vermutete das wenn die Tabelle gesplittet ist der overhead entfällt die entsprechenden daten aufzufinden bzw zu suchen denn er muss eben immer über diese varchar und blob felder springen.

Indizes vor den Selects? Das ist mir völlig unklar. Und Indizes anlegen zur Laufzeit ist schlecht da geht das System komplett in die Knie, veränderungen an der Struktur bzw Indizes während des Betriebes sind unmöglich.

Zum Thema Caching so viel, dieser Kasten hat 2GB Ram wovon ich 512 MB das ist ein drittel der gesamt Daten der Indizes im RAM vorhalte. Lt. MySQL optimal. Dazu kommen 256MB Query Cache dazu 32 MB Sortbuffer und 32 MB für Temporäre Tabellen. Die Abfragen die Temporäre Tabellen erstellen beziehen sich nicht auf Blob oder Textfelder. Würde es einen Unterschied machen TEXT statt BLOB Felder zu verwenden?

Mit EXPLAIN habe ich schon geschaut soweit aber ich habe bisher noch nciht die Erleuchtung gehabt.

Vielen Dank[/quote]

outofbound
Posts: 470
Joined: 2002-05-14 13:02
Location: Karlsruhe City

Re: MySQL Performance auf großen Tabellen

Post by outofbound » 2005-03-27 23:22

Moppi wrote:Ich vermutete das wenn die Tabelle gesplittet ist der overhead entfällt die entsprechenden daten aufzufinden bzw zu suchen denn er muss eben immer über diese varchar und blob felder springen.
Das kommt darauf an, wie du selektierst. Um das von dir beschriebene zu vermeiden wurde Indices ja geschaffen. ;)
Indizes vor den Selects? Das ist mir völlig unklar. Und Indizes anlegen zur Laufzeit ist schlecht da geht das System komplett in die Knie, veränderungen an der Struktur bzw Indizes während des Betriebes sind unmöglich.
Bei jedem INSERT oder UPDATE muss der Index neu gebaut werden. Je nach Verhältnis macht es Sinn den Index nur zur Laufzeit anzulegen, damit er bei vielein Inserts/Updates nicht neu gebaut wird. Dafür muss man halt erstmal Statistiken haben, wie oft selektiert / eingefügt wird.

Naja, wie gesagt: Ohne zu wissen was optimiert wird ist das optimieren schwierig. D.h. konkrete Daten müssen her.

Gruss,

Out

moppi
Posts: 368
Joined: 2003-02-15 11:16

Re: MySQL Performance auf großen Tabellen

Post by moppi » 2005-03-27 23:40

ist wirklich total einfach zu verstehen:

Code: Select all

CREATE TABLE `nachrichten` (
  `id` int(11) NOT NULL auto_increment,
  `von` varchar(20) NOT NULL default '',
  `an` varchar(20) NOT NULL default '',
  `sendezeit` varchar(16) NOT NULL default '',
  `gelesen` enum('j','n','a') NOT NULL default 'n',
  `del_von` enum('j','n') NOT NULL default 'n',
  `del_an` enum('j','n') NOT NULL default 'n',
  `text` text NOT NULL,
  `text_kurz` varchar(50) NOT NULL default '',
  PRIMARY KEY  (`id`),
  KEY `von` (`von`),
  KEY `an` (`an`),
  KEY `id` (`id`),
  KEY `del_von` (`del_von`),
  KEY `del_an` (`del_an`)
) TYPE=MyISAM PACK_KEYS=0; 
simpel zu verstehen oder?

outofbound
Posts: 470
Joined: 2002-05-14 13:02
Location: Karlsruhe City

Re: MySQL Performance auf großen Tabellen

Post by outofbound » 2005-03-28 00:16

Code: Select all

CREATE TABLE `nachrichten` (
  `id` int(11) NOT NULL auto_increment,
  `von` varchar(20) NOT NULL default '',
  `an` varchar(20) NOT NULL default '',
  `sendezeit` varchar(16) NOT NULL default '',
  `gelesen` enum('j','n','a') NOT NULL default 'n',
  `del_von` enum('j','n') NOT NULL default 'n',
  `del_an` enum('j','n') NOT NULL default 'n',
  `text` text NOT NULL,
  `text_kurz` varchar(50) NOT NULL default '',
  PRIMARY KEY  (`id`),
  KEY `von` (`von`),
  KEY `an` (`an`),
  KEY `id` (`id`),
  KEY `del_von` (`del_von`),
  KEY `del_an` (`del_an`)
) TYPE=MyISAM PACK_KEYS=0; 
Fangen wir mal an, ich hab leider nur kurz Zeit. ;)

Primary Key ist id... und ein Index liegt auf "id". D.h.
es gibt zwei indices auf "id". Damit wird dieser Indice jedes
mal doppelt berechnet.

Dann hast du Indices auf varchar() Felder. Was spricht
dagegen diese gegen "user_ids" auszutauschen? (Das wären
dann INTs) und die Referenz auf den "namen" in einer
extra Tabelle zu handlen?
Warum ist "sendezeit" kein Timestamp?
Und was spricht dagegen die "del_*" als INTs abzulegen?
Ich bin mir über die jeweiligen Performanceverbesserungen
nicht unbedigt im klaren, das müsste man testen, aber
da kann man sicher noch einiges an Performance alleine
durch Typänderungen rausholen. Ich schau mal ob ich morgen
noch etwas Zeit für dich habe. ;)

Besonders "gelesen, del_von, del_an" würde ich als INT abbilden,
was sicher einiges an internen Konvertierungen sparen würde.
Dann noch "von" und "an" als INT abbilden und einen join
bauen, dürfte performanter sein.

Und brauchst du wirklich Indices über die "del_*"? Normalerweise
müsstest du ja primär nach "von" und "an" selektieren, und danach
erst schauen ob gelöscht oder nicht...

Wie gesagt, morgen kann ich dir sicher noch einiges dazu erzählen,
aber ich hab schon 10 Bier intus ;)

Gruss,

Out

alexander newald
Posts: 1117
Joined: 2002-09-27 00:54
Location: Hannover

Re: MySQL Performance auf großen Tabellen

Post by alexander newald » 2005-03-28 09:46

Poste mal eine Beispielquery. Ich denke, das Problem ist, dass bei jedem Insert/Update alle Index neu aufgebaut werden müssen.

moppi
Posts: 368
Joined: 2003-02-15 11:16

Re: MySQL Performance auf großen Tabellen

Post by moppi » 2005-03-28 11:33

Danke erstmal für die Inspiration, ich muss zu meiner Verteidigung dazu sagen, das diese Tabelle nicht auf meinem "Mist" gewachsen ist. Nur ich bin kein MySQL Experte und weiss auch nur einiges. Ich werde in den nächsten Stunden mal ein paar Querys auffangen und dann hier posten.