Strict Standards: Declaration of PluginAceadminpanel_ModuleLang::Get() should be compatible with ModuleLang::Get($sName, $aReplace = Array, $bDelete = true) in /home/deer/pages.org.ua/blog/plugins/aceadminpanel/classes/modules/lang/Lang.class.php on line 21 Strict Standards: Declaration of PluginAceadminpanel_ModuleViewer::_SortBlocks() should be compatible with ModuleViewer::_SortBlocks($a, $b) in /home/deer/pages.org.ua/blog/plugins/aceadminpanel/classes/modules/viewer/Viewer.class.php on line 24 b_cache_tag / Поиск по тегам / BPOU - Bitrix blog

Битрикс подкидывает проблем: 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 запрос. В конечном итоге, скорость выполнения этого запроса очень велика, что полностью нивелирует недостаток.