Перейти к контенту
  • 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.

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

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

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

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить на вопрос...

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

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

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

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

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

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

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

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