Тупик сериализации при обновлении в Laravel с одновременными консольными командамиPhp

Кемеровские программисты php общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Тупик сериализации при обновлении в Laravel с одновременными консольными командами

Сообщение Anonymous »

Мне нужна помощь в повышении производительности моего запроса на обновление Laravel 11. Я извлекаю тысячи записей частями из потока Redis 7 и добавляю их в свою базу данных MySQL 8. Это сводная таблица. Это происходит из-за уникального индекса в таблице.
Я добавил новый столбец с именем worker, который я установил в качестве аргумента в своей консольной команде, который смешивается с уникальный индекс, но тем не менее выполнение нескольких консольных команд приводит к ошибке взаимоблокировки сериализации, и я не знаю, чего мне не хватает:

Ошибка сериализации: 1213 Обнаружена тупиковая ситуация при попытке получить блокировку; попробуйте перезапустить транзакцию (Соединение: mysql, SQL: вставить в statistic_aggregates (, Bucket_ends_at, Bucket_starts_at, страна, Create_at, for, modelable_id, modelable_type, период code>, Product, Total_processing_decline_duration, Updated_at, Worker) значения (1736344800, 2025-01-08 14:59:59, 2025-01-08 14:00:00, 1, 2025-01-08 14:42:25, 2, 1, Приложение\Модели\Компания, 60, 1, 2021 , 2025-01-08 14:42:25, 225), (1736294400, 08.01.2025 23:59:59, 08.01.2025 00:00:00, 1, 08.01.2025 14:42:25, 2, 1, Приложение\Модели\Компания , 1440, 1, 2021, 2025-01-08 14:42:25, 225), (1736344800, 2025-01-08 14:59:59, 2025-01-08 14:00:00, 1, 2025-01-08 14:42: 25, 2, 3, Приложение\Модели\Покупатель, 60, 1, 2021, 08.01.2025 14:42:25, 225), (1736294400, 08.01.2025 23:59:59, 08.01.2025 00:00:00 , 1, 08.01.2025 14:42:25, 2, 3, Приложение\Модели\Покупатель, 1440, 1, 2021, 08.01.2025 14:42:25, 225), (1736344800, 08.01.2025 14:59:59, 08.01.2025 14:00:00, 1, 08.01.2025 14:42:25, 2, 7, App\Models\BuyerTier, 60, 1, 2021, 08.01.2025 14:42:25, 225), ( 1736294400, 08.01.2025 23:59:59, 2025-01-08 00:00:00, 1, 2025-01-08 14:42:25, 2, 7, App\Models\BuyerTier, 1440, 1, 2021, 2025-01- 08 14:42:25, 225) при обновлении дубликата ключа total_processing_decline_duration = total_processing_decline_duration + ЗНАЧЕНИЯ(

Код: Выделить всё

total_processing_decline_duration
), update_at = значения(

Код: Выделить всё

updated_at
))"

Я запускаю две консольные команды в двух терминалах, каждый из которых отвечает за получение соответствующих данных идентификатора из потока, каждый это собственный модуль на компакт-диске Argo для более быстрой обработки и выделенного ресурса. Моя схема миграции:

Код: Выделить всё

Schema::create('statistic_aggregate_relations', function (Blueprint $table) {
$table->ulid('id');
$table->tinyInteger('for');
$table->tinyInteger('product');
$table->tinyInteger('country');
$table->integer('worker')->default(1);
$table->unsignedInteger('bucket');
$table->mediumInteger('period')->default(60);
$table->morphs('modelable');
$table->foreignId('company_id')->nullable();
$table->foreignId('affiliate_id')->nullable();
$table->foreignId('affiliate_campaign_id')->nullable();
$table->foreignId('buyer_id')->nullable();
$table->foreignId('buyer_tier_id')->nullable();
$table->char('key_hash', 16)->charset('binary')->virtualAs("
unhex(MD5(CONCAT(
`for`, '',
`product`, '',
`country`, '',
`worker`, '',
`bucket`, '',
`period`, '',
`modelable_type`, '',
`modelable_id`, '',
`company_id`, '',
`affiliate_id`, '',
`affiliate_campaign_id`, '',
`buyer_id`, '',
`buyer_tier_id`, '',
DATE_FORMAT(`bucket_starts_at`, '%Y-%m-%d %H:%i:%s'), '',
DATE_FORMAT(`bucket_ends_at`, '%Y-%m-%d %H:%i:%s')
)))
");

// Default
$table->bigInteger('total_sms_messages_sent')->default(0);
$table->bigInteger('total_sms_messages_delivered')->default(0);
$table->bigInteger('total_sms_messages_opened')->default(0);
$table->bigInteger('total_sms_messages_clicked')->default(0);
$table->bigInteger('total_emails_sent')->default(0);
$table->bigInteger('total_emails_delivered')->default(0);
$table->bigInteger('total_emails_opened')->default(0);
$table->bigInteger('total_emails_clicked')->default(0);
$table->bigInteger('total_sessions')->default(0);
$table->bigInteger('total_submits')->default(0);
$table->bigInteger('total_filtered')->default(0);
$table->bigInteger('total_leads')->default(0);
$table->bigInteger('total_accepted')->default(0);
$table->bigInteger('total_declined')->default(0);
$table->bigInteger('total_invalids')->default(0);
$table->bigInteger('total_timeouts')->default(0);
$table->bigInteger('total_duplicates')->default(0);
$table->bigInteger('total_redirected')->default(0);
$table->bigInteger('total_accepted_redirected')->default(0);
$table->bigInteger('total_other')->default(0);
$table->bigInteger('total_unknown')->default(0);
$table->bigInteger('total_processing_duration')->default(0);
$table->bigInteger('total_processing_accept_duration')->default(0);
$table->bigInteger('total_processing_decline_duration')->default(0);
$table->decimal('total_revenue', 8, 2)->default(0.00);
$table->decimal('total_commission', 8, 2)->default(0.00);
$table->decimal('total_costs', 8, 2)->default(0.00);
$table->decimal('total_profit_or_loss', 8, 2)->default(0.00);
$table->dateTime('bucket_starts_at');
$table->dateTime('bucket_ends_at');
$table->timestamps();

$table->index('company_id');  // For cross report analysis...
$table->index('affiliate_id'); // For cross report analysis...
$table->index('affiliate_campaign_id'); // For cross report analysis...
$table->index('buyer_id'); // For cross report analysis...
$table->index('buyer_tier_id'); // For cross report analysis...

$table->index('bucket_starts_at'); // For date filtering...
$table->index('bucket_ends_at'); // For date filtering...
$table->index('created_at'); // For fast sorting...
$table->index('period'); // For period categorisation...

// For duplicate rows...
$table->unique(['worker', 'key_hash']);
});
Я не буду прикреплять сюда тысячи строк кода, но в циклах while каждой консольной команды upsert извлекает фрагмент и выполняет обновление с помощью следующей функции:

Код: Выделить всё

/**
* Store the entries in storage
*/
private static function store(Collection $items): void
{
$start = microtime(true);

if ($items->isEmpty()) {
self::logDigestRuntime($start);

return;
}

$items->each(function (array $aggregate) {
DB::transaction(function () use ($aggregate) {
try {
$column = Arr::get($aggregate, 'column', 'total_other');

$filteredAggregates = collect(Arr::get($aggregate, 'aggregates', []))->map(function ($aggregate) {
return collect($aggregate)->except([
'company_id', 'affiliate_id', 'affiliate_campaign_id', 'buyer_id', 'buyer_tier_id'
])->toArray();
})->toArray();

$statistic = StatisticAggregate::upsert($filteredAggregates, [
'key_hash'
], [
$column => new Expression("`$column` + VALUES(`$column`)")
]);
} catch (QueryException $err) {
if (config('app.debug')) {
Log::warning('function: store QueryException error', [
'err' => $err->getMessage(),
'file' => $err->getFile(),
'line' => $err->getLine(),
]);
}
} catch (Throwable $err) {
\Sentry\captureException($err);

if (config('app.debug')) {
Log::warning('function: store throwable error', [
'err' => $err->getMessage(),
'file' => $err->getFile(),
'line' => $err->getLine(),
]);
}
}
}, 3);
});

Lottery::odds(1, 2)->winner(fn () => self::logDigestRuntime($start))->choose();
}
Как обойти проблему взаимоблокировки? Я думал, что, сохранив идентификатор работника в столбце, MySQL не будет поднимать здесь суету.
Как мне решить эту проблему?

Подробнее здесь: https://stackoverflow.com/questions/793 ... e-commands
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Php»