Hallo, ich habe ein kleines Programm das ich in Java geschriben habe und eine MySQL (InnoDB Engine) benutzt. Der MYSQL Server läuft nur local auf meinem normalen PC.
Es ist so ein kleines Programm zum verwalten von Kunden Daten.
Naja, jedenfalls ist es so:
Hm, naja, vielelicht poste ich noch mal für die bessere Verständnis die CREATE Befehle:
Naja, das problem ist nun fogendes:
Ich dachte mir, es wäre am besten, wenn ich alle Daten in einer SELECT Anfrage erfassen könnte und diese dann in Java zu "richtigen" Kunden Objecte, Karte Objecte, Kind Objecte usw. "parse". Das "parsen" funktioniert auch ganz einwandfrei und schnell, also weniger als 1 sek.
NUR:
das Abfragen, also das ausführen der SELECT QUERY mit JOINS dauert aber so extrem lange!
Also ich habe Beispieldaten:
2000 Kunden (432 KB)
100 Geschäfte (16 KB)
9000 Karten (600 KB)
8700 Kinder (1,7 MB)
100 KartenStatus (16 KB)
100 KundenStatus (16 KB)
Mit meinem SELECT JOIN dauert die Abfrage ganze 18 Minuten! FAIL!
Meine Abfrage sieht so aus:
Naja, also es ist dann so, dass in meiner Ergebnis Zeilen sozusagen "doppelt" sind:
also die "einfachen" Kunden daten wie vorname, nachname usw. (kunde.*) werden mehrfach gelistet, jedoch immer mit unterschiedlichen Kinder bzw. Karten.
Naja, so wächst aber natürlich die Anzahl an Zeilen beträchtlich.
Also, wie könnte man das optimieren?
Also an SELECT SQL wird es sicher eine effizientere Lösung geben, aber um ehrlich zu sein ist mir bis jetzt keine eingefallen. Vielleicht kann man das irgendwie besser mit einer View lösen, aber die View hat ja dann auch nur im Prinzip den selben SELECT Befehl, also gleiche Performance.
Ich habe mir gedacht, ich könnte die Views youngestkind und oldestkind irgendwie zusammenlegen zu einer View, um sich einen JOIN zu sparen, aber macht das wirklich einen größeren unterschied?
Wie funktioniert das eigentlich genau mit INDEXE? Also ich habe ja nur PRIMARY KEYS, die ja aber auch INDEXE sind, soweit ich weis zumindest. Sind FOREIGN KEYS auch INDEXE? Wenn nein, würde es die Performance verbessern wenn ich die FOREIGN KEYS zu INDEXE mache?
Was gibt es sonst noch für Möglichkeiten?
Es wäre super, wenn mir jemand weiter helfen könnte
Es ist so ein kleines Programm zum verwalten von Kunden Daten.
Naja, jedenfalls ist es so:
- Tabelle kunde: PrimaryKey "kid" (AUTO_INCREMENT). Ein Kunde hat diverse attribute wie vorname, nachname, email usw.
- Tabelle geschaft: PrimaryKey "gid" (AUTO_INCREMENT). Es gibt mehrer Geschäfte. Ein Kunde wird einen Geschäft zugeordnet mit der Spalte geschagt_gid (Foreign Key) in der Tabelle kunde
- Tabelle kundenstatus: PrimaryKey "kusid" (AUTO_INCREMENT). jeder Kunde kann einen bestimmten Status haben, zum beispiel "gesperrt" usw. Dazu existiert eine Spalte (Foreign Key) kundenstatus_kusid in der Tabelle Kunde
- Tabelle kind: PrimaryKey "kiid" (AUTO_INCREMENT). Jeder Kunde kann mehrere Kinder haben. Von den Kindern interessiert vor allem das Geburtsdatum.
In dieser Tabelle kind existiert eine Spalte (Foreign Key) kunde_kid die auf die Tabelle kunde referenziert. - Tabelle karte: PrimaryKey "kartennummer". Jeder Kunde kann mehrere solcher kundenkarten haben. Dazu gibt es eine Spalte (Foreign Key) kund_kid in der Tabelle karte die wiederum auf die Tabelle kunde referenziert.
- Tabelle kartenstatus: PrimaryKey "kasid "(AUTO_INCREMENT). Jeder Karte hat einen bestimmten Status, z.B. "verloren", "gestohlen", "ok", usw. Dazu gibt es in der Tabelle karte eine Spalte (Foreign Key) kartenstatus_kasid die eben auf diese Tabelle kartenstatus referenziert
- View oldestkind: Eine View auf die Tabelle kind, die für jeden Kunden das älteste kind breitstellt.
- View youngestkind: Eine View auf die Tabelle kind, die für jeden Kunden das älteste jüngste Kind breitstellt.
Hm, naja, vielelicht poste ich noch mal für die bessere Verständnis die CREATE Befehle:
Code:
--
-- Tabellenstruktur für Tabelle `geschaft`
--
CREATE TABLE `geschaft` (
`gid` int(11) NOT NULL auto_increment,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`gid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
--
-- Tabellenstruktur für Tabelle `kundenstatus`
--
CREATE TABLE `kundenstatus` (
`kusid` int(11) NOT NULL auto_increment,
`name` varchar(200) NOT NULL,
PRIMARY KEY (`kusid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
--
-- Tabellenstruktur für Tabelle `kunde`
--
CREATE TABLE `kunde` (
`kid` int(11) NOT NULL auto_increment,
`anrede` varchar(20) default NULL,
`vorname` varchar(50) NOT NULL,
`nachname` varchar(50) NOT NULL,
`plz` varchar(6) default NULL,
`geschaft_gid` int(11) default NULL,
`seit` date default NULL,
`staat` varchar(30) default NULL,
`ort` varchar(100) default NULL,
`hausnummer` varchar(10) default NULL,
`strasse` varchar(50) default NULL,
`email` varchar(100) default NULL,
`handy` varchar(100) default NULL,
`kundenstatus_kusid` int(11) NOT NULL default '1',
`kommentar` varchar(250) NOT NULL,
PRIMARY KEY (`kid`),
FOREIGN KEY (geschaft_gid) REFERENCES geschaft(gid),
FOREIGN KEY (kundenstatus_kusid) REFERENCES kundenstatus(kusid)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4608 ;
-- --------------------------------------------------------
--
-- Tabellenstruktur für Tabelle `kartenstatus`
--
CREATE TABLE `kartenstatus` (
`kasid` int(11) NOT NULL auto_increment,
`name` varchar(200) NOT NULL,
PRIMARY KEY (`kasid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
--
-- Tabellenstruktur für Tabelle `karte`
--
CREATE TABLE `karte` (
`kartennummer` bigint(20) NOT NULL,
`kartenstatus_kasid` int(11),
`kunde_kid` int,
PRIMARY KEY (`kartennummer`),
FOREIGN KEY (kartenstatus_kasid) REFERENCES kartenstatus(kasid) ON DELETE SET NULL
FOREIGN KEY (kunde_kid) REFERENCES kunde(kid) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Tabellenstruktur für Tabelle `kind`
--
CREATE TABLE `kind` (
`kiid` int(11) NOT NULL auto_increment,
`vorname` varchar(30) default NULL,
`nachname` varchar(30) default NULL,
`geburtsdatum` date NULL,
`kunde_kid` int(11) NOT NULL,
PRIMARY KEY (`kiid`),
FOREIGN KEY (kunde_kid) REFERENCES kunde(kid) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6245 ;
--
-- Tabellenstruktur für Tabelle `oldestkind`
--
CREATE VIEW oldestkind AS select min(kind.geburtsdatum) AS `geburtsdatum`,`kind`.`kunde_kid` AS `kunde_kid` ,`kind`.`kiid` from `kind` group by `kind`.`kunde_kid` order by `kind`.`kunde_kid`;
-- --------------------------------------------------------
--
-- Tabellenstruktur für Tabelle `youngestkind`
--
CREATE VIEW `youngestkind` AS select max(`kind`.`geburtsdatum`) AS `geburtsdatum`, `kind`.`kunde_kid` AS `kunde_kid` ,`kind`.`kiid` from `kind` group by `kind`.`kunde_kid` order by `kind`.`kunde_kid`;
Naja, das problem ist nun fogendes:
Ich dachte mir, es wäre am besten, wenn ich alle Daten in einer SELECT Anfrage erfassen könnte und diese dann in Java zu "richtigen" Kunden Objecte, Karte Objecte, Kind Objecte usw. "parse". Das "parsen" funktioniert auch ganz einwandfrei und schnell, also weniger als 1 sek.
NUR:
das Abfragen, also das ausführen der SELECT QUERY mit JOINS dauert aber so extrem lange!
Also ich habe Beispieldaten:
2000 Kunden (432 KB)
100 Geschäfte (16 KB)
9000 Karten (600 KB)
8700 Kinder (1,7 MB)
100 KartenStatus (16 KB)
100 KundenStatus (16 KB)
Mit meinem SELECT JOIN dauert die Abfrage ganze 18 Minuten! FAIL!
Meine Abfrage sieht so aus:
Code:
SELECT kunde.*, kartennummer, kind.kiid, kind.vorname as kind_vorname, kind.nachname as kind_nachname, kind.geburtsdatum, kartenstatus_kasid, youngestkind.kiid as youngestkind_kiid, youngestkind.geburtsdatum as youngestkind_geburtsdatum ,oldestkind.kiid as oldestkind_kiid, oldestkind.geburtsdatum as oldestkind_geburtsdatum
FROM kunde
LEFT OUTER JOIN karte ON (kunde.kid = karte.kartennummer)
LEFT OUTER JOIN kind ON (kind.kunde_kid = kunde.kid)
LEFT OUTER JOIN kartenstatus ON (karte.kartenstatus_kasid = kartenstatus_kasid)
LEFT OUTER JOIN youngestkind ON (youngestkind.kunde_kid = kunde.kid)
LEFT OUTER JOIN oldestkind ON (oldestkind.kunde_kid = kunde.kid)
GROUP BY kind.kiid,karte.kartennummer
ORDER BY kunde.kid
Naja, also es ist dann so, dass in meiner Ergebnis Zeilen sozusagen "doppelt" sind:
also die "einfachen" Kunden daten wie vorname, nachname usw. (kunde.*) werden mehrfach gelistet, jedoch immer mit unterschiedlichen Kinder bzw. Karten.
Naja, so wächst aber natürlich die Anzahl an Zeilen beträchtlich.
Also, wie könnte man das optimieren?
Also an SELECT SQL wird es sicher eine effizientere Lösung geben, aber um ehrlich zu sein ist mir bis jetzt keine eingefallen. Vielleicht kann man das irgendwie besser mit einer View lösen, aber die View hat ja dann auch nur im Prinzip den selben SELECT Befehl, also gleiche Performance.
Ich habe mir gedacht, ich könnte die Views youngestkind und oldestkind irgendwie zusammenlegen zu einer View, um sich einen JOIN zu sparen, aber macht das wirklich einen größeren unterschied?
Wie funktioniert das eigentlich genau mit INDEXE? Also ich habe ja nur PRIMARY KEYS, die ja aber auch INDEXE sind, soweit ich weis zumindest. Sind FOREIGN KEYS auch INDEXE? Wenn nein, würde es die Performance verbessern wenn ich die FOREIGN KEYS zu INDEXE mache?
Was gibt es sonst noch für Möglichkeiten?
Es wäre super, wenn mir jemand weiter helfen könnte