Перейти к контенту
  • 0

Раздельное хранение информации (sql и файлы)


FatCat

Вопрос

Достали тормоза при разрастании таблиц ibf_posts, ibf_jposts и ibf_jcomments; достал лимит sql, не позволяющий создавать сообщения свыше 64 Кб.

 

Мод распределяет сообщения: Сообщения свыше 4000 байт сохраняются в файл, сообщения мЕньшего веса - в sql-таблицы.

 

 

В корне форума создать директорию /arc, права доступа не ниже 0666.

 

 

functions.php

Добавились 2 функции:

	function extract_archived_post($pid, $j_type)
{
	$arc_path = ($pid-$pid%1000)/1000;
	$arc_path = "arc/".$arc_path."/";
	$arc_file = $pid%1000;
	$arc_file = $arc_path.$arc_file.".".$j_type;
	if(is_writeable( $arc_file ))
	{
		@ob_start();
		include( $arc_file );
		$archived_post = @ob_get_contents();
		@ob_end_clean();
	}
	else
	{
		$archived_post = "";
	}


	return $archived_post;
}

function create_archived_post($pid, $j_type, $txt)
{
	$arc_path = ($pid-$pid%1000)/1000;
	$arc_path = "arc/".$arc_path."/";
	$arc_file = $pid%1000;
	$arc_file = $arc_path.$arc_file.".".$j_type;
	if(file_exists($arc_file))unlink($arc_file);
	if($txt != "")
	{
		if(!file_exists($arc_path))mkdir($arc_path, 0777);
		$fh = fopen($arc_file, "w");
		fwrite($fh, $txt);
		fclose($fh);
	}
}

 

 

Теперь разносим вызовы этих функций.

Каждый раз проверяем, объявлена ли $std, и если не объявлена, объявляем.

Topics.php

Только у тех, у кого стоит oska мод фиксации первого поста:

После

// start oska modified

	if ($first > 0 and $this->topic['firstpost'] == 1) {
	$DB->query( "SELECT p.*,
				m.id,m.name,m.mgroup,m.email,m.joined,m.avatar,m.avatar_size,m.posts,m.aim_
name,m.icq_number,
				m.signature, m.website,m.yahoo,m.title,m.hide_email,m.msnname,m.dices,
				g.g_id, g.g_title, g.g_icon
				FROM ibf_posts p
				  LEFT JOIN ibf_members m ON (p.author_id=m.id)
				  LEFT JOIN ibf_groups g ON (g.g_id=m.mgroup)
				WHERE p.topic_id='".$this->topic['tid']."' and p.queued !='1'
				ORDER BY p.pid LIMIT 0, 1");

	$cached_members0 = array();
while ( $row0 = $DB->fetch_row() ) {

добавить

			if( strlen($row0['post'])<3 or ( stristr($row0['post'], "#TOPIC#") and strlen($row0['post'])<26 ) or ( stristr($row0['post'], "#POST#") and strlen($row0['post'])<26 ) )$row0['post'] = $std->extract_archived_post($row0['pid'], "arc");

 

Для всех:

После

	$cached_members = array();

	//-------------------------------------
	// Format and print out the topic list
	//-------------------------------------

	$post_count = 0;  // Use this as our master bater, er... I mean counter.

	while ( $row = $DB->fetch_row() )
	{

добавить:

			if( strlen($row['post'])<3 or ( stristr($row['post'], "#TOPIC#") and strlen($row['post'])<26 ) or ( stristr($row['post'], "#POST#") and strlen($row['post'])<26 ) )$row['post'] .= $std->extract_archived_post($row['pid'], "arc");

 

 

Post.php

После

		//--------------------------------------------------------------
	// Get the posts
	// This section will probably change at some point
	//--------------------------------------------------------------

	$post_query = $DB->query("SELECT post, pid, post_date, author_id, author_name FROM ibf_posts WHERE topic_id=$topic_id and queued <> 1 ORDER BY pid DESC LIMIT 0,10");

	while ( $row = $DB->fetch_row($post_query) )
	{

		$row['author'] = $row['author_name'];

		$row['date']   = $std->get_date( $row['post_date'], 'LONG' );

добавить

			if ( strlen($row['post']) < 3 )$row['post'] = $std->extract_archived_post($row['pid'], "arc");

 

 

 

Profile.php (тем, у кого стоит мод последних сообщений в профиле)

После

$DB->query("SELECT p.pid, p.post, t.tid, t.title, f.name, f.id
		FROM ibf_posts AS p LEFT JOIN ibf_topics AS t ON (p.topic_id=t.tid) LEFT JOIN ibf_forums AS f ON(t.forum_id=f.id)
		WHERE author_id=".$member['id']." AND f.id IN ($forums)
		ORDER BY p.post_date DESC LIMIT 0,".$INFO[latest_amount]);

while($row = $DB->fetch_row()) {

Добавить:

			if ( strlen($row['post']) < 3 )$row['post'] = $std->extract_archived_post($row['pid'], "arc");

 

 

Search.php

После

			$DB->query("SELECT t.*, p.pid, p.author_id, p.author_name, p.hide_post, p.post_date, p.post, f.id as forum_id, f.name as forum_name, f.use_html, g.g_dohtml
						FROM ibf_posts p
						  LEFT JOIN ibf_topics t ON (t.tid=p.topic_id)
						  LEFT JOIN ibf_forums f ON (f.id=p.forum_id)
						  LEFT JOIN ibf_members m ON (m.id=p.author_id)
						  LEFT JOIN ibf_groups g ON (m.mgroup=g.g_id)
						WHERE hide_post=0 AND p.pid IN(0{$posts}0)
						ORDER BY p.post_date DESC
						LIMIT ".$this->first.",25");


		while ( $row = $DB->fetch_row() )
		{

добавить

			if ( strlen($row['post']) < 3 )$row['post'] = $std->extract_archived_post($row['pid'], "arc");

 

 

modfunctions.php

После

	while ( $r = $DB->fetch_row() )
{
	if($r['attach_id'] != "")
	{
		if (is_file($this->upload_dir."/".$r['attach_id']))
		{
			@unlink ($this->upload_dir."/".$r['attach_id']);
		}
	}

добавить

		if( strlen($r['post']) < 3 or stristr($r['post'], "#TOPIC#") or stristr($r['post'], "#POST#") )$std->create_archived_post($r['pid'], "arc", "");

 

 

 

post_edit_post.php

После

		//-------------------------------------------------
	// Load the old post
	//-------------------------------------------------

	$DB->query("SELECT * FROM ibf_posts WHERE pid=".intval($ibforums->input['p']));
	$this->orig_post = $DB->fetch_row();

	if (! $this->orig_post['pid'])
	{
		$std->Error( array( LEVEL => 1, MSG => 'missing_files') );
	}

добавить

		if(strlen($this->orig_post['post'])<3)$this->orig_post['post'] = $std->extract_archived_post($this->orig_post['pid'], "arc");

 

 

После

	//-------------------------------------------------
	// Update the database (ib_forum_post)
	//-------------------------------------------------

	$this->post['append_edit'] = 1;

	if ($ibforums->member['g_append_edit'])
	{
		if ($ibforums->input['add_edit'] != 1)
		{
			$this->post['append_edit'] = 0;
		}
	}

добавить

		if (strlen( $this->post['post'] ) > 4000 )
	{
		$std->create_archived_post($this->orig_post['pid'], "arc", $this->post['post']);
		$this->post['post'] = "";
	}
	else
	{
		$std->create_archived_post($this->orig_post['pid'], "arc", "");
	}

 

 

post_new_post.php

Здесь я добавленный код пометил комментариями:

		//-------------------------------------------------
	// Unqueue the post if we're starting a new topic
	//-------------------------------------------------

	if ( $class->obj['moderate'] == 3 )
	{
		$this->post['queued'] = 0;
	}

// +FatCat Проверка размера сообщения: большие сразу архивируем.
$arc_poct_str = "";
if(strlen($this->post['post']) > 4000)
{
$arc_poct_str = $this->post['post'];
$this->post['post'] = " ";
}
// -FatCat

	$db_string = $DB->compile_db_insert_string( $this->post );

	$DB->query("INSERT INTO ibf_posts (" .$db_string['FIELD_NAMES']. ") VALUES (". $db_string['FIELD_VALUES'] .")");

	$this->post['pid'] = $DB->get_insert_id();

// +FatCat: архивируем большие сообщения: пишем файл.
if($arc_poct_str != "")$std->create_archived_post($this->post['pid'], "arc", $arc_poct_str);
// -FatCat

 

 

post_q_reply_post.php

После

	//-------------------------------------------------
	// Get the old post
	//-------------------------------------------------

	$DB->query("SELECT post, author_id, author_name, post_date, pid FROM ibf_posts WHERE pid='".$ibforums->input['p']."'");
	$this->quoted_post = $DB->fetch_row();

добавить

		//-------------------------------------------------
	// Выковыриваем архивированное
	//-------------------------------------------------

	if(strlen($this->quoted_post['post'])<3)$this->quoted_post['post'] = $std->extract_archived_post($this->quoted_post['pid'], "arc");

 

 

 

post_reply_post.php

Мои добавления помечены комментариями:

// +FatCat Проверка размера сообщения: большие сразу архивируем.
$arc_poct_str = "";
if(strlen($this->post['post']) > 4000)
{
$arc_poct_str = $this->post['post'];
$this->post['post'] = " ";
}
// -FatCat

	$db_string = $DB->compile_db_insert_string( $this->post );

	$DB->query("INSERT INTO ibf_posts (" .$db_string['FIELD_NAMES']. ") VALUES (". $db_string['FIELD_VALUES'] .")");

	$this->post['pid'] = $DB->get_insert_id();

// +FatCat: архивируем большие сообщения; пишем файл.
if($arc_poct_str != "")$std->create_archived_post($this->post['pid'], "arc", $arc_poct_str);
// -FatCat

	if ( $class->obj['moderate'] == 1 or $class->obj['moderate'] == 3 )
	{
		$DB->query("UPDATE ibf_forums SET has_mod_posts=1 WHERE id=".$class->forum['id']);

		$page = floor( ($this->topic['posts'] + 1) / $ibforums->vars['display_max_posts']);
		$page = $page * $ibforums->vars['display_max_posts'];

		$print->redirect_screen( $ibforums->lang['moderate_post'], "showtopic={$this->topic['tid']}&st=$page" );
	}

 

 

print_page.php

После

			$row['post_css'] = $td_col_count % 2 ? 'post1' : 'post2';

		++$td_col_count;

добавить

			if(strlen($row['post'])<3)$row['post'] = $std->extract_archived_post($row['pid'], "arc");

 

 

journal\calendar.php

После

		$DB->query("SELECT p.*, me.j_public, me.id, m.name
				FROM ibf_jposts p
				LEFT JOIN ibf_member_extra me ON (me.id=p.journal_id)
				LEFT JOIN ibf_members m ON (m.id=p.journal_id)
				WHERE p.post_date > '".$db_start_date."'
				AND p.post_date < '".$db_end_date."'".$q_extra."
				ORDER BY p.post_date DESC LIMIT ".$first.",15");

	if ($DB->get_num_rows())
	{
		$old_date = "";
		$start_post = true;
		while ($r = $DB->fetch_row())
		{

добавить

				if(strlen($r['post'])<3)$r['post'] = $std->extract_archived_post($r['pid'], "jpc");

 

После

				if ($r['author_id'] > 0)
				{
					$r['author'] = "<a style='text-decoration:none' href='".$ibforums->base_url."showuser=".$r['author_id']."'>".$r['author_name']."</a>";
				}
				else
				{
					$r['author'] = "<span style='color:AA3300'>".$r['author_name']."</span>";
				}

добавить

					if(strlen($r['post'])<3)$r['post'] = $std->extract_archived_post($r['cid'], "jcc");

 

 

 

comment.php

После

if ($ibforums->member['id'])
{
$post['lnk_track'] = "| <a href=\"".$journal->base_url."user=".$ibforums->member['id']."&doset=07&pid=".$post['pid']."\">".$ibforums->lang['j_track_btn']."</a> |";
}

$post['attachment'] = $posting->get_attachment($post);

добавить

if(strlen($post['post'])<3)$post['post'] = $std->extract_archived_post($post['pid'], "jpc");

 

После

			// Output comments for this post
		$DB->query("SELECT * FROM ibf_jcomments WHERE post_id='".$post['pid']."' ORDER BY post_date ASC LIMIT $first,".$journal->users['j_comment_page']);

		if (!$DB->get_num_rows())
		{
			$journal->out_data['pages'] .= $this->html->j_info($ibforums->lang['j_err_no_comments'])."<br />";
		}
		else
		{
			$journal->out_data['pages'] .= $this->html->j_post_top();
			while ($row = $DB->fetch_row())
			{

добавить

				if(strlen($row['post'])<3)$row['post'] = $std->extract_archived_post($row['cid'], "jcc");

 

Здесь мои вставки промечены комментариями:

		// Make comment array
	$rpost = $this->compile_comment();
// +FatCat большие в кеш - проверяем
if( strlen($rpost['post']) > 4000 )
{
$cached_post = $rpost['post'];
$rpost['post'] = " ";
}
else
{
$cached_post = "";
}
// -FatCat
	$rpost['post_id']	 = $ibforums->input['comm'];
	$rpost['owner_id']	= $journal->users['id'];
	$rpost['post_date']   = time();
	$rpost['author_id']   = $ibforums->member['id'] ? $ibforums->member['id'] : -1;
	$rpost['author_name'] = $ibforums->member['id'] ? $ibforums->member['name'] : $ibforums->input['UserName'];

	// Add comment to database
	$db_string = $DB->compile_db_insert_string( $rpost );
	$DB->query("INSERT INTO ibf_jcomments (" .$db_string['FIELD_NAMES']. ") VALUES (". $db_string['FIELD_VALUES'] .")");
	$rpost['cid'] = $DB->get_insert_id();
$std->create_archived_post($rpost['cid'], "jcc", $cached_post);

 

После

	// Get post
	$DB->query("SELECT c.*, p.post_date as p_date
				FROM ibf_jcomments c, ibf_jposts p
				WHERE c.cid='".$ibforums->input['comm']."' AND p.pid = c.post_id");

	if (!$DB->get_num_rows())
	{
		$journal->err_journal($ibforums->lang['j_err_data']);
	}

	$row = $DB->fetch_row();

добавить

		if(strlen($row['post'])<3)$row['post'] = $std->extract_archived_post($row['cid'], "jcc");

 

Здесь мои вставки промечены комментариями:

		// Make base post array
	$rpost = $this->compile_comment();

	// If upload preset delete old and add new to post array
	if ($rpost['attach_id'] != "")
	{
		$journal->del_uploaded($row['attach_id']);
	}
	// If select "delete attach", delete file and clear post attach array
	elseif ($ibforums->input['DEL_ATTACH'] == "yes")
	{
		$journal->del_uploaded($row['attach_id']);
		$rpost['attach_id'] = "";
	}
// +FatCat большие - в кеш
if( strlen($rpost['post']) > 4000 )
{
$cached_post = $rpost['post'];
$rpost['post'] = " ";
}
else
{
$cached_post = "";
}
$std->create_archived_post($ibforums->input['comm'], "jcc", $cached_post);
// -FatCat

 

После

		// Delete attachment
	if ($row['attach_id'])
	{
		$journal->del_uploaded($row['attach_id']);
	}

	// Delete comment
	$DB->query("DELETE FROM ibf_jcomments WHERE cid='".$ibforums->input['comm']."'");

добавить

		// Update comment statistics
	$this->update_comment_stats($row['post_id']);

	$journal->redirect_screen($ibforums->lang['j_redir_del'],$journal->base_url."user=".$journal->users['id']."&comm=".$row['post_id']);
}

 

 

 

journal\posts.php

Перед

	// show image ?
if (!$journal->users['j_show_img'])
{
	$row['post'] = preg_replace( "#<!--emo&(.+?)-->.+?<!--endemo-->#", "\\1" , $row['post']);
	$row['post'] = preg_replace( "/<img src=[\"'](.+?)[\"'].+?".">/", "<br />".$ibforums->lang['j_image']." <a href='\\1' target='_blank'>\\1</a><br />", $row['post'] );
}

// word wrap

добавить

	if(strlen($row['post'])<3)$row['post'] = $std->extract_archived_post($row['pid'], "jpc");

Здесь мои добавки размечены комментариями:

		// make post array
	$rpost = $this->compile_post();
	$rpost['journal_id'] = $journal->users['id'];
	$rpost['author_id'] = $ibforums->member['id'];
	$rpost['author_name'] = $ibforums->member['name'];
	$rpost['post_date'] = time();
	$rpost['comments']  = 0;
// +FatCat большие в кеш - проверяем
if( strlen($rpost['post']) > 4000 )
{
$cached_post = $rpost['post'];
$rpost['post'] = " ";
}
else
{
$cached_post = "";
}
// -FatCat
	// Add post to database
	$db_string = $DB->compile_db_insert_string( $rpost );
	$DB->query("INSERT INTO ibf_jposts (" .$db_string['FIELD_NAMES']. ") VALUES (". $db_string['FIELD_VALUES'] .")");
	$rpost['pid'] = $DB->get_insert_id();
$std->create_archived_post($rpost['pid'], "jpc", $cached_post);
	// check tracker
	$journal->check_post_tracker($rpost['pid']);

 

После

		// save title
	$title = $row['title'];
	$row['title'] = "<a style='text-decoration:none' href=\"".$journal->base_url."user=".$journal->users['id'].$post_count."#p".$row['pid']."\">".$row['title']."</a>";

добавить

		if(strlen($row['post'])<3)$row['post'] = $std->extract_archived_post($row['pid'], "jpc");

 

Здесь мои вставки размечены комментариями:

		// make post array
	$rpost = $this->compile_post();

	// If upload presets delete old attach and add new to post array
	if ($rpost['attach_id'] != "")
	{
		$DB->query("SELECT attach_id FROM ibf_jposts WHERE pid='".$ibforums->input['pid']."'");
		$row = $DB->fetch_row();
		$journal->del_uploaded($row['attach_id']);
	}
	// If select "delete attach", delete file and clear post attach array
	elseif ($ibforums->input['DEL_ATTACH'] == "yes")
	{
		$DB->query("SELECT attach_id FROM ibf_jposts WHERE pid='".$ibforums->input['pid']."'");
		$row = $DB->fetch_row();
		$journal->del_uploaded($row['attach_id']);
		$rpost['attach_id'] = "";
	}
// +FatCat большие - в кеш
if( strlen($rpost['post']) > 4000 )
{
$cached_post = $rpost['post'];
$rpost['post'] = " ";
}
else
{
$cached_post = "";
}
$std->create_archived_post($ibforums->input['pid'], "jpc", $cached_post);
// -FatCat
	// Update database

 

После

	// Delete post and comments attachments
	if ($row['attach_id'])
	{
		$journal->del_uploaded($row['attach_id']);
	}

	$DB->query("SELECT * FROM ibf_jcomments WHERE post_id='".$ibforums->input['pid']."'");
	while ($row = $DB->fetch_row())
	{

добавить

			if(strlen($row['post'])<3)$std->create_archived_post($row['cid'], "jcc", "");

 

После

	// Delete post and comments
	$DB->query("DELETE FROM ibf_jcomments WHERE post_id='".$ibforums->input['pid']."'");
	$DB->query("DELETE FROM ibf_jposts WHERE pid='".$ibforums->input['pid']."' AND journal_id='".$journal->users['id']."'");

добавить

		// Удаляем архивированное
	$std->create_archived_post($ibforums->input['pid'], "jpc", "");

 

 

 

prints.php

После

	// Print journal post with comment
function print_post($post=array())
{
	global $ibforums, $DB, $journal, $std;

добавить

		if(strlen($post['post'])<3)$post['post'] = $std->extract_archived_post($post['pid'], "jpc");

 

После

	// Output comments for this post
	$DB->query("SELECT * FROM ibf_jcomments WHERE post_id='".$post['pid']."' ORDER BY post_date ASC LIMIT 0,200");

	if (!$DB->get_num_rows())
	{
		$out_data .= $this->html->j_info($ibforums->lang['j_err_no_comments'])."<br />";
	}
	else
	{
		$out_data .= $this->html->j_post_top();
		while ($row = $DB->fetch_row())
		{

добавить

				if(strlen($row['post'])<3)$row['post'] = $std->extract_archived_post($row['cid'], "jcc");

 

 

 

txt\index.php

После

	$DB->query("SELECT p.* , m.id, m.signature
			FROM ibf_posts p, ibf_members m
			WHERE topic_id={$id} AND queued <> 1 AND m.id = p.author_id
			ORDER BY pid
			LIMIT {$st}, {$ibforums->vars['display_max_posts']}");


	while( $r = $DB->fetch_row() )
	{

добавить

				if ( strlen($r['post']) < 3 )$r['post'] = $std->extract_archived_post($r['pid'], "arc");

 

 

 

 

Не помню, было ли в исходном коде удаление пользователя вместе со всеми сообщениями, но если было - собственно, вот тут добавилось:

ad_member.php

Перед

			if($mem['posts'] == '0')
			{
			$del_full_topics .= $mem['tid'].",";
			$del_full_topics_counter++;
			}
		else
			{
			if($del_topics_counter != $mem['tid'])
				{
				$del_topics .= "|".$del_posts_in_topic.", ".$mem['tid'];
				$del_posts_in_topic = 1;
				}
			else
				{
				$del_posts_in_topic++;
				}
			$del_topics_counter = $mem['tid'];
			}
	}

добавить

			$arc_path = ($mem['pid']-$mem['pid']%1000)/1000;
		$arc_path = intval($arc_path)."/";
		$arc_file = $mem['pid']%1000;
		$arc_file = intval($arc_file).".arc";
		if (is_file("arc/".$arc_path.$arc_file))
			{
			unlink ("arc/".$arc_path.$arc_file);
			}

 

 

 

 

В админцентре в глобальных настройках выставить желаемый лимит размера сообщений, желательно не выше 1000 Кб, иначе могут "Войну и мир" в один пост упихнуть. :D

 

 

 

 

Что недоделано: Удаление файлов сообщений и комментариев журнала при удалении пользователей через админку.

Я не часто удаляю активно пишущих пользователей, поэтому пока не заморачивался.

Ссылка на комментарий
Поделиться на других сайтах

Рекомендуемые сообщения

  • 0
достал лимит sql, не позволяющий создавать сообщения свыше 64 Кб.

Гм.. дык поменял бы тип поля на LONGTEXT и будет 2 млн символов..

Ссылка на комментарий
Поделиться на других сайтах

  • 0

Спасибо!

Но все равно, есть смысл выносить большие сообщения в файлы.

Тестировал как-то давно под довольно слабым сервером на 5 Мб оперативы, вот результат:

При открытии топика (15 постов).

Все посты до 4 Кб - время генерации страницы 0,5-0,7 сек.

Все посты 4-10 Кб - 1-2 сек.

1 пост 64 Кб, остальные до 4 - 3-5 сек.

2 поста по 64 Кб, остальные до 4 - 5-10 сек.

3 поста по 64 Кб - белая страница, в эррорлоге ексцид мемори или таймаут (sql на той же машине, что и php).

 

Сейчас сервер помощней и оперативы побольше, но все равно есть разница, держит сервер беспроблемно 50-100 одновременных посетителей или 500-1000.

Ссылка на комментарий
Поделиться на других сайтах

Присоединиться к обсуждению

Вы можете ответить сейчас, а зарегистрироваться позже. Если у вас уже есть аккаунт, войдите, чтобы ответить от своего имени.

Гость
Ответить на вопрос...

×   Вы вставили отформатированный текст.   Удалить форматирование

  Допустимо не более 75 смайлов.

×   Ваша ссылка была автоматически заменена на медиа-контент.   Отображать как ссылку

×   Ваши публикации восстановлены.   Очистить редактор

×   Вы не можете вставить изображения напрямую. Загрузите или вставьте изображения по ссылке.

Зарузка...
×
×
  • Создать...

Важная информация

Находясь на нашем сайте, вы соглашаетесь на использование файлов cookie, а также с нашим положением о конфиденциальности Политика конфиденциальности и пользовательским соглашением Условия использования.