perf(analytics): project minimal columns in GetStats/GetAnalyticsOverview #3
@@ -55,6 +55,20 @@ namespace JobTrackerApi.Data
|
|||||||
modelBuilder.Entity<JobApplication>()
|
modelBuilder.Entity<JobApplication>()
|
||||||
.HasIndex(j => j.OwnerUserId);
|
.HasIndex(j => j.OwnerUserId);
|
||||||
|
|
||||||
|
// Owner-prefixed composite indexes for the tenant-scoped hot paths. Every
|
||||||
|
// JobApplication query is scoped by the OwnerUserId global filter first, then
|
||||||
|
// filtered by IsDeleted (list/board/stats/analytics) or FollowUpAt (reminders).
|
||||||
|
// Status is intentionally excluded from the index because Pomelo maps the
|
||||||
|
// unbounded string column to longtext, which MariaDB cannot index without a
|
||||||
|
// prefix length. The actual index DDL is applied idempotently in
|
||||||
|
// StartupInitializationExtensions (this repo provisions schema via that
|
||||||
|
// reconciler, not via the EF ModelSnapshot, which is stale).
|
||||||
|
modelBuilder.Entity<JobApplication>()
|
||||||
|
.HasIndex(j => new { j.OwnerUserId, j.IsDeleted });
|
||||||
|
|
||||||
|
modelBuilder.Entity<JobApplication>()
|
||||||
|
.HasIndex(j => new { j.OwnerUserId, j.FollowUpAt });
|
||||||
|
|
||||||
modelBuilder.Entity<Company>()
|
modelBuilder.Entity<Company>()
|
||||||
.HasIndex(c => c.OwnerUserId);
|
.HasIndex(c => c.OwnerUserId);
|
||||||
|
|
||||||
|
|||||||
@@ -499,6 +499,16 @@ public static class StartupInitializationExtensions
|
|||||||
EnsureColumn(conn, "Attachments", "Purpose", "ALTER TABLE Attachments ADD COLUMN Purpose TEXT NULL;");
|
EnsureColumn(conn, "Attachments", "Purpose", "ALTER TABLE Attachments ADD COLUMN Purpose TEXT NULL;");
|
||||||
EnsureColumn(conn, "Attachments", "UseForAi", "ALTER TABLE Attachments ADD COLUMN UseForAi INTEGER NOT NULL DEFAULT 1;");
|
EnsureColumn(conn, "Attachments", "UseForAi", "ALTER TABLE Attachments ADD COLUMN UseForAi INTEGER NOT NULL DEFAULT 1;");
|
||||||
|
|
||||||
|
// Hot-path composite indexes for tenant-scoped list/board/stats/analytics
|
||||||
|
// (OwnerUserId + IsDeleted) and reminders (OwnerUserId + FollowUpAt). Guarded
|
||||||
|
// on table existence: on a brand-new DB the table is created by Migrate()
|
||||||
|
// below, so the index is picked up on the next start.
|
||||||
|
if (HasTable(conn, "JobApplications"))
|
||||||
|
{
|
||||||
|
Exec(conn, """CREATE INDEX IF NOT EXISTS "IX_JobApplications_OwnerUserId_IsDeleted" ON "JobApplications" ("OwnerUserId", "IsDeleted");""");
|
||||||
|
Exec(conn, """CREATE INDEX IF NOT EXISTS "IX_JobApplications_OwnerUserId_FollowUpAt" ON "JobApplications" ("OwnerUserId", "FollowUpAt");""");
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure data folder exists before creating/opening SQLite files.
|
// Ensure data folder exists before creating/opening SQLite files.
|
||||||
Directory.CreateDirectory(paths.DataRoot);
|
Directory.CreateDirectory(paths.DataRoot);
|
||||||
}
|
}
|
||||||
@@ -819,6 +829,22 @@ public static class StartupInitializationExtensions
|
|||||||
cmd.ExecuteNonQuery();
|
cmd.ExecuteNonQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hot-path composite indexes for tenant-scoped list/board/stats/analytics
|
||||||
|
// (OwnerUserId + IsDeleted) and reminders (OwnerUserId + FollowUpAt).
|
||||||
|
if (!MySqlIndexExists(conn, "JobApplications", "IX_JobApplications_OwnerUserId_IsDeleted"))
|
||||||
|
{
|
||||||
|
using var cmd = conn.CreateCommand();
|
||||||
|
cmd.CommandText = "CREATE INDEX `IX_JobApplications_OwnerUserId_IsDeleted` ON `JobApplications` (`OwnerUserId`, `IsDeleted`);";
|
||||||
|
cmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MySqlIndexExists(conn, "JobApplications", "IX_JobApplications_OwnerUserId_FollowUpAt"))
|
||||||
|
{
|
||||||
|
using var cmd = conn.CreateCommand();
|
||||||
|
cmd.CommandText = "CREATE INDEX `IX_JobApplications_OwnerUserId_FollowUpAt` ON `JobApplications` (`OwnerUserId`, `FollowUpAt`);";
|
||||||
|
cmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
|
||||||
if (!MySqlIndexExists(conn, "CvUploadArtifacts", "IX_CvUploadArtifacts_OwnerUserId_UploadedAtUtc"))
|
if (!MySqlIndexExists(conn, "CvUploadArtifacts", "IX_CvUploadArtifacts_OwnerUserId_UploadedAtUtc"))
|
||||||
{
|
{
|
||||||
using var cmd = conn.CreateCommand();
|
using var cmd = conn.CreateCommand();
|
||||||
|
|||||||
Reference in New Issue
Block a user