
Hierarchische Strukturen und Bäume in MySQL (Rekursion)
Hierarchische Strukturen werden in Datenbanken oft mithilfe einer parentID umgesetzt. Man hat zu jedem Eintrag einen übergeordneten Eintrag, außer beim Wurzelelement. Diese parentID kommt zum Einsatz, da es sich laut ERM um eine Relation – besser 1:1-Beziehung – eines Eintrages der Tabelle mit einem anderen Eintrag der gleichen Tabelle handelt.
Da sich solche mathematischen Sachverhalte am verständlichsten mit einem Beispiel erklären lassen, wollen wir die Kategorien-Tabelle eines Online-Shops nehmen. Es gibt also zum Beispiel die Oberkategorien Lebensmittel und Kleidung. Als Unterkategorien haben wir Getränke, Gemüse und Obst. Gemüse hat zusätzlich die Unterkategorien Broccoli und Kohlrabi. Unter Obst hängen Pfirsich und Orange. Der gesamte Kategoriebaum wird im Baum-Schema deutlich.
Daraus lässt sich ein DHTML-Menü erstellen, das ähnlich wie das Windows-Startmenü zuerst alle Hauptkategorien auflostet und wenn man mit der Maus über eine Hauptkategorie fährt, klappen die Unterkategorien aus. Ein Script für hierarchische Menüs soll hier allerdings nicht weiter diskutiert werden. Als Beispiel und Verdeutlichung möchte ich noch das Menü auf der linken Seite eines großen Kleinanzeigenmarktes erwähnen – da sieht man recht deutlich, worum es geht: den Aufbau des Menüs.
Mit einfachem HTML verdeutlicht soll in unserer Datenbank-Tabelle folgende Struktur abgebildet werden:
- Lebensmittel
- Getränke
- Gemüse
- Broccoli
- Kohlrabi
- Obst
- Pfirsich
- Orange
- Kleidung
- Herrenkleidung
- Damenkleidung
Die Datenbank sieht nach ERM-Modell mit der Spalte parentID also so aus (Reihenfolge willkürlich gewählt):
| ID | Kategoriename | parentID |
|---|---|---|
| 1 | Lebensmittel | 0 |
| 2 | Orangen | 6 |
| 3 | Broccoli | 7 |
| 4 | Herrenkleidung | 10 |
| 5 | Damenkleidung | 10 |
| 6 | Obst | 1 |
| 7 | Gemüse | 1 |
| 8 | Pfirsich | 6 |
| 9 | Kohlrabi | 7 |
| 10 | Kleidung | 0 |
| 11 | Getränke | 1 |
Die Hauptkategorien haben die parentID 0. Wir brauchen also eine Funktion, die den Baum komplett aufbaut. Bei genauem Hinsehen sieht man, dass diese rekursiv sein muss, denn wenn wir alle Kinder von einer Hauptkategorie selektieren, brauchen wir ja auch die Kinder von den selektierten Kinder – sozusagen die Kindes-Kinder = Enkel
Die PHP-Funktionen dafür sehen so aus:
function getMenu($oberkat) { $einlesen = mysql_query("SELECT ID,name FROM kategorien WHERE parentID='".$oberkat."' ORDER BY name"); $menu = ""; while($einzeln = @mysql_fetch_assoc($einlesen)) { if(hasChildKats($einzeln['ID'])) { $menu .= "<li>".$einzeln['name']."<ul>"; $menu .= getMenu($einzeln['ID']); $menu .= "</ul></li>"; } else { $menu .= "<li>".$einzeln['name'])."</li>"; } } return $menu; } function hasChildKats($katID) { $einlesen = mysql_query("SELECT ID FROM kategorien WHERE parentID='".$katID."'"); if(mysql_num_rows($einlesen)>0) return true; else return false; }
Wir selektieren erst alle Kinder einer Ebene, dann die Kinder der selektierten Einträge usw. Die Verzweigung mit der Prüfung, ob eine selektierte Kategorie noch weitere Kinder hat, ist nötig, da eine leere Liste (UL) nicht html-konform ist.
Funktionieren tut diese Abfrage, sie entspricht auch der Normalformenlehre und trotzdem gibt es an diesem Weg etwas zu kritisieren: Rekursion und SQL-Abfragen innerhalb einer Schleife sollten unbedingt – wenn möglich – vermieden werden. Da bei größeren Datenmenge bzw. einer tieferen Baumstruktur eine Unmenge an Abfragen an die Datenbank abgesetzt werden, wird der ganze Prozess sehr langsam. Wenn Sie schon etwas fortgeschrittener im Umgang mit SQL sind, empfehle ich deshalb das Nested Sets-Modell, das wesentlich besser skaliert.
Schlagwörter: db, MySQL, performance, rekursion, schleife













PHP Performance » Nested Sets - Hierarchische Strukturen und Bäume in MySQL sagt
am 17. April 2007 @ 13:32
[...] haben bereits gesehen, dass das rekursive Abfragen eines Baumes, der über Parent-IDs verwirklicht wurde, sehr [...]
andi’s developer blog » Blog Archive » Hierarchische Strukturen in MySQL sagt
am 7. Januar 2008 @ 23:04
[...] Parent-Modell (Tutorial im PHP Performance-Blog) ist langsam, da es rekursiv arbeitet, und daher viele SQL-Queries notwendig sind. Allerdings ist [...]
MySQL - Benutzte Kategorien - Developer's Guide sagt
am 2. Juni 2008 @ 21:41
[...] bin mir auch nicht sicher, ob sich das für 3 tiefen lohnt, aber guck einfach mal: Nested Sets oder Rekursion __________________ Applikations-Programmierung: BlitzMax, BlitzPlus Webentwicklung: PHP, (X)HTML, [...]
TP: [PHP] Dynamische Navigation mit PHP & MySQL - TP Hilfe Forum -- Anleitung - Tutorial - Workshop... sagt
am 13. August 2008 @ 19:07
[...] rockr, les Dir am besten mal diesen Beitrag durch (vor allem auch den letzten Abschnitt) und entscheide selbst. __________________ #.Viele [...]
Henning Maier sagt
am 3. April 2010 @ 22:07
Moin moin, schicker Beitrag auch wenn ich das etwas anders sehe
GhostGambler sagt
am 7. April 2010 @ 06:04
Was genau siehst du wie genau anders?