performance-optimization
2
总安装量
1
周安装量
#74702
全站排名
安装命令
npx skills add https://github.com/blogic-cz/blogic-marketplace --skill performance-optimization
Agent 安装分布
mcpjam
1
claude-code
1
replit
1
junie
1
windsurf
1
zencoder
1
Skill 文档
Performance Optimization Skill
Use this skill when analyzing and implementing performance optimizations for API calls, database queries, and data processing patterns.
When to Use
- Analyzing codebase for performance bottlenecks
- Implementing batch operations
- Optimizing N+1 query patterns
- Parallelizing independent operations
- Adding database indexes
Analysis Workflow
1. Identify Bottlenecks
Search for these patterns:
// N+1 Pattern - Loop with API/DB calls
for (const item of items) {
const data = await db
.select()
.from(table)
.where(eq(table.id, item.id));
}
// Sequential Independent Calls
const a = await fetchA();
const b = await fetchB(); // Could be parallel
// Individual Inserts/Updates in Loop
for (const item of items) {
await db.insert(table).values(item);
}
2. Apply Optimizations
Batch Database Queries
// Before: N queries
for (const id of ids) {
const item = await db
.select()
.from(table)
.where(eq(table.id, id));
}
// After: 1 query
const items = await db
.select()
.from(table)
.where(inArray(table.id, ids));
const itemMap = new Map(items.map((i) => [i.id, i]));
Parallel Effect Operations
// Before: Sequential
const a = yield * effectA();
const b = yield * effectB();
// After: Parallel
const [a, b] = yield * Effect.all([effectA(), effectB()]);
// With concurrency limit
const results =
yield *
Effect.all(
items.map((item) => processItem(item)),
{ concurrency: 10 }
);
Parallel Promise Operations
// Before: Sequential
await octokit.issues.createComment({...});
await octokit.issues.update({...});
// After: Parallel
await Promise.all([
octokit.issues.createComment({...}),
octokit.issues.update({...}),
]);
Batch Updates
// Before: N updates
for (const id of ids) {
await db
.update(table)
.set({ status: "closed" })
.where(eq(table.id, id));
}
// After: 1 update
await db
.update(table)
.set({ status: "closed" })
.where(inArray(table.id, ids));
Query Consolidation with JOINs
// Before: 2 queries
const membership = await db.select().from(membersTable).where(...);
const org = await db.select().from(organizationsTable).where(...);
// After: 1 query with JOIN
const [result] = await db
.select({ org: organizationsTable, member: membersTable })
.from(organizationsTable)
.innerJoin(membersTable, eq(membersTable.organizationId, organizationsTable.id))
.where(and(
eq(organizationsTable.id, orgId),
eq(membersTable.userId, userId)
));
Common Codebase Patterns
Effect.all for Parallel Operations
// Parallel with unbounded concurrency (for few items)
yield * Effect.all(items.map(processItem));
// Parallel with bounded concurrency (for many items)
yield *
Effect.all(items.map(processItem), { concurrency: 10 });
// Parallel independent fetches
const [data1, data2] =
yield *
Effect.all([fetchData1(params), fetchData2(params)]);
Pre-fetching with Lookup Maps
// Fetch all needed data upfront
const [users, members, invitations] = await Promise.all([
db
.select()
.from(usersTable)
.where(inArray(usersTable.email, emails)),
db
.select()
.from(membersTable)
.where(inArray(membersTable.userId, userIds)),
db
.select()
.from(invitationsTable)
.where(inArray(invitationsTable.email, emails)),
]);
// Build lookup maps
const userByEmail = new Map(users.map((u) => [u.email, u]));
const memberByUserId = new Map(
members.map((m) => [m.userId, m])
);
// Use in loop without DB calls
for (const email of emails) {
const user = userByEmail.get(email);
// ...
}
Upsert with onConflictDoUpdate
// Instead of: SELECT + conditional INSERT/UPDATE
const existing = await db.select().from(table).where(eq(table.id, id));
if (existing.length > 0) {
await db.update(table).set({...}).where(eq(table.id, id));
} else {
await db.insert(table).values({...});
}
// Use: Single upsert
await db
.insert(table)
.values({ id, ...data })
.onConflictDoUpdate({
target: table.id,
set: { ...data, updatedAt: new Date() },
});
Database Index Guidelines
When to Add Indexes
- Single-column queries: If filtering by one column frequently
- Composite queries: If filtering by multiple columns together
- ORDER BY columns: If sorting by a column frequently
- Foreign keys: Usually auto-indexed, but verify
Index Syntax (Drizzle)
export const myTable = pgTable(
"my_table",
{
id: text("id").primaryKey(),
userId: text("user_id").notNull(),
status: text("status").notNull(),
createdAt: timestamp("created_at").notNull(),
},
(table) => [
index("idx_my_table_user_id").on(table.userId),
index("idx_my_table_status").on(table.status),
// Composite index for common query pattern
index("idx_my_table_user_status_created").on(
table.userId,
table.status,
table.createdAt
),
]
);
Validation Checklist
After implementing optimizations:
-
bun run checkpasses - Tests updated if behavior changed
- Error handling preserved
- Logging maintained (summary vs per-item as appropriate)
- Concurrency limits added for external APIs
- Memory usage considered for large batch operations
Measuring Impact
Before optimizing, measure:
const start = performance.now();
// ... operation
console.log(
`Operation took ${performance.now() - start}ms`
);
Or use Effect tracing:
yield * myOperation.pipe(Effect.withSpan("MyOperation"));
References
- See
references/effect-parallel-patterns.mdfor Effect-specific patterns - See
references/drizzle-batch-patterns.mdfor Drizzle ORM patterns