大量消息收件箱完成第一层性能优化
This commit is contained in:
@@ -58,6 +58,7 @@ public sealed class NotificationsController(
|
|||||||
var total = await source.CountAsync(cancellationToken);
|
var total = await source.CountAsync(cancellationToken);
|
||||||
var items = await source
|
var items = await source
|
||||||
.OrderByDescending(x => x.CreatedAt)
|
.OrderByDescending(x => x.CreatedAt)
|
||||||
|
.ThenByDescending(x => x.Id)
|
||||||
.Skip((page - 1) * pageSize)
|
.Skip((page - 1) * pageSize)
|
||||||
.Take(pageSize)
|
.Take(pageSize)
|
||||||
.Select(x => new
|
.Select(x => new
|
||||||
|
|||||||
@@ -1475,8 +1475,11 @@ public sealed class AppDbContext(DbContextOptions<AppDbContext> options)
|
|||||||
entity.Property(x => x.Title).HasMaxLength(200);
|
entity.Property(x => x.Title).HasMaxLength(200);
|
||||||
entity.Property(x => x.Content).HasColumnType("longtext");
|
entity.Property(x => x.Content).HasColumnType("longtext");
|
||||||
entity.Property(x => x.LinkUrl).HasMaxLength(300);
|
entity.Property(x => x.LinkUrl).HasMaxLength(300);
|
||||||
entity.HasIndex(x => new { x.UserId, x.IsRead });
|
// Each inbox query starts with its recipient. Keep the selected
|
||||||
entity.HasIndex(x => new { x.UserId, x.Category, x.CreatedAt });
|
// sort fields in the index so large inboxes do not need a filesort.
|
||||||
|
entity.HasIndex(x => new { x.UserId, x.CreatedAt, x.Id });
|
||||||
|
entity.HasIndex(x => new { x.UserId, x.IsRead, x.CreatedAt, x.Id });
|
||||||
|
entity.HasIndex(x => new { x.UserId, x.Category, x.CreatedAt, x.Id });
|
||||||
entity.HasIndex(x => x.MessageDispatchId);
|
entity.HasIndex(x => x.MessageDispatchId);
|
||||||
entity.HasIndex(x => x.CreatedAt);
|
entity.HasIndex(x => x.CreatedAt);
|
||||||
entity.HasOne(x => x.MessageDispatch)
|
entity.HasOne(x => x.MessageDispatch)
|
||||||
|
|||||||
@@ -102,6 +102,8 @@ public sealed class DevelopmentSqliteMigrator(
|
|||||||
"20260809_53_course_grade_statistics_refresh_settings";
|
"20260809_53_course_grade_statistics_refresh_settings";
|
||||||
private const string ExperimentCourseGradesMigration =
|
private const string ExperimentCourseGradesMigration =
|
||||||
"20260809_54_experiment_course_grades";
|
"20260809_54_experiment_course_grades";
|
||||||
|
private const string NotificationInboxIndexesMigration =
|
||||||
|
"20260810_55_notification_inbox_indexes";
|
||||||
|
|
||||||
public async Task MigrateAsync(CancellationToken cancellationToken = default)
|
public async Task MigrateAsync(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
@@ -731,6 +733,10 @@ public sealed class DevelopmentSqliteMigrator(
|
|||||||
ExperimentCourseGradesMigration,
|
ExperimentCourseGradesMigration,
|
||||||
experimentCourseGradesExist ? [] : ExperimentCourseGradesStatements,
|
experimentCourseGradesExist ? [] : ExperimentCourseGradesStatements,
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
|
await ApplyMigrationAsync(
|
||||||
|
NotificationInboxIndexesMigration,
|
||||||
|
NotificationInboxIndexesStatements,
|
||||||
|
cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ApplyMigrationAsync(
|
private async Task ApplyMigrationAsync(
|
||||||
@@ -2999,6 +3005,15 @@ public sealed class DevelopmentSqliteMigrator(
|
|||||||
"""CREATE UNIQUE INDEX IF NOT EXISTS "IX_CourseGradeStatisticsRefreshSettings_Key" ON "CourseGradeStatisticsRefreshSettings" ("Key");"""
|
"""CREATE UNIQUE INDEX IF NOT EXISTS "IX_CourseGradeStatisticsRefreshSettings_Key" ON "CourseGradeStatisticsRefreshSettings" ("Key");"""
|
||||||
];
|
];
|
||||||
|
|
||||||
|
private static readonly string[] NotificationInboxIndexesStatements =
|
||||||
|
[
|
||||||
|
"""DROP INDEX "IX_Notifications_UserId_IsRead";""",
|
||||||
|
"""DROP INDEX "IX_Notifications_UserId_Category_CreatedAt";""",
|
||||||
|
"""CREATE INDEX "IX_Notifications_UserId_CreatedAt_Id" ON "Notifications" ("UserId", "CreatedAt", "Id");""",
|
||||||
|
"""CREATE INDEX "IX_Notifications_UserId_IsRead_CreatedAt_Id" ON "Notifications" ("UserId", "IsRead", "CreatedAt", "Id");""",
|
||||||
|
"""CREATE INDEX "IX_Notifications_UserId_Category_CreatedAt_Id" ON "Notifications" ("UserId", "Category", "CreatedAt", "Id");"""
|
||||||
|
];
|
||||||
|
|
||||||
private static readonly string[] ExperimentCourseGradesStatements =
|
private static readonly string[] ExperimentCourseGradesStatements =
|
||||||
[
|
[
|
||||||
"""
|
"""
|
||||||
|
|||||||
+6936
File diff suppressed because it is too large
Load Diff
+63
@@ -0,0 +1,63 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Jiaowu.Api.Infrastructure.Persistence.Migrations.MySql
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class OptimizeNotificationInboxIndexes : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Notifications_UserId_Category_CreatedAt",
|
||||||
|
table: "Notifications");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Notifications_UserId_IsRead",
|
||||||
|
table: "Notifications");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Notifications_UserId_Category_CreatedAt_Id",
|
||||||
|
table: "Notifications",
|
||||||
|
columns: new[] { "UserId", "Category", "CreatedAt", "Id" });
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Notifications_UserId_CreatedAt_Id",
|
||||||
|
table: "Notifications",
|
||||||
|
columns: new[] { "UserId", "CreatedAt", "Id" });
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Notifications_UserId_IsRead_CreatedAt_Id",
|
||||||
|
table: "Notifications",
|
||||||
|
columns: new[] { "UserId", "IsRead", "CreatedAt", "Id" });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Notifications_UserId_Category_CreatedAt_Id",
|
||||||
|
table: "Notifications");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Notifications_UserId_CreatedAt_Id",
|
||||||
|
table: "Notifications");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Notifications_UserId_IsRead_CreatedAt_Id",
|
||||||
|
table: "Notifications");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Notifications_UserId_Category_CreatedAt",
|
||||||
|
table: "Notifications",
|
||||||
|
columns: new[] { "UserId", "Category", "CreatedAt" });
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Notifications_UserId_IsRead",
|
||||||
|
table: "Notifications",
|
||||||
|
columns: new[] { "UserId", "IsRead" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-2
@@ -3417,9 +3417,11 @@ namespace Jiaowu.Api.Infrastructure.Persistence.Migrations.MySql
|
|||||||
|
|
||||||
b.HasIndex("MessageDispatchId");
|
b.HasIndex("MessageDispatchId");
|
||||||
|
|
||||||
b.HasIndex("UserId", "IsRead");
|
b.HasIndex("UserId", "CreatedAt", "Id");
|
||||||
|
|
||||||
b.HasIndex("UserId", "Category", "CreatedAt");
|
b.HasIndex("UserId", "Category", "CreatedAt", "Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId", "IsRead", "CreatedAt", "Id");
|
||||||
|
|
||||||
b.ToTable("Notifications");
|
b.ToTable("Notifications");
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user