Node.js 主流ORM框架動(dòng)態(tài)分表方案大盤點(diǎn)
針對高并發(fā)、數(shù)據(jù)量大的場景,通常會(huì)考慮采用分庫分表進(jìn)行優(yōu)化。在這篇文章,我們重點(diǎn)盤點(diǎn)一下Node.js主流ORM框架的動(dòng)態(tài)分表方案:
分表規(guī)則
比如我們需要對訂單表進(jìn)行分表操作。可以根據(jù)實(shí)際業(yè)務(wù)需求設(shè)計(jì)分表規(guī)則,在這里,我們根據(jù)顧客Id取模動(dòng)態(tài)生成表名。比如,拆分為16張表,顧客Id為129,對應(yīng)的表名如下:
const tableName = `Order_${129 % 16}`; // Order_1
TypeORM
在TypeORM中可以按照如下方式設(shè)置動(dòng)態(tài)表名:
// 獲取repository
const repositoryOrder = dataSource.createQueryBuilder().connection.getRepository(EntityOrder);
// 設(shè)置動(dòng)態(tài)表名
const userId = 129;
const tableName = `Order_${userId % 16}`;
repositoryOrder.metadata.tablePath = tableName;
// 查詢訂單
const orders = await repositoryOrder.find();
Drizzle ORM
schema.ts
const orderFactory = userId => pgTable(
`Order_${userId % 16}`,
{
id: serial('id').primaryKey(),
name: text('name').notNull(),
},
);
export const order0 = orderFactory(0);
...
export const order15 = orderFactory(15);
query.ts
import * as schema from './db/schema';
const db = drizzle(process.env.DATABASE_URL!, { schema });
const userId = 129;
const modelName=`order${userId % 16}`;
const orders = await db.query[modelName].findMany();
Prisma ORM
Prisma ORM對動(dòng)態(tài)表名的支持還在規(guī)劃當(dāng)中,參見:Table Partitioning
作為備選方案,我們可以使用$queryRawUnsafe直接構(gòu)造原始SQL:
const userId = 129;
const tableName = `Order_${userId % 16}`;
const orders = await prisma.$queryRawUnsafe(`SELECT * FROM "${tableName}"`);
Vona ORM
Vona ORM提供了兩種模式:自動(dòng)模式/手工模式
1. 自動(dòng)模式
model/order.ts
import { EntityOrder } from '../entity/order.ts';
@Model({
entity: EntityOrder,
table(ctx: VonaContext, defaultTable: keyof ITableRecord) {
const user = ctx.app.bean.passport.getCurrentUser();
if (!user) return defaultTable;
return `${defaultTable}_${Number(user.id) % 16}`;
},
})
export class ModelOrder {}
- defaultTable: 是在EntityOrder中定義的缺省表名,如:
Order
service/order.ts
class ServiceOrder {
async findAll() {
return await this.scope.model.order.select();
}
}
2. 手工模式
service/order.ts
class ServiceOrder {
async findAll() {
const user = this.bean.passport.getCurrentUser();
const tableName = `Order_${Number(user!.id) % 16}`;
const modelOrder = this.scope.model.order.newInstance(undefined, tableName as any);
return await modelOrder.select();
}
}
- newInstance: 第一個(gè)參數(shù)可以傳入數(shù)據(jù)源,從而實(shí)現(xiàn)
分庫能力。這里忽略,因此傳入undefined

針對高并發(fā)、數(shù)據(jù)量大的場景,通常會(huì)考慮采用分庫分表進(jìn)行優(yōu)化。在這篇文章,我們重點(diǎn)盤點(diǎn)一下Node.js主流ORM框架的動(dòng)態(tài)分表方案
浙公網(wǎng)安備 33010602011771號