Struktur eines Forums

  • Themenstarter Themenstarter P_F
  • Beginndatum Beginndatum
klasse, ich probiere es gleich aus. Also ich find es wirklich super, dass du dir die zeit genommen hast, das so detailiert zu erklären -> serh nice
Philipp
 
Mir ist gerade noch was eingefallen:
Du wirst keine Kategorien aufgelistet bekommen, in denen kein Forum enthalten ist.
Da ein Forum jedoch immer zu einer Kategorie gehört(Ist das so?), sollte man den LEFT JOIN vielleicht andersrum machen, also "... FROM Kategorie LEFT JOIN Forum ON ...".
 
ich schwörs dir, hab es ausprobiert und genau das gemerkt und wollte grade posten. Tja, da bist du mir zuvor gekommen - sehr gut !
Klappt super - genau das hab ich gesucht :D
 
Habe noch ein paar Benchmarks gemacht:

hier erst mal das Benchmark script:
PHP:
<?php
         // +----------------------------------------------------------------------+
 // | codeSnippetBench.php											 |
         // |======================================================================|
         // | How it works:
         // |   Below you will see some working code as sample. To add new tests
         // |   add a $profileTest[] hash entry below.
         // |   'title' / 'text' Are used for the output and are self explaining.
         // |   'function' Is the function *basename* like "myTest". This program
 // |			 will then look for function "myTest1", "myTest2" a.s.o.
         // |   'param'	Is the first parameter passed to that function
         // |
         // |  Now write the function (e.g. "myTest1", "myTest2"). They will be
         // |  called and benchmarked.
         // +----------------------------------------------------------------------+
 // | Main Author:														 |
 // | Sam Blum <bs_php@infeer.com>									 |
 // |																	 |
 // | Modified By Gerhard Jörges <gerhard@joerges.net>					 |
         // +----------------------------------------------------------------------+
         
         $durchlaeufe = 1000;
         
         # For query vs array vs 1 query
         $profileTest[] = array (
         	'title'	 => ' ',
         	'text'	  => ' 10 Kategorien je 1 Forum (kein Query Cache)',
         	'function'  => 'kat_for_',
         	'param'	 => array('3', 'SQL_NO_CACHE')
         );
         
         $profileTest[] = array (
         	'title'	 => ' ',
         	'text'	  => ' 10 Kategorien je 1 Forum (mit Query Cache)',
         	'function'  => 'kat_for_',
         	'param'	 => array('3', 'SQL_CACHE')
         );
         
         $profileTest[] = array (
         	'title'	 => ' ',
         	'text'	  => ' 10 Kategorien 0 Foren (kein Query Cache)',
         	'function'  => 'kat_for_',
         	'param'	 => array('2', 'SQL_NO_CACHE')
         );
         
         $profileTest[] = array (
         	'title'	 => ' ',
         	'text'	  => ' 10 Kategorien 0 Foren (mit Query Cache)',
         	'function'  => 'kat_for_',
         	'param'	 => array('2', 'SQL_CACHE')
         );
         
         $profileTest[] = array (
         	'title'	 => ' ',
         	'text'	  => ' 10 Kategorien 400 Foren (kein Query Cache)',
         	'function'  => 'kat_for_',
         	'param'	 => array('1', 'SQL_NO_CACHE')
         );
         
         $profileTest[] = array (
         	'title'	 => ' ',
         	'text'	  => ' 10 Kategorien 400 Foren (mit Query Cache)',
         	'function'  => 'kat_for_',
         	'param'	 => array('1', 'SQL_CACHE')
         );
         
         // ------------------------------------------------------------------
         // ------------------------------------------------------------------
         //   Add your functions below here
         
         $db = mysql_connect('localhost', 'root', 'root');
         mysql_select_db('phpbb2');
         mysql_query('SET QUERY_CACHE_TYPE = DEMAND');
         echo mysql_error();
         
         #----------------------------------------------------------------------
         # query Methode
         function kat_for_1($table, &$profTest, $functionNr) {
         	global $db;
         
         	$profTest['TestCaption'][$functionNr] = 'query Methode';
         
 	$sql = 'SELECT '.$table[1].' cat_id, cat_title FROM categories_'.$table[0].' ORDER BY cat_order';
         	$result_cat = mysql_query($sql);
         	$tmp = '';
         	while ($cat = mysql_fetch_assoc($result_cat)) {
         		$tmp .= $cat['cat_title'].'<br>';
 		$sql = 'SELECT '.$table[1].' forum_id, forum_name FROM forums_'.$table[0].' WHERE cat_id='.$cat['cat_id'].' ORDER BY forum_order';
         		$result_forum = mysql_query($sql);
         		while ($forum = mysql_fetch_assoc($result_forum)) {
         			$tmp .= '- '.$forum['forum_name'].'<br>';
         		}
         	}
         //echo $tmp.'<br><br>';
         }
         
         #----------------------------------------------------------------------
         # Array Methode #1
         function kat_for_2($table, &$profTest, $functionNr) {
         	global $db;
         
         	$profTest['TestCaption'][$functionNr] = 'Array Methode #1';
         
 	$sql = 'SELECT '.$table[1].' cat_id, cat_title FROM categories_'.$table[0].' ORDER BY cat_order';
         	$result_cat = mysql_query($sql);
         	$category = array();
         	while($cat = mysql_fetch_assoc($result_cat)) {
         		$category[] = $cat;
         	}
         
 	$sql = 'SELECT '.$table[1].' forum_id, forum_name, cat_id FROM forums_'.$table[0].' ORDER BY forum_order';
         	$result_forum = mysql_query($sql);
         	$board = array();
         	while($forum = mysql_fetch_assoc($result_forum)) {
    		if(!isset($board[$forum['cat_id']])) { $board[$forum['cat_id']] = array(); }
         		$board[$forum['cat_id']][] = $forum;
         	}
         
         	$tmp = '';
         	foreach ($category as $cat) {
         		$tmp .= $cat['cat_title'].'<br>';
         		if (is_array($board[$cat['cat_id']])) {
         			foreach ($board[$cat['cat_id']] as $forum) {
 				$tmp .= '- '.$forum['forum_name'].'<br>';
         			}
         		}
         	}
         //echo $tmp.'<br><br>';
         }
         
         #----------------------------------------------------------------------
         # Array Methode #2
         function kat_for_3($table, &$profTest, $functionNr) {
         	global $db;
         
         	$profTest['TestCaption'][$functionNr] = 'Array Methode #2';
         
 	$sql = 'SELECT '.$table[1].' cat_id, cat_title FROM categories_'.$table[0].' ORDER BY cat_order';
         	$result_cat = mysql_query($sql);
         	$category = array();
         	while($cat = mysql_fetch_assoc($result_cat)) {
         		$category[] = $cat;
         	}
         
 	$sql = 'SELECT '.$table[1].' forum_id, forum_name, cat_id FROM forums_'.$table[0].' ORDER BY forum_order';
         	$result_forum = mysql_query($sql);
         	$board = array();
         	while($forum = mysql_fetch_assoc($result_forum)) {
    		if(!isset($board[$forum['cat_id']])) { $board[$forum['cat_id']] = array(); }
         		$board[] = $forum;
         	}
         
         	$tmp = '';
         	foreach ($category as $cat) {
         		$tmp .= $cat['cat_title'].'<br>';
         		foreach ($board as $forum) {
         			if ($forum['cat_id'] == $cat['cat_id']) {
 				$tmp .= '- '.$forum['forum_name'].'<br>';
         			}
         		}
         	}
         //echo $tmp.'<br><br>';
         }
         
         #----------------------------------------------------------------------
         # Array Methode #3
         function kat_for_4($table, &$profTest, $functionNr) {
         	global $db;
         
         	$profTest['TestCaption'][$functionNr] = 'Array Methode #3';
         
 	$sql = 'SELECT '.$table[1].' cat_id, cat_title FROM categories_'.$table[0].' ORDER BY cat_order';
         	$result_cat = mysql_query($sql);
         	$category = array();
         	while($cat = mysql_fetch_assoc($result_cat)) {
         		$category[$cat['cat_id']] = $cat;
         	}
         
 	$sql = 'SELECT '.$table[1].' forum_id, forum_name, cat_id FROM forums_'.$table[0].' ORDER BY cat_id, forum_order';
         	$result_forum = mysql_query($sql);
         	$board = array();
         	while($forum = mysql_fetch_assoc($result_forum)) {
    		if(!isset($board[$forum['cat_id']])) { $board[$forum['cat_id']] = array(); }
         		$board[] = $forum;
         	}
         
         	$tmp = '';
         	$lastcat = '';
         	foreach ($board as $forum) {
         		if($lastcat != $forum['cat_id']) {
 			$tmp .= $category[$forum['cat_id']]['cat_title'].'<br>';
         			$lastcat = $forum['cat_id'];
         		}
         		$tmp .= '- '.$forum['forum_name'].'<br>';
         	}
         //echo $tmp.'<br><br>';
         }
         
         #----------------------------------------------------------------------
         # 1 query Methode
         function kat_for_5($table, &$profTest, $functionNr) {
         	global $db;
         
         	$profTest['TestCaption'][$functionNr] = '1 query Methode';
         
         	$sql = 'SELECT '.$table[1].' f.forum_id, c.cat_id, f.forum_name, c.cat_title '
         	.'FROM forums_'.$table[0].' f LEFT JOIN categories_'.$table[0].' c ON c.cat_id=f.cat_id '
         	.'ORDER BY c.cat_order, f.forum_order';
         	$result = mysql_query($sql);
         	$lastCat="";
         	while ($row=mysql_fetch_assoc($result)) {
         		if($row['cat_id'] != $lastCat) {
         			$tmp .= $row['cat_title'].'<br>';
         			$lastCat=$row['cat_id'];
         		}
         		$tmp .= '- '.$row['forum_name'].'<br>';
         	}
         //echo $tmp.'<br><br>';
         }
         
         
         
         #=======================================================================
         #  Don't add anything below this line
         #=======================================================================
         
         $out = '';
         $out_bash = '';
         $testSize = sizeOf($profileTest);
         for ($i=0; $i<$testSize; $i++) {
         	$profTest = &$profileTest[$i];
         	if ($profTest['title'] == $runOnlyThis) continue;
         
         	// Now loop through the functions of every test
         	$functionNr = 1;
         	$function = $profTest['function'] . $functionNr;
         	while(function_exists($function)) {
         		$profTest['result'][$functionNr-1] = 0;
         		for ($durchlauf = 1; $durchlauf <= $durchlaeufe; $durchlauf++) {
         			$sTime = explode(' ', microtime());
 			$function($profTest['param'], $profTest, $functionNr-1);
         			$eTime = explode(' ', microtime());
 		 $profTest['result'][$functionNr-1] += (($eTime[1] - $sTime[1]) + ($eTime[0] - $sTime[0]))*1000;
         		}
         
         		$functionNr++;
         		$function = $profTest['function'] . $functionNr;
         	}
         	$out .= '<table width="500" border="0" cellspacing="0" cellpadding="0">'
         		 .  '<tr align="left" bgcolor="#bcd6f1"><th colspan=2>'
         		 .	 $profTest['title']
         		 .  '</th></tr>'
         		 .  '<tr bgcolor="#bcd6f1"><td  colspan=2>'
         		 .	$profTest['text']
         		 .  '</td></tr>';
         
         	$out_bash .= '	 '.$profTest['title']."\n";
         	$out_bash .= wordwrap($profTest['text'])."\n";
         	$out_bash .= "------------------------------------------------------------------------------\n";
         
         	for ($res=0; $res<sizeOf($profTest['result']); $res++) {
         		$color = ($res % 2 == 0) ? 'bgcolor="#e1fffe"' : 'bgcolor="#ecf5ff"';
  		$out .= "<tr {$color}><td width=65% style='font-size: 11'>";
         		$funcName = $profTest['function'][$res];
 		$out .= isSet($profTest['TestCaption'][$res]) ? ($res+1).': '. $profTest['TestCaption'][$res] : '&nbsp;';
         		$out  .= '</td><td style="font-family: courier" nowrap>';
         		if (isSet($profTest['TestCaption'][$res])) {
 			$out_bash .= '| '.($res+1).' | '. str_pad($profTest['TestCaption'][$res], 53, ' ');
         		} else {
 			$out_bash .= '| '.($res+1).' |		 ?								 ';
         		}
   		$time = sprintf("%.2f", round($profTest['result'][$res]/$durchlaeufe, 2));
         		$time  = str_pad($time,5,' ',STR_PAD_LEFT);
         		$out  .= 'Total time: ' . str_replace(' ','&nbsp;',$time) . '[ms]';
         		$out  .= '</td></tr>';
         		$out_bash .= ' | Time: '.$time.' ms |'."\n";
         	}
         	$out .= '</table><br>';
         	$out_bash .= "------------------------------------------------------------------------------\n";
         }
         if ($argc == 1) {
         	echo "\n".str_pad('*** Benchmark start ('.$durchlaeufe.' Durchlaeufe) ', 79, '*')."\n";
         	echo $out_bash;
         	echo "\n*** habe fertig **************************************************************\n\n";
         } else {
         	echo '<body  style="font-family: Verdana, Geneva, Arial">';
         	echo $out;
         	echo '</body>';
         }
         ?>

und die Ergebnisse:
Code:
 10 Kategorien je 1 Forum (kein Query Cache)
      ---------------------------------------------------
       
         | 1 | query Methode	    | Time:  3.91 ms |
         | 2 | Array Methode #1	   | Time:  1.06 ms |
         | 3 | Array Methode #2	   | Time:  1.30 ms |
         | 4 | Array Methode #3	   | Time:  1.06 ms |
         | 5 | 1 query Methode        | Time:  0.88 ms |
      ---------------------------------------------------
         
          10 Kategorien je 1 Forum (mit Query Cache)
         ---------------------------------------------------
         | 1 | query Methode	    | Time:  1.80 ms |
         | 2 | Array Methode #1	   | Time:  0.62 ms |
         | 3 | Array Methode #2	   | Time:  0.89 ms |
         | 4 | Array Methode #3	   | Time:  0.62 ms |
         | 5 | 1 query Methode	   | Time:  0.34 ms |
         ---------------------------------------------------
         
          10 Kategorien 0 Foren (kein Query Cache)
         ---------------------------------------------------
         | 1 | query Methode	    | Time:  2.57 ms |
         | 2 | Array Methode #1	   | Time:  0.78 ms |
         | 3 | Array Methode #2	   | Time:  0.72 ms |
         | 4 | Array Methode #3	   | Time:  0.71 ms |
         | 5 | 1 query Methode	   | Time:  0.28 ms |
         ---------------------------------------------------
         
          10 Kategorien 0 Foren (mit Query Cache)
         ---------------------------------------------------
         | 1 | query Methode	    | Time:  1.71 ms |
         | 2 | Array Methode #1	   | Time:  0.49 ms |
         | 3 | Array Methode #2	   | Time:  0.44 ms |
         | 4 | Array Methode #3	   | Time:  0.42 ms |
         | 5 | 1 query Methode	   | Time:  0.19 ms |
         ---------------------------------------------------
         
          10 Kategorien 400 Foren (kein Query Cache)
         ---------------------------------------------------
         | 1 | query Methode	    | Time: 13.41 ms |
         | 2 | Array Methode #1	   | Time: 13.67 ms |
         | 3 | Array Methode #2	   | Time: 27.32 ms |
         | 4 | Array Methode #3	   | Time: 11.70 ms |
         | 5 | 1 query Methode        | Time: 10.61 ms |
         ---------------------------------------------------
         
          10 Kategorien 400 Foren (mit Query Cache)
         ---------------------------------------------------
         | 1 | query Methode	    | Time:  5.46 ms |
         | 2 | Array Methode #1	   | Time:  8.34 ms |
         | 3 | Array Methode #2	   | Time: 17.79 ms |
         | 4 | Array Methode #3	   | Time:  8.44 ms |
         | 5 | 1 query Methode	   | Time:  6.11 ms |
         ---------------------------------------------------
 
Hmm...

mal eine Frage, da ich gerade vor einem ähnlichen Problem stehe:

Wie wäre es mit Nested Sets für die Kategorien?

Und, auch wenn das jetzt etwas OT ist, noch eine Anschlussfrage:
Ich habe mir jetzt ne schöne Nested-Sets-Klasse geschrieben, meine Frage ist jetzt, ob es sinnvoll ist oder nicht ist diese bei Kategorie-Bäumen mit nur einer Unterebene einzusetzen?#
Also bei soetwas:
Code:
Root
    Kat.A
    Kat.B
    Kat.C
Oder soll ich bei soetwas lieber eine komplett neue Klasse schreiben, die das Ganze über das altbekannte parentID-Modell realisiert?
Also mir geht es hier gerade eigentlich nur um die Performance, weil sonst ist es ja relativ egal...
Wäre halt geschickt, hier auch die NestedSets-Klasse einzusetzten, weil ich dann alle Arten von Kategorien (Sitemap, File-Database, Forum, Usergruppen) über die gleiche Klasse verwalten könnte...


swEEper

swEEper
 
Zurück