mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-02 02:00:49 +08:00
feat: improve workspace list perf
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
-- Add persisted size column for snapshots (nullable for backwards compatibility)
|
||||
ALTER TABLE "snapshots" ADD COLUMN IF NOT EXISTS "size" BIGINT;
|
||||
|
||||
-- Ensure size is populated on insert/update even for older app versions
|
||||
CREATE OR REPLACE FUNCTION snapshots_set_size() RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW."size" := COALESCE(NEW."size", octet_length(NEW."blob"));
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
DROP TRIGGER IF EXISTS snapshots_set_size_before_write ON "snapshots";
|
||||
CREATE TRIGGER snapshots_set_size_before_write
|
||||
BEFORE INSERT OR UPDATE OF "blob" ON "snapshots"
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION snapshots_set_size();
|
||||
|
||||
-- Backfill existing rows
|
||||
UPDATE "snapshots"
|
||||
SET "size" = octet_length("blob")
|
||||
WHERE "size" IS NULL;
|
||||
|
||||
-- Support faster admin aggregates
|
||||
CREATE INDEX IF NOT EXISTS "idx_wur_owner" ON "workspace_user_permissions" ("workspace_id")
|
||||
WHERE "type" = 99 AND "status" = 'Accepted'::"WorkspaceMemberStatus";
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "idx_wur_workspace" ON "workspace_user_permissions" ("workspace_id");
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "idx_blobs_active" ON "blobs" ("workspace_id")
|
||||
WHERE "deleted_at" IS NULL AND "status" = 'completed';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "idx_workspace_pages_public" ON "workspace_pages" ("workspace_id")
|
||||
WHERE "public" = TRUE;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "idx_workspace_features_activated" ON "workspace_features" ("workspace_id")
|
||||
WHERE "activated" = TRUE;
|
||||
@@ -273,6 +273,8 @@ model Snapshot {
|
||||
workspaceId String @map("workspace_id") @db.VarChar
|
||||
id String @default(uuid()) @map("guid") @db.VarChar
|
||||
blob Bytes @db.ByteA
|
||||
// persisted size of blob to avoid summing over bytea
|
||||
size BigInt? @map("size") @db.BigInt
|
||||
state Bytes? @db.ByteA
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
|
||||
// the `updated_at` field will not record the time of record changed,
|
||||
|
||||
@@ -149,6 +149,7 @@ export class DocModel extends BaseModel {
|
||||
async upsert(doc: Doc) {
|
||||
const { spaceId, docId, blob, timestamp, editorId } = doc;
|
||||
const updatedAt = new Date(timestamp);
|
||||
const size = blob.byteLength ?? blob.length;
|
||||
// CONCERNS:
|
||||
// i. Because we save the real user's last seen action time as `updatedAt`,
|
||||
// it's possible to simply compare the `updatedAt` to determine if the snapshot is older than the one we are going to save.
|
||||
@@ -158,10 +159,10 @@ export class DocModel extends BaseModel {
|
||||
// where: { workspaceId_id: {}, updatedAt: { lt: updatedAt } }
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
const result: { updatedAt: Date }[] = await this.db.$queryRaw`
|
||||
INSERT INTO "snapshots" ("workspace_id", "guid", "blob", "created_at", "updated_at", "created_by", "updated_by")
|
||||
VALUES (${spaceId}, ${docId}, ${blob}, DEFAULT, ${updatedAt}, ${editorId}, ${editorId})
|
||||
INSERT INTO "snapshots" ("workspace_id", "guid", "blob", "size", "created_at", "updated_at", "created_by", "updated_by")
|
||||
VALUES (${spaceId}, ${docId}, ${blob}, ${size}, DEFAULT, ${updatedAt}, ${editorId}, ${editorId})
|
||||
ON CONFLICT ("workspace_id", "guid")
|
||||
DO UPDATE SET "blob" = ${blob}, "updated_at" = ${updatedAt}, "updated_by" = ${editorId}
|
||||
DO UPDATE SET "blob" = ${blob}, "size" = ${size}, "updated_at" = ${updatedAt}, "updated_by" = ${editorId}
|
||||
WHERE "snapshots"."workspace_id" = ${spaceId} AND "snapshots"."guid" = ${docId} AND "snapshots"."updated_at" <= ${updatedAt}
|
||||
RETURNING "snapshots"."workspace_id" as "workspaceId", "snapshots"."guid" as "id", "snapshots"."updated_at" as "updatedAt"
|
||||
`;
|
||||
|
||||
@@ -211,7 +211,7 @@ export class WorkspaceModel extends BaseModel {
|
||||
),
|
||||
snapshot_stats AS (
|
||||
SELECT workspace_id,
|
||||
SUM(octet_length(blob)) AS snapshot_size,
|
||||
SUM(COALESCE(size, octet_length(blob))) AS snapshot_size,
|
||||
COUNT(*) AS snapshot_count
|
||||
FROM snapshots
|
||||
GROUP BY workspace_id
|
||||
|
||||
Reference in New Issue
Block a user