FAQ |
Kalender |
![]() |
#1 | ||
|
|||
Flitig postare
|
ja har en tabell med id, forum_name, parent
om parent är 0 har den ingen förälder. Om parent != 0 så är parent något forums id. Om ja vill skriva ut ett forums alla föräldrar måste jag loopa någonstans för att kolla om den har en förälder. Jag vill liksom få: Spel->CS->Global Offensive->Skärmdumpar Detta vill jag skriva ut genom att ha Skärmdumpars ID. Där Global Offensive är skärmdumpars förälder och cs är global offensive förälder och spel är CS förälder. Det är just denna loop där ja kollar om man har ngn parent som jag iunte vet hur ja ska bygga. |
||
![]() |
![]() |
![]() |
#2 | ||
|
|||
Klarade millennium-buggen
|
Typiskt rekursiv funktion, dvs funktionen kollar om parent är NULL, är den det så vet den att den nått ROOT-nivån i trädstrukturen, annars anropar den sig själv igen med parent som ID.
Pseudocode: Kod:
function category(categoryID) if (categoryID==NULL) // Nu har vi nått root-nivån else // Slå upp den nya parentID för aktuell categoryID från SQL // Här kör du SQL-satsen.... // Sen anropar du category()-funktionen igen med parentID som parameter category(parentID) endif End function Senast redigerad av Conny Westh den 2012-10-03 klockan 01:54 |
||
![]() |
![]() |
![]() |
#3 | |||
|
||||
Mycket flitig postare
|
Samma sak kan göras direkt i SQL om du vill.
I MSSQL är det relativt billigt att skapa temptabeller vilket man tillsammans med en sp skulle använda för att skriva en rekursiv, ehm, sp. Vet inte hur det är i MySQL som jag misstänker att du använder dig av men det vet säkert någon annan här. Min hjärna är dock inte tillräckligt vaken för rekursiva anrop och framförallt inte i SQL men du kan ju kika på följande länk: http://www.google.se/search?hl=sv&cl...sv&q=recursion ![]() |
|||
![]() |
![]() |
![]() |
#4 | ||
|
|||
Administratör
|
Rekursiva funktioner är ofta långsamma. Behöver du räkna med svarstid från SQL för varje rekursion finns det än mer anledning att hålla sig borta från det.
Det finns något som heter "Nested set model" som är desto mer effektivt. Läs på t ex http://scvinodkumar.wordpress.com/20...data-in-mysql/ Eller googla på hierarchical data in MySQL (eller annan dbms) eller nested set model. Ett alternativ är att denormalisera och spara hela sökvägen i varje post, men det blir istället ineffektivt och komplicerat vid uppdateringar.
__________________
eldefors.com - Personlig (teknik)-blogg |
||
![]() |
![]() |
![]() |
#5 | |||
|
||||
Mycket flitig postare
|
Du, Clarence, verkar vara en av få tekniskt vassa på det här forumet men usch, jag har svårt för sådana här generella rekommendationer. Hur relevant är det i det här fallet egentligen?
Svaret är att vi inte vet. Eftersom frecka inte skriver hur många nivåer eller träd det handlar om kan vi bara göra antaganden och det är ju sällan särskilt givande. Om man inte vet vad som är långsamt - mät. Antar eller gissar man kommer man garanterat sitta och pilla på nånting som inte ger någon mätbar skillnad. Den risken har man inte om man gör metodiska mätningar. Då får man det svart på vitt. Det kan inte gå fel! ![]() Senast redigerad av dAEk den 2012-10-04 klockan 23:02 |
|||
![]() |
![]() |
![]() |
#6 | ||
|
|||
Klarade millennium-buggen
|
Ett annat tips vad gäller optimeringar är att man inte ska optimera om man inte behöver det. Dvs lös först problemet på ett pedagogiskt och enklet sätt, så det blir lätt för nästa programmerare som ska ta över koden att förstå vad som görs. Sen om det visar sig att det blir prestandaproblem, då och först då börjar man optimera för ökad prestanda. Den största kostnaden vid systemutveckling är inte CPU-tid utan programmerarnas arbetstid. det är med andra ord effektivare att optimera programmerarnas arbetstid än datorns CPU-tid.
Sen att rekursiva funktionsanrop skulle vara ineffektiva har jag aldrig sett, det är körningsmässigt och kodmässigt inget som skiljer ett vanligt funktionsanrop från ett rekursivt, de är identiskt effektiva i alla kompilerande språk (åtminstonde de jag kört och testat). Senast redigerad av Conny Westh den 2012-10-04 klockan 23:34 |
||
![]() |
![]() |
![]() |
#7 | ||
|
|||
Administratör
|
Till att börja med, efter man varit på tillräckligt antal dåligt skrivna webbapplikationer som använt rekursiva anrop med queries, förmodligen för att programmerare precis lärt sig rekursion, så blir man lite allergisk av det. Men med det sagt så är det precis lika träligt att i det fallet ha en vanlig loop med queries.
Annars har ConnyWesth rätt, förutsatt att man har en kompilator/språk med tail call recursion optimization och man skriver sin rekursion så att kompilatorn kan göra optimeringen - vilket väl i bästa fall görs 50% av gångerna även av kompetenta programmerare. Också förutsatt att du faktiskt behövde en loop eller rekursion från första början - vilket inte ens gäller i detta fallet. Själv tycker jag väldigt bra om generella rekommendationer. Använd rekursion om det finns ett behov för rekursion - för läsbarhet, kodeffektivitet osv. I fallet i denna tråden har man istället fått sämre läsbarhet och 300% extra frågor mot databasen (delen av stacken som är svårast att skala effektivt). Och då har man ens inte tagit i åtanke de andra negativa effekter man får om man t ex ska hämta och visa hela trädet, noder på samma nivå osv.
__________________
eldefors.com - Personlig (teknik)-blogg |
||
![]() |
![]() |
![]() |
#8 | ||
|
|||
Medlem
|
Intressant länk med "Hierarchical Data" och "Nested set model".
Men också avancerat, som jag förstår detta, med bibehållen tabellstruktur är alternativet selfjoins SELECT t1.forum_name AS lev1, t2.forum_name as lev2, t3.forum_name as lev3, t4.forum_name as lev4 FROM forums AS t1 LEFT JOIN forums AS t2 ON t2.parent = t1.id LEFT JOIN forums AS t3 ON t3.parent = t2.id LEFT JOIN forums AS t4 ON t4.parent = t3.id WHERE t1.forum_name= 'Spel' AND t4.forum_name= 'Skärmdumpar'; Personligen skulle jag dock gå på ConnyWesth alternativ i detta specifika fall, om vi antar att man ska bygga ett eget enkelt forum. Givet att det inte blir fler än ett par hundra forumkategorier kan man ju även hämta all data och spara i en array, då blir det endast ett sql anrop $query = 'SELECT * Forum;'; $result = MYSQL_QUERY($query); $forums= array(); while($row = mysql_fetch_array($result)) { // stoppa in data i $forums array } function category(categoryID) if (categoryID==NULL) // Nu har vi nått root-nivån else // Slå upp den nya parentID för aktuell categoryID // hämta data från $forums array // Sen anropar du category()-funktionen igen med parentID som parameter category(parentID) endif End function |
||
![]() |
![]() |
![]() |
#9 | |||
|
||||
Mycket flitig postare
|
Vi har inte sett någon annan kod så de olika lösningarna som vi ställer mot varandra kan mkt väl vara en droppe i havet. Vi har heller ingen aning om vilka krav som finns ang. prestanda så det finns egentligen inget värde i att snacka optimering. Visst kan vi diskutera fram och tillbaka rent generellt men jag ser inte någon mening med det. Jag får iaf inte ut något av det.
Ang. läsbarhet: man behöver inte skriva ett blogginlägg för att förklara hur en rekursiv metod funkar (till skillnad mot t.ex. nested set-modellen) vilket borde ge en indikation på vilken av lösningarna som är enkel/tydlig/läsbar/etc. Rekursiva metoder är dock knepiga att få grepp om för en del ![]() |
|||
![]() |
![]() |
![]() |
#10 | ||
|
|||
Administratör
|
För mig handlar det om att skriva bestående och flexibel kod snarare än att skriva prototyp-kod som fungerar nu och kanske måste skrivas om senare.
En bra skriven sajt kan du flytta till olika miljöer. En dåligt skriven sajt som du flyttar till något moln, t ex Amazon, får du ofta skriva om från grunden för att svarstiderna inom molnet blir för stora. Rekursion eller loopar med onödiga queries är ett klassiskt exempel som kan leda till sekunder i svarstid och oftast inte tar någon nämnvärd ansträngning att bli av med. Skulle det bara gälla en meny så är det inte heller några problem att optimera vid flytten - men återupprepas samma ineffektiva mönster i övriga delar av applikationen så har man ett helvetes jobb framför sig.
__________________
eldefors.com - Personlig (teknik)-blogg |
||
![]() |
![]() |
Svara |
|
|