Главная/Статьи/Битрикс24: очистка таблиц модуля socialnetwork

Битрикс24: очистка таблиц модуля socialnetwork

Автоматическая очистка устаревших записей социальной сети в Битрикс24. Метод ClearOld, cron-задача и оптимизация базы данных.

ДМ
Дмитрий Мещеряков
📅 23 января 2025 г.📖 5 мин чтения

Живая лента в Битрикс24 — самая быстрорастущая подсистема портала. Каждое действие сотрудника, каждый комментарий, каждое изменение задачи оставляет запись, а вместе со связями по правам доступа одна запись превращается в несколько строк в разных таблицах.

На портале, работающем несколько лет, это десятки миллионов строк — и заметное замедление всего, что обращается к ленте. Разберём штатный способ чистки и то, как применять его, не уронив портал.

Проблема

Модуль socialnetwork в Битрикс24 накапливает огромное количество записей в таблицах:

  • b_sonet_log — лента новостей
  • b_sonet_log_comment — комментарии
  • b_sonet_log_site — привязка к сайтам
  • b_sonet_log_right — права доступа

Со временем эти таблицы разрастаются до миллионов записей, замедляя работу портала.

Решение: метод ClearOld

Битрикс предоставляет встроенный метод CSocNetLog::ClearOld() для очистки устаревших записей. Использовать штатный метод здесь принципиально: связи между таблицами ленты неочевидны, и ручной DELETE FROM b_sonet_log оставит осиротевшие записи в b_sonet_log_comment, b_sonet_log_right и b_sonet_log_site — то есть мусор, который уже ничем не вычистить, потому что связать его не с чем.

php
// Удаляет записи старше 90 дней
CSocNetLog::ClearOld(90);

// Удаляет записи старше 30 дней
CSocNetLog::ClearOld(30);

Как работает метод

php
public static function ClearOld($days = 90)
{
    global $DB;

    $days = (int)$days;
    if ($days <= 0) {
        return true;
    }

    // Удаляем комментарии к старым записям
    $DB->Query("
        DELETE LC FROM b_sonet_log_comment LC 
        INNER JOIN (
            SELECT L.TMP_ID FROM b_sonet_log L 
            LEFT JOIN b_sonet_log_favorites LF ON L.ID = LF.LOG_ID 
            WHERE LF.USER_ID IS NULL 
            AND L.LOG_UPDATE < DATE_SUB(NOW(), INTERVAL {$days} DAY)
        ) L1 ON LC.LOG_ID = L1.TMP_ID
    ", true);
    
    // Удаляем привязки к сайтам
    $DB->Query("
        DELETE LS FROM b_sonet_log_site LS 
        INNER JOIN (
            SELECT L.ID FROM b_sonet_log L 
            LEFT JOIN b_sonet_log_favorites LF ON L.ID = LF.LOG_ID 
            WHERE LF.USER_ID IS NULL 
            AND L.LOG_UPDATE < DATE_SUB(NOW(), INTERVAL {$days} DAY)
        ) L1 ON LS.LOG_ID = L1.ID
    ", true);
    
    // Удаляем права
    $DB->Query("
        DELETE LR FROM b_sonet_log_right LR 
        INNER JOIN (
            SELECT L.ID FROM b_sonet_log L 
            LEFT JOIN b_sonet_log_favorites LF ON L.ID = LF.LOG_ID 
            WHERE LF.USER_ID IS NULL 
            AND L.LOG_UPDATE < DATE_SUB(NOW(), INTERVAL {$days} DAY)
        ) L1 ON LR.LOG_ID = L1.ID
    ", true);

    // Удаляем сами записи ленты
    return $DB->Query("
        DELETE FROM b_sonet_log 
        WHERE LOG_UPDATE < DATE_SUB(NOW(), INTERVAL {$days} DAY)
    ", true);
}
💡 Совет

Важно: Метод НЕ удаляет записи, добавленные в избранное (b_sonet_log_favorites). Это защищает важные для пользователей записи.

⚠️ Важно

Первый запуск на портале, который никогда не чистили, — самый опасный. Метод удалит всё накопленное за годы одной операцией: миллионы строк, длительные блокировки, разросшийся журнал транзакций и портал, не отвечающий на запросы всё это время.

Безопасный подход — заходить сверху и постепенно: сначала ClearOld(1095) (три года), убедиться, что портал жив и объём уменьшился, затем ClearOld(730), затем ClearOld(365). Каждый шаг удаляет ощутимо меньше предыдущего, и ни один не создаёт пиковой нагрузки.

И обязательно — на копии базы сначала. Не ради проверки корректности метода (он штатный), а чтобы измерить, сколько операция реально занимает на ваших объёмах.

Автоматизация через cron

Создайте файл /local/cron/cleanup_socialnetwork.php:

php
<?php
/**
 * Очистка таблиц socialnetwork
 * Запуск: 0 3 * * 0 php /home/bitrix/www/local/cron/cleanup_socialnetwork.php
 */

$_SERVER["DOCUMENT_ROOT"] = realpath(dirname(__FILE__) . "/../..");
$DOCUMENT_ROOT = $_SERVER["DOCUMENT_ROOT"];

// Отключаем лишнюю логику
define("NO_KEEP_STATISTIC", true);
define("NOT_CHECK_PERMISSIONS", true);
define("NO_AGENT_CHECK", true);
define("DisableEventsCheck", true);

require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");

// Увеличиваем лимиты для тяжёлой операции
ini_set('ignore_user_abort', 1);
ini_set('max_execution_time', 3600);
ini_set('memory_limit', '1024M');
set_time_limit(3600);

if (!\Bitrix\Main\Loader::includeModule('socialnetwork')) {
    die('Ошибка: не удалось подключить модуль socialnetwork');
}

$startTime = microtime(true);

// Очищаем записи старше 90 дней
$result = CSocNetLog::ClearOld(90);

$executionTime = round(microtime(true) - $startTime, 2);

// Логируем результат
$logMessage = date('Y-m-d H:i:s') . " - Очистка socialnetwork завершена за {$executionTime} сек.\n";
file_put_contents(
    $_SERVER["DOCUMENT_ROOT"] . "/local/logs/cleanup_socialnetwork.log",
    $logMessage,
    FILE_APPEND
);

echo $logMessage;

Настройка cron

bash
# Запуск каждое воскресенье в 3:00
0 3 * * 0 /usr/bin/php /home/bitrix/www/local/cron/cleanup_socialnetwork.php >> /home/bitrix/www/local/logs/cron.log 2>&1

Дополнительная оптимизация

После массового удаления рекомендуется оптимизировать таблицы:

sql
OPTIMIZE TABLE b_sonet_log;
OPTIMIZE TABLE b_sonet_log_comment;
OPTIMIZE TABLE b_sonet_log_site;
OPTIMIZE TABLE b_sonet_log_right;

Скрипт полной оптимизации

php
<?php
// После ClearOld выполняем оптимизацию
global $DB;

$tables = [
    'b_sonet_log',
    'b_sonet_log_comment',
    'b_sonet_log_site',
    'b_sonet_log_right',
];

foreach ($tables as $table) {
    $DB->Query("OPTIMIZE TABLE {$table}");
    echo "Оптимизирована таблица: {$table}\n";
}

Мониторинг размера таблиц

sql
SELECT 
    table_name AS 'Таблица',
    ROUND(data_length / 1024 / 1024, 2) AS 'Данные (MB)',
    ROUND(index_length / 1024 / 1024, 2) AS 'Индексы (MB)',
    table_rows AS 'Строки'
FROM information_schema.tables
WHERE table_schema = DATABASE()
AND table_name LIKE 'b_sonet_log%'
ORDER BY data_length DESC;

Итоги

Чистить ленту нужно, и лучше регулярно. Ежедневное удаление небольшого объёма не создаёт нагрузки; разовая операция над данными за пять лет требует окна обслуживания.

Только штатным методом. Ручной DELETE по одной таблице оставляет мусор в связанных, и убрать его потом нечем.

Первый запуск — ступенями сверху вниз, а не сразу целевым значением.

Срок хранения — вопрос к бизнесу, а не к разработчику. Лента содержит рабочую переписку и историю обсуждений; 90 дней подходят большинству компаний, но узнать это нужно до удаления, а не после.

После чистки место на диске не освободится само — потребуется перестройка таблиц, а это отдельная операция с блокировкой записи, которую планируют в окно минимальной нагрузки.

⚠️ Важно

Перед первым запуском на боевом сервере — обязательно копия базы и прогон на ней. Нужно знать не только что метод отработает, но и сколько времени это займёт на ваших объёмах: разница между «пять минут» и «два часа» полностью меняет план работ.

🚀

Хотите такое же решение?

Настрою окружение под ваш проект, учту специфику инфраструктуры и обучу команду.

Обсудить проект →
Бесплатная консультация · Ответ в течение дня

Комментарии

Система комментариев скоро будет подключена. А пока вы можете написать мне в Telegram или на email.