mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-05-09 11:01:45 +00:00
perf(db): otimizar índices — remover 7 sem uso, adicionar 17 em FKs
Baseado em análise do pg_stat_user_indexes (187 dias de estatísticas): removidos 7 índices com 0 scans e adicionados 17 índices em foreign keys que antes geravam sequential scans durante deletes nas tabelas pai. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
24
drizzle/0025_burly_colonel_america.sql
Normal file
24
drizzle/0025_burly_colonel_america.sql
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
DROP INDEX "tokens_api_user_id_idx";--> statement-breakpoint
|
||||||
|
DROP INDEX "cartoes_user_id_status_idx";--> statement-breakpoint
|
||||||
|
DROP INDEX "dashboard_notification_states_user_id_archived_idx";--> statement-breakpoint
|
||||||
|
DROP INDEX "contas_user_id_status_idx";--> statement-breakpoint
|
||||||
|
DROP INDEX "antecipacoes_parcelas_series_id_idx";--> statement-breakpoint
|
||||||
|
DROP INDEX "pagadores_user_id_status_idx";--> statement-breakpoint
|
||||||
|
DROP INDEX "pagadores_user_id_role_idx";--> statement-breakpoint
|
||||||
|
CREATE INDEX "account_user_id_idx" ON "account" USING btree ("userId");--> statement-breakpoint
|
||||||
|
CREATE INDEX "anexos_user_id_idx" ON "anexos" USING btree ("user_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "orcamentos_categoria_id_idx" ON "orcamentos" USING btree ("categoria_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "cartoes_conta_id_idx" ON "cartoes" USING btree ("conta_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "import_category_mappings_category_id_idx" ON "import_category_mappings" USING btree ("category_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "pre_lancamentos_lancamento_id_idx" ON "pre_lancamentos" USING btree ("lancamento_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "antecipacoes_parcelas_lancamento_id_idx" ON "antecipacoes_parcelas" USING btree ("lancamento_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "antecipacoes_parcelas_pagador_id_idx" ON "antecipacoes_parcelas" USING btree ("pagador_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "antecipacoes_parcelas_categoria_id_idx" ON "antecipacoes_parcelas" USING btree ("categoria_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "anotacoes_user_id_idx" ON "anotacoes" USING btree ("user_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "passkey_user_id_idx" ON "passkey" USING btree ("userId");--> statement-breakpoint
|
||||||
|
CREATE INDEX "compartilhamentos_pagador_shared_with_user_id_idx" ON "compartilhamentos_pagador" USING btree ("shared_with_user_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "compartilhamentos_pagador_created_by_user_id_idx" ON "compartilhamentos_pagador" USING btree ("created_by_user_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "session_user_id_idx" ON "session" USING btree ("userId");--> statement-breakpoint
|
||||||
|
CREATE INDEX "lancamentos_conta_id_idx" ON "lancamentos" USING btree ("conta_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "lancamentos_categoria_id_idx" ON "lancamentos" USING btree ("categoria_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "lancamentos_antecipacao_id_idx" ON "lancamentos" USING btree ("antecipacao_id");
|
||||||
2889
drizzle/meta/0025_snapshot.json
Normal file
2889
drizzle/meta/0025_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -176,6 +176,13 @@
|
|||||||
"when": 1774891206703,
|
"when": 1774891206703,
|
||||||
"tag": "0024_petite_lucky_pierre",
|
"tag": "0024_petite_lucky_pierre",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 25,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1776351838548,
|
||||||
|
"tag": "0025_burly_colonel_america",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
109
src/db/schema.ts
109
src/db/schema.ts
@@ -32,7 +32,9 @@ export const user = pgTable("user", {
|
|||||||
}).notNull(),
|
}).notNull(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const account = pgTable("account", {
|
export const account = pgTable(
|
||||||
|
"account",
|
||||||
|
{
|
||||||
id: text("id").primaryKey(),
|
id: text("id").primaryKey(),
|
||||||
accountId: text("accountId").notNull(),
|
accountId: text("accountId").notNull(),
|
||||||
providerId: text("providerId").notNull(),
|
providerId: text("providerId").notNull(),
|
||||||
@@ -60,9 +62,15 @@ export const account = pgTable("account", {
|
|||||||
mode: "date",
|
mode: "date",
|
||||||
withTimezone: true,
|
withTimezone: true,
|
||||||
}).notNull(),
|
}).notNull(),
|
||||||
});
|
},
|
||||||
|
(table) => ({
|
||||||
|
userIdIdx: index("account_user_id_idx").on(table.userId),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
export const session = pgTable("session", {
|
export const session = pgTable(
|
||||||
|
"session",
|
||||||
|
{
|
||||||
id: text("id").primaryKey(),
|
id: text("id").primaryKey(),
|
||||||
expiresAt: timestamp("expiresAt", {
|
expiresAt: timestamp("expiresAt", {
|
||||||
mode: "date",
|
mode: "date",
|
||||||
@@ -82,7 +90,11 @@ export const session = pgTable("session", {
|
|||||||
userId: text("userId")
|
userId: text("userId")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => user.id, { onDelete: "cascade" }),
|
.references(() => user.id, { onDelete: "cascade" }),
|
||||||
});
|
},
|
||||||
|
(table) => ({
|
||||||
|
userIdIdx: index("session_user_id_idx").on(table.userId),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
export const verification = pgTable("verification", {
|
export const verification = pgTable("verification", {
|
||||||
id: text("id").primaryKey(),
|
id: text("id").primaryKey(),
|
||||||
@@ -104,7 +116,9 @@ export const verification = pgTable("verification", {
|
|||||||
|
|
||||||
// ===================== PASSKEY (WebAuthn) =====================
|
// ===================== PASSKEY (WebAuthn) =====================
|
||||||
|
|
||||||
export const passkey = pgTable("passkey", {
|
export const passkey = pgTable(
|
||||||
|
"passkey",
|
||||||
|
{
|
||||||
id: text("id").primaryKey(),
|
id: text("id").primaryKey(),
|
||||||
name: text("name"),
|
name: text("name"),
|
||||||
publicKey: text("publicKey").notNull(),
|
publicKey: text("publicKey").notNull(),
|
||||||
@@ -121,7 +135,11 @@ export const passkey = pgTable("passkey", {
|
|||||||
mode: "date",
|
mode: "date",
|
||||||
withTimezone: true,
|
withTimezone: true,
|
||||||
}),
|
}),
|
||||||
});
|
},
|
||||||
|
(table) => ({
|
||||||
|
userIdIdx: index("passkey_user_id_idx").on(table.userId),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
export const userPreferences = pgTable("preferencias_usuario", {
|
export const userPreferences = pgTable("preferencias_usuario", {
|
||||||
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`),
|
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`),
|
||||||
@@ -157,9 +175,7 @@ export const userPreferences = pgTable("preferencias_usuario", {
|
|||||||
|
|
||||||
// ===================== PUBLIC TABLES =====================
|
// ===================== PUBLIC TABLES =====================
|
||||||
|
|
||||||
export const financialAccounts = pgTable(
|
export const financialAccounts = pgTable("contas", {
|
||||||
"contas",
|
|
||||||
{
|
|
||||||
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`),
|
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`),
|
||||||
name: text("nome").notNull(),
|
name: text("nome").notNull(),
|
||||||
accountType: text("tipo_conta").notNull(),
|
accountType: text("tipo_conta").notNull(),
|
||||||
@@ -182,14 +198,7 @@ export const financialAccounts = pgTable(
|
|||||||
})
|
})
|
||||||
.notNull()
|
.notNull()
|
||||||
.defaultNow(),
|
.defaultNow(),
|
||||||
},
|
});
|
||||||
(table) => ({
|
|
||||||
userIdStatusIdx: index("contas_user_id_status_idx").on(
|
|
||||||
table.userId,
|
|
||||||
table.status,
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
export const categories = pgTable(
|
export const categories = pgTable(
|
||||||
"categorias",
|
"categorias",
|
||||||
@@ -248,14 +257,6 @@ export const payers = pgTable(
|
|||||||
uniqueShareCode: uniqueIndex("pagadores_share_code_key").on(
|
uniqueShareCode: uniqueIndex("pagadores_share_code_key").on(
|
||||||
table.shareCode,
|
table.shareCode,
|
||||||
),
|
),
|
||||||
userIdStatusIdx: index("pagadores_user_id_status_idx").on(
|
|
||||||
table.userId,
|
|
||||||
table.status,
|
|
||||||
),
|
|
||||||
userIdRoleIdx: index("pagadores_user_id_role_idx").on(
|
|
||||||
table.userId,
|
|
||||||
table.role,
|
|
||||||
),
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -285,6 +286,12 @@ export const payerShares = pgTable(
|
|||||||
table.payerId,
|
table.payerId,
|
||||||
table.sharedWithUserId,
|
table.sharedWithUserId,
|
||||||
),
|
),
|
||||||
|
sharedWithUserIdIdx: index(
|
||||||
|
"compartilhamentos_pagador_shared_with_user_id_idx",
|
||||||
|
).on(table.sharedWithUserId),
|
||||||
|
createdByUserIdIdx: index(
|
||||||
|
"compartilhamentos_pagador_created_by_user_id_idx",
|
||||||
|
).on(table.createdByUserId),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -317,10 +324,7 @@ export const cards = pgTable(
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
(table) => ({
|
(table) => ({
|
||||||
userIdStatusIdx: index("cartoes_user_id_status_idx").on(
|
accountIdIdx: index("cartoes_conta_id_idx").on(table.accountId),
|
||||||
table.userId,
|
|
||||||
table.status,
|
|
||||||
),
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -387,10 +391,13 @@ export const budgets = pgTable(
|
|||||||
userIdCategoryIdPeriodUnique: uniqueIndex(
|
userIdCategoryIdPeriodUnique: uniqueIndex(
|
||||||
"orcamentos_user_id_categoria_id_periodo_key",
|
"orcamentos_user_id_categoria_id_periodo_key",
|
||||||
).on(table.userId, table.categoryId, table.period),
|
).on(table.userId, table.categoryId, table.period),
|
||||||
|
categoryIdIdx: index("orcamentos_categoria_id_idx").on(table.categoryId),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const notes = pgTable("anotacoes", {
|
export const notes = pgTable(
|
||||||
|
"anotacoes",
|
||||||
|
{
|
||||||
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`),
|
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`),
|
||||||
title: text("titulo"),
|
title: text("titulo"),
|
||||||
description: text("descricao"),
|
description: text("descricao"),
|
||||||
@@ -406,7 +413,11 @@ export const notes = pgTable("anotacoes", {
|
|||||||
userId: text("user_id")
|
userId: text("user_id")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => user.id, { onDelete: "cascade" }),
|
.references(() => user.id, { onDelete: "cascade" }),
|
||||||
});
|
},
|
||||||
|
(table) => ({
|
||||||
|
userIdIdx: index("anotacoes_user_id_idx").on(table.userId),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
export const savedInsights = pgTable(
|
export const savedInsights = pgTable(
|
||||||
"insights_salvos",
|
"insights_salvos",
|
||||||
@@ -460,7 +471,6 @@ export const apiTokens = pgTable(
|
|||||||
.defaultNow(),
|
.defaultNow(),
|
||||||
},
|
},
|
||||||
(table) => ({
|
(table) => ({
|
||||||
userIdIdx: index("tokens_api_user_id_idx").on(table.userId),
|
|
||||||
tokenHashIdx: uniqueIndex("tokens_api_token_hash_idx").on(table.tokenHash),
|
tokenHashIdx: uniqueIndex("tokens_api_token_hash_idx").on(table.tokenHash),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@@ -524,6 +534,9 @@ export const inboxItems = pgTable(
|
|||||||
table.userId,
|
table.userId,
|
||||||
table.createdAt,
|
table.createdAt,
|
||||||
),
|
),
|
||||||
|
transactionIdIdx: index("pre_lancamentos_lancamento_id_idx").on(
|
||||||
|
table.transactionId,
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -555,9 +568,6 @@ export const dashboardNotificationStates = pgTable(
|
|||||||
userIdNotificationKeyUnique: uniqueIndex(
|
userIdNotificationKeyUnique: uniqueIndex(
|
||||||
"dashboard_notification_states_user_id_key_unique",
|
"dashboard_notification_states_user_id_key_unique",
|
||||||
).on(table.userId, table.notificationKey),
|
).on(table.userId, table.notificationKey),
|
||||||
userIdArchivedAtIdx: index(
|
|
||||||
"dashboard_notification_states_user_id_archived_idx",
|
|
||||||
).on(table.userId, table.archivedAt),
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -597,10 +607,14 @@ export const installmentAnticipations = pgTable(
|
|||||||
.defaultNow(),
|
.defaultNow(),
|
||||||
},
|
},
|
||||||
(table) => ({
|
(table) => ({
|
||||||
seriesIdIdx: index("antecipacoes_parcelas_series_id_idx").on(
|
|
||||||
table.seriesId,
|
|
||||||
),
|
|
||||||
userIdIdx: index("antecipacoes_parcelas_user_id_idx").on(table.userId),
|
userIdIdx: index("antecipacoes_parcelas_user_id_idx").on(table.userId),
|
||||||
|
transactionIdIdx: index("antecipacoes_parcelas_lancamento_id_idx").on(
|
||||||
|
table.transactionId,
|
||||||
|
),
|
||||||
|
payerIdIdx: index("antecipacoes_parcelas_pagador_id_idx").on(table.payerId),
|
||||||
|
categoryIdIdx: index("antecipacoes_parcelas_categoria_id_idx").on(
|
||||||
|
table.categoryId,
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -700,6 +714,12 @@ export const transactions = pgTable(
|
|||||||
table.cardId,
|
table.cardId,
|
||||||
table.period,
|
table.period,
|
||||||
),
|
),
|
||||||
|
// FK indexes: evitam seq scan em deletes/updates nas tabelas pai
|
||||||
|
accountIdIdx: index("lancamentos_conta_id_idx").on(table.accountId),
|
||||||
|
categoryIdIdx: index("lancamentos_categoria_id_idx").on(table.categoryId),
|
||||||
|
anticipationIdIdx: index("lancamentos_antecipacao_id_idx").on(
|
||||||
|
table.anticipationId,
|
||||||
|
),
|
||||||
// Dedup OFX: garante FITID único por usuário
|
// Dedup OFX: garante FITID único por usuário
|
||||||
ofxFitIdUserIdIdx: uniqueIndex("lancamentos_ofx_fit_id_user_id_idx")
|
ofxFitIdUserIdIdx: uniqueIndex("lancamentos_ofx_fit_id_user_id_idx")
|
||||||
.on(table.userId, table.ofxFitId)
|
.on(table.userId, table.ofxFitId)
|
||||||
@@ -905,7 +925,9 @@ export const installmentAnticipationsRelations = relations(
|
|||||||
|
|
||||||
// ===================== ATTACHMENTS =====================
|
// ===================== ATTACHMENTS =====================
|
||||||
|
|
||||||
export const attachments = pgTable("anexos", {
|
export const attachments = pgTable(
|
||||||
|
"anexos",
|
||||||
|
{
|
||||||
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`),
|
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`),
|
||||||
userId: text("user_id")
|
userId: text("user_id")
|
||||||
.notNull()
|
.notNull()
|
||||||
@@ -917,7 +939,11 @@ export const attachments = pgTable("anexos", {
|
|||||||
createdAt: timestamp("created_at", { mode: "date", withTimezone: true })
|
createdAt: timestamp("created_at", { mode: "date", withTimezone: true })
|
||||||
.notNull()
|
.notNull()
|
||||||
.defaultNow(),
|
.defaultNow(),
|
||||||
});
|
},
|
||||||
|
(table) => ({
|
||||||
|
userIdIdx: index("anexos_user_id_idx").on(table.userId),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
export const transactionAttachments = pgTable(
|
export const transactionAttachments = pgTable(
|
||||||
"lancamento_anexos",
|
"lancamento_anexos",
|
||||||
@@ -953,6 +979,9 @@ export const importCategoryMappings = pgTable(
|
|||||||
},
|
},
|
||||||
(table) => ({
|
(table) => ({
|
||||||
pk: primaryKey({ columns: [table.userId, table.descriptionKey] }),
|
pk: primaryKey({ columns: [table.userId, table.descriptionKey] }),
|
||||||
|
categoryIdIdx: index("import_category_mappings_category_id_idx").on(
|
||||||
|
table.categoryId,
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user