fix stat_user unique key with record_type and deduplicate before index

This commit is contained in:
yinjianm
2026-02-26 04:39:42 +08:00
parent 87e547d2f1
commit 1e291f8408
2 changed files with 44 additions and 4 deletions
+2 -2
View File
@@ -129,7 +129,7 @@ class StatUserJob implements ShouldQueue
'created_at' => time(),
'updated_at' => time(),
],
['user_id', 'server_rate', 'server_id', 'server_type', 'record_at'],
['user_id', 'server_rate', 'server_id', 'server_type', 'record_at', 'record_type'],
[
'u' => DB::raw("u + VALUES(u)"),
'd' => DB::raw("d + VALUES(d)"),
@@ -152,7 +152,7 @@ class StatUserJob implements ShouldQueue
$sql = "INSERT INTO {$table} (user_id, server_rate, server_id, server_type, record_at, record_type, u, d, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (user_id, server_rate, server_id, server_type, record_at)
ON CONFLICT (user_id, server_rate, server_id, server_type, record_at, record_type)
DO UPDATE SET
u = {$table}.u + EXCLUDED.u,
d = {$table}.d + EXCLUDED.d,
@@ -28,17 +28,19 @@ return new class extends Migration {
}
});
$this->mergeDuplicateRows();
$this->dropUniqueIfExists(self::TABLE, self::OLD_UNIQUE_INDEX);
$this->dropIndexIfExists(self::TABLE, self::OLD_COMPOSITE_INDEX);
$this->addUniqueIfNotExists(
self::TABLE,
['user_id', 'server_rate', 'server_id', 'server_type', 'record_at'],
['user_id', 'server_rate', 'server_id', 'server_type', 'record_at', 'record_type'],
self::NEW_UNIQUE_INDEX
);
$this->addIndexIfNotExists(
self::TABLE,
['user_id', 'server_id', 'server_type', 'record_at'],
['user_id', 'server_id', 'server_type', 'record_at', 'record_type'],
self::NEW_COMPOSITE_INDEX
);
$this->addIndexIfNotExists(self::TABLE, ['server_id'], self::NEW_SERVER_ID_INDEX);
@@ -132,4 +134,42 @@ return new class extends Migration {
default => false,
};
}
/**
* Merge historical duplicates before adding the new unique index.
* Duplicate criteria is aligned with the new unique key columns.
*/
private function mergeDuplicateRows(): void
{
$duplicateRows = DB::table(self::TABLE)
->selectRaw(
'MIN(id) AS keep_id, user_id, server_rate, server_id, server_type, record_at, record_type, ' .
'SUM(u) AS total_u, SUM(d) AS total_d, MIN(created_at) AS min_created_at, MAX(updated_at) AS max_updated_at'
)
->groupBy('user_id', 'server_rate', 'server_id', 'server_type', 'record_at', 'record_type')
->havingRaw('COUNT(*) > 1')
->orderBy('keep_id')
->cursor();
foreach ($duplicateRows as $row) {
DB::table(self::TABLE)
->where('id', $row->keep_id)
->update([
'u' => (int) $row->total_u,
'd' => (int) $row->total_d,
'created_at' => (int) $row->min_created_at,
'updated_at' => (int) $row->max_updated_at,
]);
DB::table(self::TABLE)
->where('user_id', $row->user_id)
->where('server_rate', $row->server_rate)
->where('server_id', $row->server_id)
->where('server_type', $row->server_type)
->where('record_at', $row->record_at)
->where('record_type', $row->record_type)
->where('id', '!=', $row->keep_id)
->delete();
}
}
};