3Danke
ERLEDIGT
JA
JA
ANTWORTEN
8
8
ZUGRIFFE
386
386
EMPFEHLEN
-
Ich schreibe ein Übersetzungstool für eine Multilingua-Seite.
Die Seite nutzt eine MySql Tabelle, wo alle Texte in folgenden Spalten stehen
id | folder | page | piece | language | content
Inhalt der Zeilen wäre z.B.
1 | members | login | st_title | 1 | Log In
2 | members | login | st_title | 2 | Einloggen
Das Ganze funktioniert super, bis auf eine Kleinigkeit.
Damit der Übersetzer sich nicht dusselig sucht, auf welchen Seiten noch Übersetzungen fehlen, will ich ihm eine hübsch nach Ordner und Seite sortierte Liste ausgeben, die nur die Seiten anzeigt, wo mindestens ein Teil fehlt.
Problem ist, das sind heftige viele Zeilen, so wie ich es jetzt habe dauert die Abfrage 35 Sek., aber max script runtime ist beim Provider nur 30 Sek., sprich das gibt kein Ergebnis, sondern Timeout.
Darum die Frage: Kann ich den folgenden Code irgendwie optimieren, so dass es schneller geht?
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
$allfiles = array(); $abfrage = mysql_query("SELECT DISTINCT `folder` FROM `sitetext` WHERE `language` = 1 ORDER BY `folder`"); while($row = mysql_fetch_object($abfrage)) { $abfrage2 = mysql_query("SELECT DISTINCT `page` FROM `sitetext` WHERE `folder` = '".$row->folder."' AND `language` = 1 ORDER BY `page`"); while($row2 = mysql_fetch_object($abfrage2)) { $abfrage3 = mysql_fetch_array(mysql_query("SELECT COUNT(`id`) FROM `sitetext` WHERE `folder` = '".$row->folder."' AND `page` = '".$row2->page."' AND `language` = 1")); $abfrage4 = mysql_fetch_array(mysql_query("SELECT COUNT(`id`) FROM `sitetext` WHERE `folder` = '".$row->folder."' AND `page` = '".$row2->page."' AND `language` = 2 AND `content` <> ''")); if ($abfrage3[0] != $abfrage4[0]) { $allfiles[] = $row->folder."/".$row2->page; } } }
Edit: Sorry, bin im falschen Forum gelandet, kann das jemand bitte nach PHP verschieben?Geändert von Thomasio (05.10.11 um 17:49 Uhr)
-
05.10.11 17:27 #2
- Registriert seit
- Jun 2007
- Ort
- Passau (Niederbayern)
- Beiträge
- 1.394
Hi,
würde hier die Struktur deiner MySQL-Tabelle etwas mehr nach den Normalformen gestalten.
Was ich damit im Speziellen meine, ist die Aufteilung in mehrere Tabellen:
============================================
languages:
bezeichnung: varchar
folders:
name: varchar
pages:
name: varchar
pieces:
name: varchar
sitetext:
id: int
folder: varchar (REFERENCES folders.name)
page: varchar (REFERENCES pages.name)
piece: varchar (REFERENCES pieces.name)
language: varchar (REFERENCES languages.bezeichnung)
content: varchar
============================================
Legende:
Fett: Tabelle
Unterstrichen: Primärschlüssel
Kursiv: Index / Fremdschlüssel
Das sollte deine Performanceprobleme größtenteils beseitigen
Gruß
BKGeändert von Bratkartoffel (05.10.11 um 17:30 Uhr) Grund: LEgende hinzugefügt
Über eine gute Bewertung freut sich jeder ;)
Bitte erledigte Threads als "Erledigt" markieren.
"Though a program be but three lines long, someday it will have to be maintained.''
-- Geoffrey James, "The Tao of Programming"
-
Das geht leider nicht, weil die Tabelle nicht von mir ist.
Ich soll nur das Übersetzungstool (neu) schreiben, nachdem der original Programmierer sich dünn gemacht hat.
Hauptproblem ist, der Inhaber der Seite hat genausoviel Angst wie keine Ahnung, wenn ich dem vorschlage die Struktur seiner DB grundlegend zu ändern bekommt er vermutlich Schüttelfrost oder sowas.
Auf jeden Fall danke für den Tipp, ich werde mal versuchen, wie weit ich die Jungs überreden kann.
Falls noch jemand eine Idee hat, wie es ohne Reorganisation der Tabelle geht, immer her damit.
-
05.10.11 21:36 #4
- Registriert seit
- Jun 2005
- Beiträge
- 8.168
Hi.
Der Datenbank Bereich wäre wohl passender gewesen. Du hast da ein RDBMS - warum benutzt du es nicht?
GrußCode sql:1 2 3 4 5 6 7 8 9 10
SELECT lang1.folder, lang1.page FROM (SELECT folder, page, COUNT(`id`) AS ids FROM sitetext WHERE LANGUAGE = '1' GROUP BY folder, page) AS lang1 INNER JOIN (SELECT folder, page, COUNT(`id`) AS ids FROM sitetext WHERE LANGUAGE = '2' GROUP BY folder, page) AS lang2 USING (folder, page) WHERE lang1.ids <> lang2.ids
Geändert von deepthroat (06.10.11 um 08:11 Uhr)
If at first you don't succeed, try again. Then quit. No use being a damn fool about it.
-
05.10.11 23:18 #5
- Registriert seit
- Jun 2007
- Ort
- Passau (Niederbayern)
- Beiträge
- 1.394
Hi,
wenn du dir ein Backup deiner Datenbank erstellst und jeglichen Zugriff von aussen blockierst, dann sollte die Änderung...
a) nicht großartig sein
b) nicht schiefgehen können
c) die performance dauerhaft erhöhen.
Falls du ihn von der Änderung überzeugen konntest, hier mal mein Ansatz (nur rudimentär getestet, würde das vorher an einer Kopie der Originaldatenbank testen bevor du das auf die "kritischen" Datensätzen loslässt
)
Code sql:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
-- Transaktion starten SET AUTOCOMMIT=0; START TRANSACTION; -- Tabellen erstellen CREATE TABLE `languages` ( `bezeichnung` VARCHAR(32) PRIMARY KEY NOT NULL ) ENGINE=innodb; CREATE TABLE `folders` ( `name` VARCHAR(64) PRIMARY KEY NOT NULL ) ENGINE=innodb; CREATE TABLE `pages` ( `name` VARCHAR(64) PRIMARY KEY NOT NULL ) ENGINE=innodb; CREATE TABLE `pieces` ( `name` VARCHAR(64) PRIMARY KEY NOT NULL ) ENGINE=innodb; -- Tabellen füllen INSERT INTO `languages` SELECT DISTINCT `language` FROM `sidetext`; INSERT INTO `pages` SELECT DISTINCT `page` FROM `sidetext`; INSERT INTO `folders` SELECT DISTINCT `folder` FROM `sidetext`; INSERT INTO `pieces` SELECT DISTINCT `piece` FROM `sidetext`; -- Tabelle sidetext anpassen und Indices sowie Fremdschlüssel setzen ALTER TABLE `sidetext` ENGINE innodb; ALTER TABLE `sidetext` CHANGE `language` `language` VARCHAR(32) NOT NULL; ALTER TABLE `sidetext` ADD INDEX(`folder`), ADD INDEX (`piece`), ADD INDEX (`page`), ADD INDEX (`language`); ALTER TABLE `sidetext` ADD CONSTRAINT `sidetext_fk_folder` FOREIGN KEY (`folder`) REFERENCES `folders` (`name`) ON UPDATE CASCADE, ADD CONSTRAINT `sidetext_fk_language` FOREIGN KEY (`language`) REFERENCES `languages` (`bezeichnung`) ON UPDATE CASCADE, ADD CONSTRAINT `sidetext_fk_page` FOREIGN KEY (`page`) REFERENCES `pages` (`name`) ON UPDATE CASCADE, ADD CONSTRAINT `sidetext_fk_piece` FOREIGN KEY (`piece`) REFERENCES `pieces` (`name`) ON UPDATE CASCADE; -- Alles fertig, Änderungen durchziehen COMMIT;
Vollautomatisch innerhalb einer Transaktion
Gruß
BKGeändert von Bratkartoffel (05.10.11 um 23:22 Uhr)
Über eine gute Bewertung freut sich jeder ;)
Bitte erledigte Threads als "Erledigt" markieren.
"Though a program be but three lines long, someday it will have to be maintained.''
-- Geoffrey James, "The Tao of Programming"
-
Ich danke euch beiden.
Inzwischen habe ich mit ihm gesprochen und ich hatte die Idee mit einer Kopie der DB auch schon.
Er will es sich überlegen hat er gesagt.
Bis dahin probiere ich mal den Vorschlag von deepthroat.
Nochmals vielen Dank.
-
06.10.11 08:40 #7
- Registriert seit
- Jun 2005
- Beiträge
- 8.168
Hi.Das finde ich nicht wirklich sinnvoll. Wozu die extra Tabellen? Ein UNIQUE INDEX auf die entsprechenden Spalten hätte genau den gleichen Effekt.
Man hätte höchstens einen stellvertretenden Primärschlüssel einführen können, da wäre eine extra Tabelle durchaus sinnvoll gewesen.
Außerdem bedeuten die Indizes und Fremdschlüssel einen Mehraufwand für die Datenbank (bei Änderungen der Daten). Da sollte man erstmal das Gesamtbild anschauen, bevor man da auf eine bestimmte Abfrage hin optimiert.
GrußGeändert von deepthroat (06.10.11 um 08:49 Uhr)
If at first you don't succeed, try again. Then quit. No use being a damn fool about it.
-
06.10.11 09:47 #8
- Registriert seit
- Jun 2007
- Ort
- Passau (Niederbayern)
- Beiträge
- 1.394
Hi,
klar gibt es keine 0815-Lösung zur Optimierung, lediglich Vorschläge die je nach bestehenden Schema getestet und analysiert werden müssen.
Jetzt wo ich mir meine Abfragen so nochmals durchsehe und drüber nachdenke fallen mir auch noch einige Änderungen ein, die ich machen würde. War anscheinend gestern nicht mehr so ganz auf der Höhe und hab im Eifer des Gefechts dann mit Kannonen auf Spatzen gezielt
. Kann aber auch sein, dass ich ein notorischer Datenbank-Struktur-Verbesserer bin, spiele mich da gern rum um die verschiedenen Möglichkeiten zu betrachten.
Was mir jetzt noch fix für den ersten Post einfällft, ist dass man eventuell das "mysql_fetch_object" durch ein "mysql_fetch_assoc" austauschen könnte. Soweit ich das noch richtig im Kopf hab, war das um einiges schneller. (Edit: Benchmark)
Edit: @thomasio: Bitte melde dich dann nochmal wenn du dich für eine Lösung entschieden hast und um wieviel sich deine Ergebnisse verbesser haben
Gruß
BKGeändert von Bratkartoffel (06.10.11 um 09:54 Uhr)
Über eine gute Bewertung freut sich jeder ;)
Bitte erledigte Threads als "Erledigt" markieren.
"Though a program be but three lines long, someday it will have to be maintained.''
-- Geoffrey James, "The Tao of Programming"
-
Sorry, war ein paar Tage im Urlaub, darum späte Antwort.
Deine Lösung haut leider nicht hin, weil pages und pieces mehrfach den selben Eintrag haben können, erst in der Kombination von folder/page/piece wird es unique.
Mit dem Vorschlag von deepthroat gewinne ich genug Zeit um unterm Timeout zu bleiben, wieviel genau kann ich nicht sagen, weil sich die Daten ständig ändern, wenn die Übersetzer an der Arbeit sind, geschätzt ca. 40%.
Nochmal danke euch beiden, für den Moment ist mir geholfen.
Ähnliche Themen
-
MySQL > 1 zu n Abfrage optimieren
Von newbe im Forum PHPAntworten: 1Letzter Beitrag: 26.10.09, 16:31 -
mySQL Abfrage optimieren
Von BadMatt im Forum Relationale DatenbanksystemeAntworten: 4Letzter Beitrag: 15.09.08, 06:07 -
MySQL-Abfrage optimieren
Von devilzride im Forum Relationale DatenbanksystemeAntworten: 1Letzter Beitrag: 12.09.06, 23:20 -
MySQL-Abfrage optimieren
Von devilzride im Forum PHPAntworten: 0Letzter Beitrag: 12.09.06, 23:01 -
MySQL Abfrage Optimieren
Von dr_Alex im Forum Relationale DatenbanksystemeAntworten: 1Letzter Beitrag: 07.03.06, 02:42





Zitieren

Login






