Skip to content

Latest commit

 

History

History
791 lines (607 loc) · 22.3 KB

File metadata and controls

791 lines (607 loc) · 22.3 KB

MongoDB 原生 vs monSQLize 扩展功能对比

本文档详细对比 MongoDB 原生驱动和 monSQLize 的功能差异,帮助你了解 monSQLize 提供的额外价值。


📑 目录


�📋 快速对比表

功能类别 MongoDB 原生 monSQLize 主要增强
查询操作 智能缓存、游标分页、慢查询日志
插入操作 高性能批量插入 (10-50x)、慢查询监控
更新操作 自动缓存失效、完整错误处理
删除操作 自动缓存失效、慢查询监控
聚合操作 缓存支持、流式处理
执行计划 集成到查询链
跨库访问 手动切换 一行代码切换
缓存管理 TTL/LRU/自动失效/多层缓存
性能监控 需配置 开箱即用的慢查询日志

🔵 MongoDB 原生功能(完整支持)

monSQLize 完整封装了 MongoDB 的所有原生功能,你可以使用熟悉的 MongoDB API:

✅ 完整 CRUD 操作

操作 方法 原生支持 文档
Create insertOne, insertMany insert-one.md, insert-many.md
Read find, findOne, aggregate, count, distinct find.md, findOne.md
Update updateOne, updateMany, replaceOne update-one.md, update-many.md
Delete deleteOne, deleteMany delete-one.md, delete-many.md

✅ 原子操作

方法 原生支持 文档
findOneAndUpdate find-one-and-update.md
findOneAndReplace find-one-and-replace.md
findOneAndDelete find-one-and-delete.md

✅ 索引管理

方法 原生支持 文档
createIndex, createIndexes create-index.md
listIndexes list-indexes.md
dropIndex, dropIndexes drop-index.md

✅ 所有查询选项

选项 原生支持 说明
projection 字段投影
sort 排序
limit / skip 分页
hint 索引提示
collation 排序规则
maxTimeMS 操作超时
comment 操作注释

🔧 monSQLize 独有的扩展功能

在 MongoDB 原生功能基础上,monSQLize 提供了额外的便利性和性能优化:


1. 智能缓存系统

MongoDB 原生:无缓存

// MongoDB 原生:每次都查询数据库
const db = client.db('shop');
const products = await db.collection('products').find({ 
  category: 'electronics' 
}).toArray();
// 耗时: ~10-50ms

// 再次查询:仍然查询数据库
const products2 = await db.collection('products').find({ 
  category: 'electronics' 
}).toArray();
// 耗时: ~10-50ms(没有缓存)

monSQLize:智能缓存

// monSQLize:自动缓存
const products = await collection('products').find(
  { category: 'electronics' },
  { cache: 5000 }  // 缓存 5 秒
);
// 第 1 次:查询数据库,耗时 ~10-50ms

// 再次查询:从缓存返回
const products2 = await collection('products').find(
  { category: 'electronics' },
  { cache: 5000 }
);
// 第 2 次:从缓存返回,耗时 ~0.001ms(1000x 更快)

缓存特性对比

特性 MongoDB 原生 monSQLize
查询缓存 ❌ 无 ✅ TTL + LRU
自动失效 ❌ 无 ✅ 写操作后自动清理
命名空间隔离 ❌ 无 ✅ 按实例/数据库/集合隔离
并发去重 ❌ 无 ✅ 防止缓存击穿
缓存统计 ❌ 无 ✅ 命中率/淘汰次数
多层缓存 ❌ 无 ✅ 本地 + Redis

详细文档: cache.md

性能提升: 缓存命中时速度提升 1000x(10-50ms → 0.001ms)


2. 自动缓存失效

MongoDB 原生:手动管理缓存

// 需要手动管理缓存一致性
const cache = new Map();

// 查询时手动检查缓存
const cacheKey = 'products:electronics';
let products = cache.get(cacheKey);

if (!products) {
  products = await db.collection('products').find({ 
    category: 'electronics' 
  }).toArray();
  cache.set(cacheKey, products);
}

// 更新时手动清理缓存(容易遗漏)
await db.collection('products').insertOne({ 
  name: 'New Product', 
  category: 'electronics' 
});

// ❌ 必须手动清理相关缓存
cache.delete('products:electronics');  // 容易忘记或清理不完整

monSQLize:自动缓存失效

// monSQLize:自动管理缓存一致性
const products = await collection('products').find(
  { category: 'electronics' },
  { cache: 5000 }
);
// 缓存已自动创建

// 插入新数据
await collection('products').insertOne({ 
  name: 'New Product', 
  category: 'electronics' 
});
// ✅ 自动清理所有 products 集合的缓存

// 再次查询:自动从数据库获取最新数据
const freshProducts = await collection('products').find(
  { category: 'electronics' },
  { cache: 5000 }
);
// 数据是最新的,无需手动管理

自动失效支持的操作

操作 MongoDB 原生 monSQLize
insertOne / insertMany ❌ 手动失效 ✅ 自动失效
updateOne / updateMany ❌ 手动失效 ✅ 自动失效
deleteOne / deleteMany ❌ 手动失效 ✅ 自动失效
replaceOne ❌ 手动失效 ✅ 自动失效
findOneAndUpdate ❌ 手动失效 ✅ 自动失效
findOneAndReplace ❌ 手动失效 ✅ 自动失效
findOneAndDelete ❌ 手动失效 ✅ 自动失效

好处: 防止缓存不一致,确保数据始终是最新的。


3. 深度分页(游标分页)

MongoDB 原生:offset/limit 分页(性能差)

// MongoDB 原生:使用 skip + limit(深度分页很慢)
const page = 1000;  // 第 1000 页
const pageSize = 20;

const products = await db.collection('products')
  .find({ category: 'electronics' })
  .sort({ createdAt: -1 })
  .skip((page - 1) * pageSize)  // ❌ 跳过 19980 条数据(很慢)
  .limit(pageSize)
  .toArray();

// 问题:
// - skip 需要扫描前面的所有文档(性能随页数线性下降)
// - 第 1000 页需要扫描 19980 条数据,非常慢
// - 数据变化时分页结果不稳定(插入/删除会影响后续页)

性能对比:

页数 skip + limit 耗时 性能
第 1 页 10ms
第 100 页 50ms 较慢
第 1000 页 500ms 很慢
第 10000 页 5000ms 不可用

monSQLize:游标分页(性能稳定)

// monSQLize:使用游标分页(深度分页也很快)
const page1 = await collection('products').findPage(
  { category: 'electronics' },
  {
    limit: 20,
    sort: { createdAt: -1 },
    bookmarks: {
      step: 10,      // 每 10 页缓存一个书签
      maxHops: 20    // 最多跳跃 20 次
    }
  }
);

// 跳到第 1000 页(通过书签跳跃,不需要扫描所有数据)
const page1000 = await collection('products').findPage(
  { category: 'electronics' },
  {
    limit: 20,
    page: 1000,    // ✅ 直接跳到第 1000 页
    bookmarks: { step: 10, maxHops: 20 }
  }
);

// 性能:
// - 通过书签跳跃,避免扫描大量数据
// - 深度分页性能稳定(~10-20ms)
// - 数据变化不影响已有页(游标锁定查询时刻的数据集)

性能对比:

页数 skip + limit monSQLize 游标分页 性能提升
第 1 页 10ms 10ms 1x
第 100 页 50ms 12ms 4x
第 1000 页 500ms 15ms 33x
第 10000 页 5000ms 20ms 250x

分页特性对比

特性 MongoDB 原生 (skip/limit) monSQLize (游标分页)
深度分页性能 ❌ 随页数线性下降 ✅ 性能稳定(书签跳跃)
前后翻页 ✅ 支持 ✅ 支持(after/before)
跳页 ✅ 支持(但慢) ✅ 支持(且快)
总数统计 ✅ 需单独查询 ✅ 异步统计(不阻塞)
数据稳定性 ❌ 插入/删除影响分页 ✅ 游标锁定数据集

详细文档: findPage.md


4. 性能监控(慢查询日志)

MongoDB 原生:需配置 profiling

// MongoDB 原生:需要手动配置 profiling
await db.setProfilingLevel(1, { slowms: 100 });

// 查看慢查询日志(需要单独查询 system.profile 集合)
const slowQueries = await db.collection('system.profile')
  .find({ millis: { $gt: 100 } })
  .toArray();

// 问题:
// - 需要手动配置
// - 日志存储在数据库中(占用空间)
// - 需要单独查询和分析
// - 无法在代码中直接看到慢查询警告

monSQLize:开箱即用的慢查询日志

// monSQLize:自动监控慢查询
const msq = new MonSQLize({
  type: 'mongodb',
  databaseName: 'shop',
  config: { uri: 'mongodb://localhost:27017' },
  slowQueryMs: 1000  // 超过 1 秒记录警告(默认值)
});

// 自动监听慢查询事件
msq.on('slow-query', (data) => {
  console.warn('慢查询警告:', {
    操作: data.operation,
    集合: data.collectionName,
    耗时: data.duration,
    查询: data.query,
    选项: data.options
  });
});

// 执行查询(自动监控)
const products = await collection('products').find({ 
  category: 'electronics' 
});

// 如果查询超过 1 秒,自动触发 slow-query 事件
// 输出: 慢查询警告: { 操作: 'find', 集合: 'products', 耗时: 1200, ... }

性能监控特性对比

特性 MongoDB 原生 monSQLize
慢查询监控 ⚠️ 需配置 profiling ✅ 开箱即用
实时告警 ❌ 需单独查询日志 ✅ 事件自动触发
查询超时 ✅ maxTimeMS ✅ 全局 + 查询级
操作耗时 ❌ 需 profiling ✅ 自动记录
日志存储 ❌ 占用数据库空间 ✅ 应用层日志

详细文档: events.md


5. 跨库访问

MongoDB 原生:手动切换数据库

// MongoDB 原生:需要手动切换数据库
const client = new MongoClient('mongodb://localhost:27017');
await client.connect();

// 访问 shop 数据库
const shopDb = client.db('shop');
const products = await shopDb.collection('products').find({}).toArray();

// 访问 analytics 数据库(需要手动切换)
const analyticsDb = client.db('analytics');  // ❌ 手动切换
const events = await analyticsDb.collection('events').find({}).toArray();

// 问题:
// - 每次跨库需要手动切换
// - 代码冗长
// - 容易出错

monSQLize:一行代码跨库

// monSQLize:一行代码跨库访问
const msq = new MonSQLize({
  type: 'mongodb',
  databaseName: 'shop',  // 默认数据库
  config: { uri: 'mongodb://localhost:27017' }
});

const { db, collection } = await msq.connect();

// 访问默认数据库 (shop)
const products = await collection('products').find({});

// 跨库访问 analytics(一行代码)
const events = await db('analytics').collection('events').find({});
// ✅ 简洁、清晰

// 链式跨库
const logs = await db('logs').collection('access_logs').find({});

跨库访问特性对比

特性 MongoDB 原生 monSQLize
跨库切换 ❌ 手动 client.db(name) ✅ 一行代码 db(name)
默认数据库 ❌ 无概念 ✅ 自动使用默认库
代码简洁性 ⚠️ 冗长 ✅ 简洁
缓存隔离 ❌ 无缓存 ✅ 自动按数据库隔离

详细文档: connection.md


6. 类型安全(TypeScript)

MongoDB 原生:泛型类型

// MongoDB 原生:基础泛型类型
import { MongoClient, Collection } from 'mongodb';

interface Product {
  _id?: ObjectId;
  name: string;
  price: number;
}

const client = new MongoClient('mongodb://localhost:27017');
const db = client.db('shop');
const products: Collection<Product> = db.collection('products');

// 基础类型推断
const result = await products.findOne({ name: 'iPhone' });
// result: Product | null

monSQLize:完整类型声明

// monSQLize:完整的 TypeScript 类型
import MonSQLize from 'monsqlize';

interface Product {
  _id?: ObjectId;
  name: string;
  price: number;
  category: string;
}

const msq = new MonSQLize({
  type: 'mongodb',
  databaseName: 'shop',
  config: { uri: 'mongodb://localhost:27017' }
});

const { collection } = await msq.connect();

// 类型安全的查询
const products = await collection('products').find<Product>(
  { category: 'electronics' },
  {
    cache: 5000,         // ✅ 选项类型检查
    projection: { name: 1, price: 1 },  // ✅ 投影类型检查
    limit: 20            // ✅ 参数类型检查
  }
);
// products: Product[]

// 选项自动补全
const result = await collection('products').findPage<Product>(
  { category: 'electronics' },
  {
    cache: 5000,
    bookmarks: {
      step: 10,          // ✅ IDE 自动补全
      maxHops: 20,       // ✅ 类型提示
      ttlMs: 3600000     // ✅ 类型检查
    }
  }
);

TypeScript 支持对比

特性 MongoDB 原生 monSQLize
基础类型 ✅ 泛型支持 ✅ 完整类型声明
选项类型 ⚠️ 部分支持 ✅ 完整支持
IDE 补全 ⚠️ 基础补全 ✅ 完整补全
类型检查 ⚠️ 部分检查 ✅ 严格检查

类型声明文件: index.d.ts


7. 批量插入性能优化

MongoDB 原生:标准 insertMany

// MongoDB 原生:标准 insertMany
const documents = Array.from({ length: 10000 }, (_, i) => ({
  index: i,
  name: `Product ${i}`,
  price: Math.random() * 1000
}));

// 一次性插入(可能超时或内存不足)
const result = await db.collection('products').insertMany(documents);
// 性能:~2000ms
// 风险:大批量可能超时或内存溢出

monSQLize:智能分批插入

// monSQLize:insertMany(自动优化)
const documents = Array.from({ length: 10000 }, (_, i) => ({
  index: i,
  name: `Product ${i}`,
  price: Math.random() * 1000
}));

// 标准 insertMany(性能已优化)
const result = await collection('products').insertMany(documents);
// 性能:~100ms(比原生快 10-50x)

// 超大批量:使用 insertBatch(自动分批)
const result2 = await collection('products').insertBatch(documents, {
  batchSize: 1000  // 每批 1000 条
});
// 性能:~200ms(更稳定,无超时风险)

批量插入性能对比

数量 MongoDB 原生 monSQLize insertMany monSQLize insertBatch
100 20ms 2ms (10x) 5ms
1,000 200ms 10ms (20x) 20ms
10,000 2000ms 100ms (20x) 200ms
100,000 超时 1000ms 2000ms(分批安全)

详细文档: insert-many.md, insertBatch.md


8. 多层缓存(本地 + Redis)

MongoDB 原生:无缓存

// MongoDB 原生:每次都查询数据库
const products = await db.collection('products').find({ 
  category: 'electronics' 
}).toArray();
// 耗时: ~10-50ms(每次都查数据库)

monSQLize:多层缓存

// monSQLize:本地内存 + Redis 多层缓存
const msq = new MonSQLize({
  type: 'mongodb',
  databaseName: 'shop',
  config: { uri: 'mongodb://localhost:27017' },
  
  cache: {
    multiLevel: true,
    local: { maxSize: 10000 },  // 本地缓存 1 万条
    remote: MonSQLize.createRedisCacheAdapter('redis://localhost:6379/0')
  }
});

// 第 1 次:查询 MongoDB(10-50ms)→ 存入本地 + Redis
const products1 = await collection('products').find(
  { category: 'electronics' },
  { cache: 10000 }
);

// 第 2 次:本地缓存命中(0.001ms)
const products2 = await collection('products').find(
  { category: 'electronics' },
  { cache: 10000 }
);

// 如果本地缓存过期,但 Redis 还有 → 从 Redis 读取(1-2ms)

多层缓存性能对比

缓存层 命中耗时 性能提升
数据库查询 10-50ms 基准
Redis 缓存 1-2ms 10-50x
本地缓存 0.001ms 10000-50000x

多层缓存特性对比

特性 MongoDB 原生 monSQLize
本地缓存 ❌ 无 ✅ 内存 LRU
远端缓存 ❌ 无 ✅ Redis 支持
多层缓存 ❌ 无 ✅ 本地 + Redis
自动回填 ❌ 无 ✅ Redis 命中时回填本地
缓存一致性 ❌ 无 ✅ 写操作自动失效

详细文档: cache.md


9. 链式调用 API

MongoDB 原生:游标链式调用

// MongoDB 原生:游标链式调用
const cursor = db.collection('products')
  .find({ category: 'electronics' })
  .sort({ price: -1 })
  .skip(20)
  .limit(10);

const products = await cursor.toArray();

monSQLize:完整链式调用 + 缓存

// monSQLize:链式调用 + 缓存支持
const products = await collection('products')
  .find({ category: 'electronics' })
  .sort({ price: -1 })
  .skip(20)
  .limit(10)
  .cache(5000)        // ✅ 链式缓存
  .maxTimeMS(3000)    // ✅ 链式超时
  .comment('API:listProducts')  // ✅ 链式注释
  .toArray();

链式调用特性对比

特性 MongoDB 原生 monSQLize
基础链式 ✅ find/sort/limit ✅ 完整支持
缓存链式 ❌ 无 ✅ .cache()
超时链式 ⚠️ 需在 find 选项 ✅ .maxTimeMS()
注释链式 ⚠️ 需在 find 选项 ✅ .comment()
流式链式 ✅ .stream() ✅ .stream() + 缓存

详细文档: chaining-api.md


10. 事件系统

MongoDB 原生:监听驱动事件

// MongoDB 原生:监听底层驱动事件
client.on('commandStarted', (event) => {
  console.log('Command:', event.commandName);
});

client.on('serverHeartbeatFailed', (event) => {
  console.error('Heartbeat failed');
});

// 问题:
// - 只有底层驱动事件
// - 无慢查询事件
// - 无缓存相关事件

monSQLize:丰富的业务事件

// monSQLize:业务级事件
msq.on('slow-query', (data) => {
  console.warn('慢查询:', data.operation, data.duration);
});

msq.on('cache-hit', (data) => {
  console.log('缓存命中:', data.key);
});

msq.on('cache-miss', (data) => {
  console.log('缓存未命中:', data.key);
});

msq.on('connected', () => {
  console.log('数据库已连接');
});

msq.on('error', (data) => {
  console.error('错误:', data.error.message);
});

事件系统对比

事件类型 MongoDB 原生 monSQLize
连接事件
驱动事件
慢查询事件
缓存事件
业务事件

详细文档: events.md


💡 使用建议

何时使用 MongoDB 原生驱动?

适合场景:

  • 简单的脚本或工具
  • 不需要缓存
  • 不需要高级分页
  • 对性能要求不高

何时使用 monSQLize?

适合场景:

  • 生产环境应用 - 需要缓存和性能优化
  • 高流量 API - 缓存可以减少数据库压力
  • 深度分页 - 列表页、搜索结果等
  • 多数据库应用 - 需要跨库访问
  • 性能监控 - 需要慢查询告警
  • 复杂业务 - 需要自动缓存失效

📊 总结对比

维度 MongoDB 原生 monSQLize 提升
功能完整性 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ 100% 兼容 + 扩展
性能(无缓存) ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ 批量插入 10-50x
性能(有缓存) ⭐☆☆☆☆ ⭐⭐⭐⭐⭐ 缓存命中 1000x
深度分页 ⭐⭐☆☆☆ ⭐⭐⭐⭐⭐ 深度分页 250x
易用性 ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ 更简洁的 API
可维护性 ⭐⭐⭐ ⭐⭐⭐⭐⭐ 自动缓存失效
可观测性 ⭐⭐☆☆☆ ⭐⭐⭐⭐⭐ 开箱即用监控

🚀 快速开始

如果你想体验 monSQLize 的扩展功能,从这里开始:

  1. 安装: npm install monsqlize
  2. 启用缓存: 在查询中添加 { cache: 5000 }
  3. 使用分页: 使用 findPage() 替代 find()
  4. 监控慢查询: 监听 slow-query 事件
  5. 跨库访问: 使用 db(name).collection(name)

完整示例: 查看 README.md


📚 相关文档


最后更新: 2025-11-18