Битрикс подкидывает проблем: b_cache_tag занимает много места, сайт тормозит

В версии 12.5 (в 14 возможно исправили, не смотрел ещё), при включенном кешировании компонентов, и большой посещаемости, табличка b_cache_tag начала набирать 15к записей в полчаса, а там одно и тоже, уникальных записей от силы 20. Из-за этого «говна», сайт начал дико тупить, на генерацию страницы уходило по 2 секунды, из-за очень многих инсертов на каждом шагу. Нормальные люди, делают инсерт — если такой записи нет, в битриксе решили не парится и народ везде на форумах, предлагает по крону транкейтить таблицу (это тупо пиздец).

Пришлось переписать функцию «виновника торжества» EndTagCache, запись добавляется только при уникальности составляющих (ибо если её просто отключить, кеширование исходит на говно). Тупой инсерт превратился в умный и красивый

function EndTagCache() {
	global $DB;
	$this->InitCompSalt();

	if($this->bWasTagged) {
		$sqlSITE_ID = $DB->ForSQL(SITE_ID, 2);
		$sqlCACHE_SALT = $this->SALT;

		$strSqlPrefix = "INSERT ".($this->isMySql? "IGNORE": "").
				" INTO b_cache_tag (SITE_ID, CACHE_SALT, RELATIVE_PATH, TAG) VALUES";
		$strSqlPrefix2 = "INSERT ".($this->isMySql? "IGNORE": "").
				" INTO b_cache_tag (SITE_ID, CACHE_SALT, RELATIVE_PATH, TAG) ";

		$maxValuesLen = $this->isMySql? 2048: 0;
		$strSqlValues = $strSqlValues2 = "";

		foreach($this->comp_cache_stack as $arCompCache) {
			$path = $arCompCache[0];
			if(strlen($path)) {
				$this->InitDBCache($path);
				$sqlRELATIVE_PATH = $DB->ForSQL($path, 255);

				$sql = ",\n('".$sqlSITE_ID."', '".$sqlCACHE_SALT."', '".$sqlRELATIVE_PATH."',";
				$sql2 = " SELECT * FROM (SELECT '".$sqlSITE_ID."', '".$sqlCACHE_SALT."', '".$sqlRELATIVE_PATH."', '#TAG#') AS tmp ".
"WHERE NOT EXISTS ( ".
"    SELECT SITE_ID FROM b_cache_tag ".
"    WHERE CACHE_SALT = '".$sqlCACHE_SALT."' ".
"    AND RELATIVE_PATH = '".$sqlRELATIVE_PATH."' ".
"    AND TAG = '#TAG#' ".
") LIMIT 1; \n";

				foreach($arCompCache[1] as $tag => $t) {
					if(!isset($this->DBCacheTags[$path][$tag])) {
						$strSqlValues .= $sql." '".$DB->ForSQL($tag, 50)."')";
						$strSqlValues2 = $strSqlPrefix2.str_replace("#TAG#",$DB->ForSQL($tag, 50), $sql2);
						$DB->Query($strSqlValues2);
						if(strlen($strSqlValues) > $maxValuesLen) {
							//$DB->Query($strSqlPrefix.substr($strSqlValues, 2));
							$strSqlValues = "";
							
						}
						$this->DBCacheTags[$path][$tag] = true;
					}
				}
			}
		}
		if($strSqlValues <> '') {
			//$DB->Query($strSqlPrefix.substr($strSqlValues, 2));
		}
	}

	array_shift($this->comp_cache_stack);
}

В итоге
INSERT IGNORE INTO b_cache_tag (SITE_ID, CACHE_SALT, RELATIVE_PATH, TAG) 
VALUES('ar', '/e25', '/ar/bitrix/news.list/06f', 'iblock_id_5')

Превращается в
INSERT IGNORE INTO b_cache_tag (SITE_ID, CACHE_SALT, RELATIVE_PATH, TAG)  
SELECT * FROM (SELECT 'ar', '/e25', '/ar/bitrix/news.list/06f', 'iblock_id_5') AS tmp 
WHERE NOT EXISTS (
     SELECT SITE_ID FROM b_cache_tag
     WHERE CACHE_SALT = '/e25'
     AND RELATIVE_PATH = '/ar/bitrix/news.list/06f'
     AND TAG = 'iblock_id_5' ) 
LIMIT 1;


У новой функции есть один недостаток, она выполняется в цикле каждый раз (хотя циклов больше двух я не видел), тогда как старая группирует инсерты в 1 запрос. В конечном итоге, скорость выполнения этого запроса очень велика, что полностью нивелирует недостаток.
  • 0
  • 14 февраля 2014, 17:45
  • admin

Комментарии (0)

RSS свернуть / развернуть
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.