"We are back" « oc.at

MySQL - Tabelle optimieren

AngelOfDeath 07.05.2004 - 09:54 1171 8
Posts

AoD

aka AngelOfDeath
Avatar
Registered: Nov 2002
Location: St. Pölten
Posts: 1482
Hi,

Folgende Tabelle:
Code:
CREATE TABLE `mautdaten` (
  `Datum` date NOT NULL default '0000-00-00',
  `Zeit` time NOT NULL default '00:00:00',
  `Referenznummer` bigint(12) unsigned zerofill NOT NULL default '000000000000',
  `MautabschnittsID` smallint(4) unsigned zerofill NOT NULL default '0000',
  `Strassenkennzahl` char(5) NOT NULL default '',
  `Mautabschnittsbezeichnung` char(60) NOT NULL default '',
  `KfzKennzeichen` char(12) NOT NULL default '',
  `Nationalitaet` char(2) NOT NULL default '',
  `GoBoxNummer` char(18) NOT NULL default '',
  `KfzKennungFraechter` char(20) NOT NULL default '',
  `KostenstelleFraechter` char(20) NOT NULL default '',
  `Vertragsart` char(4) NOT NULL default '',
  `Kategorie` tinyint(2) unsigned zerofill NOT NULL default '00',
  `Hinweis` char(4) NOT NULL default '',
  `Zahlungsmittel` bigint(20) unsigned zerofill NOT NULL default '00000000000000000000',
  `Netto` int(7) unsigned zerofill NOT NULL default '0000000',
  `USt` int(7) unsigned zerofill NOT NULL default '0000000',
  `Brutto` int(7) unsigned zerofill NOT NULL default '0000000',
  KEY `Datum` (`Datum`),
  KEY `Zeit` (`Zeit`),
  KEY `GoBoxNummer` (`GoBoxNummer`),
  KEY `Netto` (`Netto`),
  FULLTEXT KEY `KfzKennzeichen` (`KfzKennzeichen`)
) TYPE=MyISAM ROW_FORMAT=FIXED

Wie leicht zu erkennen ist, handelt es sich um die Tabelle für Go-Maut Datensätze. Zur Tabelle kommen pro Monat ~20MB an Daten hinzu, sprich jetzt im Mai nach 4 Monaten ~75MB Daten und 15 MB Index.
Da die Spalten Datum, Zeit, GoBoxNummer, Netto und KfzKennzeichen oft in WHERE Klauseln benötigt werden, hab ich diese zum Index hinzugefügt (Ausnahme Spalte Netto, welche nicht in WHERE Klauseln vorkommt, aber ich erhoffte mir durch einen Index eine schnellere Summierung der Werte).


Abfrage #1:
Code:
EXPLAIN
SELECT MAX(datum) AS LetztesDatum,KfzKennzeichen
FROM mautdaten
GROUP BY KfzKennzeichen
ORDER BY NULL;
Ergebnis:
Code:
Using temporary
Hier wird kein Index verwendet :(


Abfrage #2:
Code:
EXPLAIN
SELECT LPAD(SUM(netto),7,'0') AS Netto,KfzKennzeichen
FROM mautdaten
WHERE datum>='DATUMVON' AND datum<='DATUMBIS'
GROUP BY KfzKennzeichen
ORDER BY NULL;
Ergebnis:
Code:
Using where; Using temporary
Hier wird Datum als Index verwendet

Bevor ich ORDER BY NULL hatte, wurde mir beim explain auch noch zusätzlich using filesort angezeigt. Laut MySQL Handbuch sollte man dies vermeiden, allerdings konnte ich keine Auswirkung (positive und negative) feststellen.

Mein Fragen:
Was kann ich noch beschleunigen? Warum wird bei der ersten Abfrage kein Index/keine Indizes verwendet?
Bedacht werden sollte auch, dass die Tabelle nach einem Jahr ~250 MB haben wird. (Anfang 2005 werd ich die Tabelle mit den Daten von 2004 umbennen und eine neu Tabelle mit den 2005er Daten machen)

Danke für jeden Hinweis ;)

Rektal

Here to stay
Registered: Dec 2002
Location: Inside
Posts: 4477
Die besten Hints habe ich immer noch bekommen wenn ichs direkt an die MySQL-Listen geschickt habe, hat sich immer ausgezahlt. Man bekommt auch recht schnell Antwort. HTH ;-)

mat

Administrator
Legends never die
Avatar
Registered: Aug 2003
Location: nö
Posts: 25539
temptables werden auch bei "group by" verwendet.
damit alles schön schnell geht sollte man
*) tmp_table_size sollte groß genug sein
*) der temptable sollte entweder auf einem memdrive oder auf mehreren physischen datenträgern sein

wenn er bei sorts einen temptable erstellt dann sort_buffer und read_rnd_buffer_size erhöhen.

wenn möglich, dann nichts aus dem table löschen, sonst wird der table "fragmentierter" und damit auch langsamer, bis OPTIMIZE TABLE ausgeführt wird.

allgemein zu datenspeicherung von so einem großem table:
wenn möglich dann teilen.. weil ein 4 gig table ist unbearbeitbar und damit meine ich auch von der wartung her. ich denke ich würde einen table machen der die großen datentable pro jahr oder vl besser pro fixer größe enthält und jegliche queries verwaltet. der overhead/query wäre imo ziemlich gering und du müsstest die tabletrennung niemals händisch durchführen. is nur so eine idee :)

AoD

aka AngelOfDeath
Avatar
Registered: Nov 2002
Location: St. Pölten
Posts: 1482
1. wegen tmp_table_size:
Code:
If an in-memory temporary table exceeds this size,
MySQL automaticallys convert it to an on-disk MyISAM table.
Increase the value of tmp_table_size
if you do many advanced GROUP BY queries and you have lots of memory.
Für mein Beispiel, wie groß sollte da tmp_table_size sein?
Da die Abfragen meistens nur auf 2-5 Spalten gehen sollte ja 70MB passen, oder?

2. Aus der tabelle wird NIE etwas gelöscht werden, da werden NUR inserts und selects gemacht.
Inserts mach ich mit "INSERT DELAYED IGNORE INTO mautdaten VALUES" in 500er Blöcken.

3. deine idee hab ich jetzt nicht verstanden :D
Ich würds zur zeit so machen:
Jänner 2005:
Code:
RENAME TABLE mautdaten TO mautdaten_04;
CREATE NEW TABLE mautdaten .........

mat

Administrator
Legends never die
Avatar
Registered: Aug 2003
Location: nö
Posts: 25539
ich nehm mal an du musst nicht nur daten aufnehmen sondern auch queries durch diese daten machen um gewissen informationen, statistiken, usw. herausholen zu können. ein allgemeines abstrahiertes system könnte dir viel arbeit ersparen = eine klasse die einen table mit allen bisher gesamelten tables und deren daten beinhält und queries, egal ob insert, select oder wwi handhabt.

also:

tblDataManager
beinhält tablename und vl auch noch andere wichtige und schnell ereichbare daten. zB daten eingetragen von datum bis datum (= 2 datelines) usw.

dieser table verwaltet also die anderen tables die deine mautdaten beinhalten. das ganze eingepackt in eine schöne klassen die funktionen wie query() usw. hat und entscheidet welche tables von den queries betroffen sind blabla.

ein beispiel:
tblDataManager
1. Datensatz: 'tbl2003', datelinevon (unix timestamp), datelinebis, ..
2. Datensatz: 'tbl2004', usw.

die tables werden natürlich von der klasse DataManager bei bedarf selber erstellt, nach bestimmten regeln.. zB größe des aktuellen tables größer als 500 mb oder anzahl der datensätze größer als 50.000 oder so ähnlich.

ich hoffe ich hab mich jetzt verständlicher ausgedrückt. das system wäre einfach nur g0il, kann aber natürlich sein dass es für deine Aufgabe/Zeitrahmen nicht geeignet ist.

Ringding

Pilot
Avatar
Registered: Jan 2002
Location: Perchtoldsdorf/W..
Posts: 4300
Wenn du nach kfzKennzeichen gruppierst, muss das am Anfang (oder als einzige Spalte) in einem Index stehen.

Leider ist MySQL manchmal sehr unwillig, einen Index zu verwenden. Ich hab auch schon öfters Fälle gehabt, wo es sich einfach beim besten Willen nicht dazu überreden lässt. Aber dein Beispiel ist so simpel, da sollt's eigentlich ohne Probleme gehen.

manalishi

tl;dr
Avatar
Registered: Feb 2001
Location: Feldkirch
Posts: 5977
ich muss mich phex bedingungslos anschließen. es stellt sich jedoch die frage, ob du nicht wegen performancegründen auf eine gewisse redundanz zurückgreifen solltest.
beispiel: du nimmst zusätzlich zur spalte "komplettes-kennzeichen" noch eine mit dem bezirk. fixe länge+index verstehen sich von selbst imho.
das würde eben viel sinn machen wenn du sonst oft eine substring-funktion o.ä. brauchst

Ringding

Pilot
Avatar
Registered: Jan 2002
Location: Perchtoldsdorf/W..
Posts: 4300
Der phex hat ja gar nix gepostet ...

mat

Administrator
Legends never die
Avatar
Registered: Aug 2003
Location: nö
Posts: 25539
er meint matphex! :cool:
Kontakt | Unser Forum | Über overclockers.at | Impressum | Datenschutz