Seite 1 von 3

Abfrage für große Topics verbessern

Verfasst: 13.02.2006 22:22
von mgutt
Ich habe ein Problem mit einem Thema in meinem Board.

Dies umfasst ca. 60.000 Antworten und seit der ca. 30.000 Antwort schalte ich eine Funktion nach der anderen ab um das Thema zu beschleunigen.

Naja, jetzt ist meine viewtopic.php mitterweile stark zerklüftet mit speziellen Spamtopicbedingungen und mir fällt nichts mehr ein.

Das hautpsächliche Problem verursacht denke ich die standardmäßige Abfrage der Topics bzw. für die Pagination.

Nicht wundern über die Vielfalt ;)
www.maxrev.de/files/viewtopic.txt

Das Problem verursacht die Hauptabfrage:

Code: Alles auswählen

	$sql = "SELECT pt.post_sub_title, u.username, u.user_id, u.user_posts, u.user_from, u.user_firstname, u.user_ebayname, u.user_car, u.user_website, u.user_email, u.user_icq, u.user_aim, u.user_yim, u.user_regdate, u.user_msnm, u.user_viewemail, u.user_rank, u.user_sig, u.user_sig_bbcode_uid, u.user_avatar, u.user_avatar_type, u.user_allowavatar, u.user_allowsmile, u.user_gender, p.*,  pt.post_text, pt.post_subject, pt.bbcode_uid
		FROM " . POSTS_TABLE . " p, " . USERS_TABLE . " u, " . POSTS_TEXT_TABLE . " pt
		WHERE p.topic_id = $topic_id
			$limit_posts_time
			AND pt.post_id = p.post_id
			AND u.user_id = p.poster_id
		ORDER BY p.post_time ASC
		LIMIT $start, ".$board_config['posts_per_page'];
Wie könnte man die Performance vielleicht verbessern?

Mein Memory wird andauernd mit mehr als 50 MB (mein Max.) gefüllt. (wohlgemerkt nur in dem einen Thread).

Verfasst: 13.02.2006 22:50
von alcaeus
Moin moin,

ich empfehle dir mal, dieses Thema durchzuarbeiten: http://www.phpbb.com/phpBB/viewtopic.php?t=135383

Greetz
alcaeus

Verfasst: 14.02.2006 00:35
von mgutt
Das Problem ist, dass das Topic (wo ich auf den letzten Seiten schon fleißig war) keine wirkliche Lösung gefunden habe. Jeder schmeißt da einen Schnippsel rein und dann heißt es probieren. Der Code auf der 1. Seite war auf jedenfall VIEL langsamer als der Original Code.

Folgende Abfragen verursachen DB Zeit:

nachdem ein beitrag abgesendet wurde:

Code: Alles auswählen

viewtopic.php
Zeile: 236
DB: 0.1731s
 Anfrage 
 SELECT t.topic_sub_type, t.topic_duration, t.topic_first_post_id, t.topic_sub_title, t.topic_calendar_time, t.topic_calendar_duration, t.topic_attachment, t.topic_id, t.topic_title, t.topic_status, t.topic_replies, t.topic_time, t.topic_type, t.topic_vote, t.topic_last_post_id, t.forum_id, COUNT(p2.post_id) AS prev_posts FROM phpbb_topics t, phpbb_posts p, phpbb_posts p2 WHERE p.post_id = 171978 AND t.topic_id = p.topic_id AND p2.topic_id = p.topic_id AND p2.post_id <= 171978 GROUP BY t.topic_sub_type, t.topic_duration, t.topic_first_post_id, t.topic_sub_title, t.topic_calendar_time, t.topic_calendar_duration, t.topic_attachment, p.post_id, t.topic_id, t.topic_title, t.topic_status, t.topic_replies, t.topic_time, t.topic_type, t.topic_vote, t.topic_last_post_id, t.forum_id ORDER BY p.post_id ASC   
  Tabelle     Typ     Mögliche Schlüssel     Benutzter Schlüssel     Schlüssel Länge     Ref.     Zeilen     Kommentar   
  p     const     PRIMARY,topic_id     PRIMARY     3     const     1        
  t     const     PRIMARY     PRIMARY     3     const     1        
  p2 

immer langsam:

Code: Alles auswählen

viewtopic.php
Zeile: 792
DB: 4.2441s
 Anfrage 
 SELECT pt.post_sub_title, u.username, u.user_id, u.user_posts, u.user_from, u.user_firstname, u.user_ebayname, u.user_car, u.user_website, u.user_email, u.user_icq, u.user_aim, u.user_yim, u.user_regdate, u.user_msnm, u.user_viewemail, u.user_rank, u.user_sig, u.user_sig_bbcode_uid, u.user_avatar, u.user_avatar_type, u.user_allowavatar, u.user_allowsmile, u.user_gender, p.*, pt.post_text, pt.post_subject, pt.bbcode_uid FROM phpbb_posts p, phpbb_users u, phpbb_posts_text pt WHERE p.topic_id = 6311 AND pt.post_id = p.post_id AND u.user_id = p.poster_id ORDER BY p.post_time ASC LIMIT 60610, 10   
  Tabelle     Typ     Mögliche Schlüssel     Benutzter Schlüssel     Schlüssel Länge     Ref.     Zeilen     Kommentar   
  p     ref     PRIMARY,topic_id,poster_id     topic_id     3     const     59688     Using where; Using filesort   
  u     eq_ref     PRIMARY     PRIMARY     3     p.poster_id     1        
  pt

Verfasst: 15.02.2006 19:19
von Gumfuzi
Sorry, wenn ich hier mal OT einbringe, aber wie stellt man die DB-Zeit PRO Anfrage fest?
(siehe Deine Codebeispiele)

Verfasst: 16.02.2006 14:05
von mgutt
Bei Categories Hierarchy kann man den Debugmodus aktivieren und dann schmeißt er mir unterhalb jeder Seite alle Abfragen aus :D

Verfasst: 16.02.2006 14:24
von Fundus
hab mich damit noch nicht befasst aber hast du eine möglichkeit wirklich nur die benötigten daten zu laden?

im zweifelsfall eben 1-2 zusätzliche abfragen einbauen die eben details auszählen oder was man braucht

problem wird wohl die bestimmung bei der sortierung sein, da müsste man die bestehende abfrage so anlegen das er sich nur die IDs aus der posts raussucht und dann mit diesen die restlichen details ausliest inclusive Joins und was man halt so braucht :roll:

Verfasst: 16.02.2006 20:17
von Gumfuzi
danke! werde ich testen.

Verfasst: 17.02.2006 13:40
von Fundus
und funzt das mit der geteilten abfrage? (zeile ~ 759)

wozu du dabei

if ( $topic_id ) ... else ..

benutzt ist mir nicht nachvollziehbar, das wird kaum ohne gehen, wenn dann

if ( intval($forum_topic_data['topic_replies']) < 30000 )

:D

Verfasst: 17.02.2006 15:17
von mgutt
nein, bei $topic_id stand dann die topic_id von dem spamtopic.

also so:

Code: Alles auswählen

if ( $topic_id != 6311 )
das habe ich nur rückgängig gemacht, damit der else teil gar nicht ausgeführt werden kann. (der else teil war noch lahmer als der original code)

Verfasst: 19.02.2006 17:25
von mgutt
Ok,

ich scheine damit die Version gefunden zu haben, die funktioniert:

Code: Alles auswählen

//
// Go ahead and pull all data for this topic
//
//-- mod : speed up topic ------------------------------------------------------
//-- delete
/*
$sql = "SELECT u.username, u.user_id, u.user_posts, u.user_from, u.user_firstname, u.user_ebayname, u.user_car, u.user_website, u.user_email, u.user_icq, u.user_aim, u.user_yim, u.user_regdate, u.user_msnm, u.user_viewemail, u.user_rank, u.user_sig, u.user_sig_bbcode_uid, u.user_avatar, u.user_avatar_type, u.user_allowavatar, u.user_allowsmile, p.*,  pt.post_text, pt.post_subject, pt.bbcode_uid
	FROM " . POSTS_TABLE . " p, " . USERS_TABLE . " u, " . POSTS_TEXT_TABLE . " pt
	WHERE p.topic_id = $topic_id
		$limit_posts_time
		AND pt.post_id = p.post_id
		AND u.user_id = p.poster_id
	ORDER BY p.post_time ASC
	LIMIT $start, ".$board_config['posts_per_page'];
*/
/*
	$sql = "SELECT pt.post_sub_title, u.username, u.user_id, u.user_posts, u.user_from, u.user_firstname, u.user_ebayname, u.user_car, u.user_website, u.user_email, u.user_icq, u.user_aim, u.user_yim, u.user_regdate, u.user_msnm, u.user_viewemail, u.user_rank, u.user_sig, u.user_sig_bbcode_uid, u.user_avatar, u.user_avatar_type, u.user_allowavatar, u.user_allowsmile, u.user_gender, p.*,  pt.post_text, pt.post_subject, pt.bbcode_uid
		FROM " . POSTS_TABLE . " p, " . USERS_TABLE . " u, " . POSTS_TEXT_TABLE . " pt
		WHERE p.topic_id = $topic_id
			$limit_posts_time
			AND pt.post_id = p.post_id
			AND u.user_id = p.poster_id
		ORDER BY p.post_time ASC
		LIMIT $start, ".$board_config['posts_per_page'];
*/
//-- add
// Pages
$total_pages = ceil($total_replies/$board_config['posts_per_page']); 
$on_page = floor($start / $board_config['posts_per_page']) + 1; 
if ($start > 100 && ($total_replies / 2) < $start) { 
    $reverse = TRUE; 
    $last_page_posts = $total_replies - ($board_config['posts_per_page'] * ($total_pages - 1)); 
}
// Reverse & Post Id's
$p_array = array(); 
if (isset($reverse)) { 
    $limit_string = ($total_pages == $on_page) ? $last_page_posts : ($last_page_posts + ($total_pages - $on_page - 1) * $board_config['posts_per_page'] ).','. $board_config['posts_per_page']; 
    $sql = "SELECT p.post_id FROM " . POSTS_TABLE . " p USE INDEX(topic_n_id) WHERE p.topic_id = $topic_id $limit_posts_time ORDER BY p.post_id DESC LIMIT $limit_string" ; 
} else { 
    $sql = "SELECT p.post_id FROM " . POSTS_TABLE . " p WHERE p.topic_id = $topic_id $limit_posts_time LIMIT $start, " . $board_config['posts_per_page']; 
}
if ( !($result = $db->sql_query($sql)) ) 
{ 
   message_die(GENERAL_ERROR, "Could not obtain post index information.", '', __LINE__, __FILE__, $sql); 
} 
while (list($p_id) = $db->sql_fetchrow($result)) { 
    $p_array[] = $p_id; 
} 
$post_index = implode(",",$p_array);
// Pull the data
$sql = "SELECT pt.post_sub_title, u.username, u.user_id, u.user_posts, u.user_from, u.user_firstname, u.user_ebayname, u.user_car, u.user_website, u.user_email, u.user_icq, u.user_aim, u.user_yim, u.user_regdate, u.user_msnm, u.user_viewemail, u.user_rank, u.user_sig, u.user_sig_bbcode_uid, u.user_avatar, u.user_avatar_type, u.user_allowavatar, u.user_allowsmile, u.user_gender, p.*,  pt.post_text, pt.post_subject, pt.bbcode_uid
   FROM " . POSTS_TABLE . " p, " . USERS_TABLE . " u, " . POSTS_TEXT_TABLE . " pt 
   WHERE p.post_id in ($post_index) 
      AND pt.post_id = p.post_id 
      AND u.user_id = p.poster_id 
   ORDER BY p.post_time $post_time_order";

if ( !($result = $db->sql_query($sql)) )
{
	message_die(GENERAL_ERROR, "Could not obtain post/user information.", '', __LINE__, __FILE__, $sql);
}
Dadurch werden anstatt eine Abfrage zwar zwei gemacht, aber im Ergebnis gewinne ich im Schnitt 3 Sekunden (!!!).

Erst fragt er die ID's ab per:

Code: Alles auswählen

viewtopic.php
Zeile: 785
DB: 0.0003s
 Anfrage 
 SELECT p.post_id FROM phpbb_posts p USE INDEX(topic_n_id) WHERE p.topic_id = 6311 ORDER BY p.post_id DESC LIMIT 1   
  Tabelle     Typ     Mögliche Schlüssel     Benutzter Schlüssel     Schlüssel Länge     Ref.     Zeilen     Kommentar   
  p  
 
und dann holt er sich die Daten:

Code: Alles auswählen

viewtopic.php
Zeile: 801
DB: 0.0004s
 Anfrage 
 SELECT pt.post_sub_title, u.username, u.user_id, u.user_posts, u.user_from, u.user_firstname, u.user_ebayname, u.user_car, u.user_website, u.user_email, u.user_icq, u.user_aim, u.user_yim, u.user_regdate, u.user_msnm, u.user_viewemail, u.user_rank, u.user_sig, u.user_sig_bbcode_uid, u.user_avatar, u.user_avatar_type, u.user_allowavatar, u.user_allowsmile, u.user_gender, p.*, pt.post_text, pt.post_subject, pt.bbcode_uid FROM phpbb_posts p, phpbb_users u, phpbb_posts_text pt WHERE p.post_id in (176663) AND pt.post_id = p.post_id AND u.user_id = p.poster_id ORDER BY p.post_time    
  Tabelle     Typ     Mögliche Schlüssel     Benutzter Schlüssel     Schlüssel Länge     Ref.     Zeilen     Kommentar   
  p     const     PRIMARY,poster_id     PRIMARY     3     const     1        
  u     const     PRIMARY     PRIMARY     3     const     1        
  pt   
Man beachte die Zeiten :D