[MySQL] Performanceprobleme

Eroli

Erfahrenes Mitglied
Guten Vorabend zusammen ;-)

Ich hatte vor einiger Zeit das Datenbankdesign einer meiner Websites komplett überarbeitet und ich dachte, ich hätte es damit auch optimiert, doch bei diesem Punkt stutze ich derweil irgendwie...
Ich sollte dazu vielleicht ergänzen, dass ich auf meinem Rechner überhaupt keinen Performanceunterschied feststellen konnte - auf dem produktivsystem aber sehr wohl. Auf meinem Entwicklungsrechner kam das Ergebnis quasi "at once" - auf dem Server dauert dieselbe Abfrage schonmal gut und gerne an die 60s ****?
Zum Vergleich habe ich zwei Tabellen, welche sich sehr ähnlich sind.

Zum einen Tabelle A mit 3.500 Einträgen (die schnelle) und dann Tabelle B (die langsame) mit 13.000 Einträgen. Beide Tabellen haben eine ähnliche Struktur und arbeiten mit InnoDB:

---Tabelle A---
Primary Key
Primary Key2
Einige Foreign Keys
Datenfelder

---Tabelle B---
Primary Key
Einige ForeignKeys (unter anderem auch einer zu Tabelle A)
Datenfelder

Query zum durchforsten von Tabelle A:
SQL:
SELECT a.PrimaryKey, a.EinigeForeignKeys, a.EinigeDatenfelder, c.Datenfeld, d.Datenfeld
FROM Tabelle A a
INNER JOIN TabelleC c ON a.ForeignKey = c.PrimaryKey
[insgesamt 1 INNER JOIN, 2 JOINS und 1 OUTER LEFT JOIN]
WHERE ...
GROUP BY ...
ORDER BY ...

Und Tabelle B durchsuche ich so:
SQL:
SELECT b.PrimaryKey, b.ForeignKey, b.Datenfelder, e.PrimaryKey, e.Datenfeld
FROM TabelleB b
LEFT OUTER JOIN TabelleE e ON e.ForeignKey =  b.ForeignKey
WHERE b.ForeignKey = ?PrimaryKeyAusTabelleA

Das mag jetzt vielleicht ein bisschen wirr aussehen, deswegen beschreib ich das nochmal mit meinen Worten:
Obgleich mri bewusst ist, dass Tabelle B 4 mal soviele Einträge hat, kommt das Ergebnis der Query zum Durchsuchen von Tabelle B viel viel langsamer, obwohl die Query eigentlich leichter strukturiert ist (nur ein LEFT OUTER JOIN). Außerdem liefert die Query nur ein Ergebnis zurück. Der andere Befehl liefert über 200 Resultate in seeeehr viel kürzerer Zeit zurück und das macht mich halt alles etwas stutzig...

Hat das WHERE mit dem Parameter, welcher ein PrimaryKey aus Tabelle A ist, etwas damit zu tun?
Liegt es doch tatsächlich an der Menge der Datensätze?
Kann man die Tabelle vielleicht umsortieren (sodass neuerer Einträge schneller gefunden werden (Weil man wohl viel öfter die neueren brauchen wird, als die ganz alten))?

Ich hoffe ihr könnt mich etwas aufklären :)

Falls ihr weitere Infos braucht, sagt Bescheid ;-)

Ciao,
Eroli :)
 
Hi,

es währe um einiges hilfreicher, wenn du uns den Tabellenaufbau (am besten die CREATE TABLE-Statements) und die vollständigen Select-Queries geben könntest.

Selbst wenn ich nicht weiß wie deine Tabellen aufgebaut und deine Queries genau aussehen, kann ich mir beim besten Willen nicht vorstellen, dass eine Abfrage bei 13.000 Datensätzen so lange dauert .

Gruß
RudolfG
 
Hallo RudolfG,

vielen Dank für deinen Beitrag. Anbei die CREATE-Statements:
Die "schnelle" Tabelle:
SQL:
CREATE  TABLE IF NOT EXISTS `artikel` (

  `PK_Artikel` BINARY(16) NOT NULL ,

  `ID` INT NULL ,

  `FK_Rubric` BINARY(16) NOT NULL ,

  `FK_Category` BINARY(16) NOT NULL ,

  `FK_Language` BINARY(16) NOT NULL ,

  `FK_User` BINARY(16) NOT NULL ,

  `Title` VARCHAR(250) NULL ,

  `Description` TEXT NULL ,

  `Views` INT NULL ,

  `CreationTimestamp` DATETIME NULL ,

  `UpdateTimestamp` DATETIME NULL ,

  `Publication` VARCHAR(250) NULL ,

  `ReviewLink` VARCHAR(250) NULL ,

  `PrivateReviewlLink` VARCHAR(250) NULL ,

  `Regisseur` VARCHAR(250) NULL ,

  `Actors` VARCHAR(250) NULL ,

  `Runtime` VARCHAR(250) NULL ,

  `Producer` VARCHAR(250) NULL ,

  `Artist` VARCHAR(250) NULL ,

  `Album` VARCHAR(250) NULL ,

  `Equipment` VARCHAR(250) NULL ,

  `Approved` TINYINT(1)  NULL ,

  `Request` TINYINT(1)  NULL DEFAULT False ,

  PRIMARY KEY (`PK_Artikel`, `ID`) )

ENGINE = InnoDB;

Und die "langsame" Tabelle:
SQL:
CREATE  TABLE IF NOT EXISTS `downloadlinks` (

  `PK_DownloadLink` BINARY(16) NOT NULL ,

  `FK_System` BINARY(16) NOT NULL ,

  `FK_Artikel` BINARY(16) NOT NULL ,

  `FK_Owner` BINARY(16) NOT NULL ,

  `FK_Group` BINARY(16) NOT NULL ,

  `PrivateTitle` VARCHAR(250) NULL ,

  `DownloadLink` VARCHAR(500) NOT NULL ,

  `FileName` VARCHAR(250) NULL ,

  `FileSize` BIGINT NULL ,

  `Downloads` INT NULL DEFAULT 0 ,

  `Approved` TINYINT(1)  NULL ,

  `CreationTimestamp` DATETIME NULL ,

  `UpdateTimestamp` DATETIME NULL ,

  PRIMARY KEY (`PK_DownloadLink`) )

ENGINE = InnoDB;

Und nun die SELECT-Statements:
Das schnelle Select:
SQL:
SELECT x.PK_Artikel, x.Title, x.FK_Language, u.UploadHint, c.Title AS CategoryTitle, COUNT(co.PK_Comment) AS Comments, SUM(dl.Downloads) AS Downloads
FROM Artikel x
INNER JOIN users u ON x.FK_User = u.PK_User
JOIN categories c ON x.FK_Category = c.PK_Category
JOIN downloadLinks dl ON dl.FK_Artikel = x.PK_Artikel (dies ist die langsame Tablle)
LEFT OUTER JOIN comments co ON co.FK_Upload = x.PK_Upload
WHERE x.Approved = ?Approved AND x.FK_Rubric = ?FK_Rubric
GROUP BY dl.FK_Artikel, co.FK_Artikel
ORDER BY x.CreationTimestamp " + (newestFirst ? "DESC" : "ASC")
 LIMIT {0}, {1}, offset, count);

Das langsame Select:
SQL:
SELECT dl.PrivateTitle, dl.FK_Group, COUNT(dl.FK_Group) AS Count,
SUM(dl.Downloads) AS Downloads, SUM(dl.FileSize) AS Size,
dl.FK_System, s.System, s.Collection
FROM downloadlinks dl
INNER JOIN systems s ON s.PK_System = dl.FK_System
WHERE FK_Artikel = ?FK_Artikel
GROUP BY FK_Group
ORDER BY Downloads DESC, s.SortIndex ASC

(Ausschnitt aus einer ASP.NET Website, deswegen kein reiner SQL-Code)

So, ich hoffe du kannst damit mehr anfangen. Ich bin wirklich gespannt, warum dies auf dem Server (zudem ich leider nicht wirklich viel weiß, da nur Webspace) so langsam läuft.

Vielen Dank schonmal im vorraus.

Ciao,
Eroli
 
Hallo,

mir ist gerade aufgefallen, dass mein mysqldumper anzeigt, dass Tabelle Artikel eine IndexLength von 160KB und downloadlinks von 1.5MB hat.
Irgendwie doch unlogisch, da Artikel 2 PKs und 4FKs hat und Downloadlinks 1PK und 4FK...

Kann das damit zusammenhängen? Falls ja, warum ist diese IndexLength soviel größer?
 
Stelle bitte der langsamen Abfrage EXPLAIN voran, führe dieses Statement aus und poste uns die Ausgabe.

Tipp: In der Konsole hinter den Query \G erzeugt eine für das Forum bessere Ausgabe.
Code:
EXPLAIN SELECT 1\G

Grüße BN
 

Neue Beiträge

Zurück