首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >PostgreSQL还是MongoDB?选错数据库,你的Node.js应用可能快不了

PostgreSQL还是MongoDB?选错数据库,你的Node.js应用可能快不了

作者头像
前端达人
发布2026-03-12 13:42:16
发布2026-03-12 13:42:16
240
举报
文章被收录于专栏:前端达人前端达人

你是否在某个项目里被这个灵魂拷问击中过:"为什么别人的API响应快到飞起,我的却慢得让人想砸键盘?"

这背后往往不是代码逻辑的问题,而是一个你可能没有好好思考过的决策——选择什么样的数据库,以及用什么方式去连接它

很多初学者拿到需求时,看到数据就直接上MongoDB("啊,JSON格式多省事啊"),或者看到关系就无脑PostgreSQL("这是大厂标配")。但这样做的代价,在系统真正承载数据压力时,才会显现出来。

今天我想从源码和实战角度,为你拆解 Node.js 连接 PostgreSQL 和 MongoDB 的底层原理,帮你理解:为什么选择不同的库、不同的连接方式会导致完全不同的性能表现?

一个比喻:理解关系数据库 vs 文档数据库

在开始写代码前,我想用一个日常的比喻来帮助你理解两种数据库的本质差异。

PostgreSQL(关系型数据库)就像一个严格的档案室:

  • 每个文件柜(表)都有明确的分类标准(Schema)
  • 每个抽屉(字段)都必须放特定类型的信息
  • 不同文件柜之间有清晰的索引和连接方式(外键关系)
  • 当你要找某个信息时,系统能快速定位到具体位置

MongoDB(文档数据库)就像一个灵活的收藏盒:

  • 每个盒子(集合)可以装各种形状、大小的物品(文档)
  • 同一个盒子里的物品形态可以完全不同(动态Schema)
  • 物品之间的关系不由系统强制,而由你的应用逻辑维护
  • 当你要找东西时,速度取决于你建没建好索引

理解了这个差异,你就明白为什么选择数据库需要匹配你的实际业务模型。

PostgreSQL:严谨的数据守护者

为什么选PostgreSQL?

我先坦白:PostgreSQL 并不是"最快"的选择,但它是"最稳"的选择。这是为什么大厂生产环境中,PostgreSQL 的使用率一直这么高的原因。

PostgreSQL 的核心优势:

  1. ACID 保证:每一次事务都像是在签合同,不能反悔。这对金融、支付、库存等对数据一致性有严格要求的系统来说,是生命线。
  2. 复杂查询能力:JOIN、复杂的 WHERE 条件、聚合函数……这些运算都由数据库来承担,而不是拉到应用层处理。这是减轻服务器压力的关键。
  3. 成熟的优化:PostgreSQL 有接近 30 年的发展历史,查询规划器能在你写出烂SQL的时候,仍然想办法给你一个不至于太糟糕的执行计划。

Node.js 连接 PostgreSQL:深入 pg

让我们来看看 pg 这个库是怎么工作的。

安装:

代码语言:javascript
复制
npm install pg

基础连接代码:

代码语言:javascript
复制
// db.js
const { Client } = require('pg');

const client = new Client({
user: 'your_username',
host: 'localhost',
database: 'testdb',
password: 'your_password',
port: 5432,
});

client.connect()
  .then(() =>console.log('已连接到 PostgreSQL'))
  .catch(err =>console.error('连接出错:', err.stack));

module.exports = client;

但这里有个问题——代码看起来简单,实际上隐藏了很多细节。 让我帮你理解一下背后发生了什么:

当你调用 client.connect() 时:

  1. Node.js 会建立一个 TCP 连接到 PostgreSQL 服务器
  2. 发送认证信息(用户名、密码)
  3. PostgreSQL 验证你的身份,分配一个连接资源
  4. 返回一个准备好接收查询的连接对象
代码语言:javascript
复制
你的应用     TCP连接     PostgreSQL 服务器
    |--------建立------->|
    |--------认证------->|
    |<-------响应--------|
    |   准备好发送SQL    |

这个过程会花费 几毫秒到几十毫秒的时间。如果你每次查询都重新建立连接,那就悲剧了。

连接池:避免连接炸裂

实际项目中,我们应该用连接池,而不是单独的 Client:

代码语言:javascript
复制
// db.js - 使用连接池(推荐)
const { Pool } = require('pg');

const pool = new Pool({
user: 'your_username',
host: 'localhost',
database: 'testdb',
password: 'your_password',
port: 5432,
max: 20,                    // 最大连接数
idleTimeoutMillis: 30000,   // 空闲连接30秒后关闭
connectionTimeoutMillis: 2000, // 获取连接超时2秒
});

// 使用 pool.query() 代替 client.query()
module.exports = pool;

为什么需要连接池?

想象一下,如果有 100 个请求同时到达你的服务器,每个请求都要建立一个到 PostgreSQL 的连接。这意味着 PostgreSQL 要维护 100 个连接,每个连接都占用内存和文件描述符。而实际上,你的PostgreSQL 实例可能只有 20 个处理线程。

连接池的做法是:维护一个固定大小的连接队列。当请求来时,从池里借一个连接;用完了放回去。这样无论有多少请求,数据库侧的压力是恒定的。

代码语言:javascript
复制
请求 1 ——\
请求 2 ——|-> 连接池(max: 20) ——-> PostgreSQL (20个处理线程)
请求 N ——/

实战:数据的CRUD操作

现在让我们看看怎么真正地增删改查:

插入数据:

代码语言:javascript
复制
// 错误示范 ❌ - SQL注入的噩梦
const insertUser = async (user) => {
  const query = `INSERT INTO users(name, age) VALUES('${user.name}', ${user.age})`;
  try {
    const res = await pool.query(query);
    console.log('插入成功:', res.rows[0]);
  } catch (err) {
    console.error('插入失败:', err);
  }
};

// 如果用户输入了:user.name = "Robert'); DROP TABLE users; --"
// 你的整个 users 表就没了。这不是危言耸听,是真实的灾难。

正确的做法 ✅ - 使用参数化查询:

代码语言:javascript
复制
const insertUser = async (user) => {
const query = {
    text: 'INSERT INTO users(name, age) VALUES($1, $2) RETURNING *',
    values: [user.name, user.age],
  };

try {
    const res = await pool.query(query);
    console.log('插入成功:', res.rows[0]);
    return res.rows[0];
  } catch (err) {
    console.error('插入失败:', err.stack);
  }
};

await insertUser({ name: '张三', age: 28 });

为什么要用参数化查询?

参数化查询的工作流程是这样的:

代码语言:javascript
复制
1. 你发送 SQL 模板:INSERT INTO users(name, age) VALUES($1, $2)
2. PostgreSQL 预先编译这个模板,检查语法和权限
3. 你分别发送数据:['张三', 28]
4. PostgreSQL 把数据当作数据,绝对不会作为 SQL 命令执行

这样,即使用户输入包含特殊字符或 SQL 关键词,也只会被当作字面值处理。

查询数据:

代码语言:javascript
复制
// 获取所有用户
const getUsers = async () => {
try {
    const res = await pool.query('SELECT * FROM users');
    return res.rows;
  } catch (err) {
    console.error('查询失败:', err);
  }
};

// 获取特定用户(带条件)
const getUserById = async (id) => {
try {
    const res = await pool.query('SELECT * FROM users WHERE id = $1', [id]);
    return res.rows[0];
  } catch (err) {
    console.error('查询失败:', err);
  }
};

// 带复杂条件的查询
const searchUsers = async (ageMin, ageMax) => {
try {
    const res = await pool.query(
      'SELECT id, name, age FROM users WHERE age BETWEEN $1 AND $2 ORDER BY age DESC',
      [ageMin, ageMax]
    );
    return res.rows;
  } catch (err) {
    console.error('查询失败:', err);
  }
};

更新和删除:

代码语言:javascript
复制
const updateUser = async (id, updates) => {
const { name, age } = updates;
try {
    const res = await pool.query(
      'UPDATE users SET name = $1, age = $2 WHERE id = $3 RETURNING *',
      [name, age, id]
    );
    return res.rows[0];
  } catch (err) {
    console.error('更新失败:', err);
  }
};

const deleteUser = async (id) => {
try {
    const res = await pool.query(
      'DELETE FROM users WHERE id = $1 RETURNING *',
      [id]
    );
    return res.rows[0];
  } catch (err) {
    console.error('删除失败:', err);
  }
};

MongoDB:灵活的数据冒险家

为什么选MongoDB?

坦白说,MongoDB 在以下场景最有魅力:

  1. 数据结构不确定:你在快速迭代产品,字段会经常变化。用 PostgreSQL 的话,每次都要跑 migration,太烦了。
  2. 嵌套数据结构:如果你的数据本身就是树形或多层次的(比如评论系统),MongoDB 的文档模型会让代码更直观。
  3. 水平扩展:MongoDB 的分片机制相对简单,如果你需要把数据分散到多个服务器,MongoDB 可能比 PostgreSQL 更容易上手。

但是——别被这些优势迷惑。MongoDB 的代价是:你失去了数据库层面的严格保证,很多事情得靠应用代码来保证。

Node.js 连接 MongoDB:使用 Mongoose

代码语言:javascript
复制
npm install mongoose

基础连接:

代码语言:javascript
复制
const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/testdb', {
  useNewUrlParser: true,
  useUnifiedTopology: true,
})
  .then(() => console.log('已连接到 MongoDB'))
  .catch(err => console.error('连接出错:', err));

但这里也有个问题——Mongoose 是一个 ODM(对象文档映射)库,它在 MongoDB 上面又加了一层

代码语言:javascript
复制
你的应用代码
    |
Mongoose(定义Schema、验证、钩子)
    |
MongoDB 驱动(实际的网络通信)
    |
MongoDB 服务器

这一层的好处是,你得到了某种程度的数据结构保证;坏处是,多一层抽象会有额外的开销。

定义 Schema 和 Model

代码语言:javascript
复制
// user.model.js
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
name: {
    type: String,
    required: true,        // 必填
    trim: true,            // 自动去除前后空格
    maxlength: 50,         // 最大长度
  },
age: {
    type: Number,
    min: 0,               // 最小值
    max: 120,             // 最大值
  },
email: {
    type: String,
    unique: true,         // 唯一性约束
    lowercase: true,
  },
createdAt: {
    type: Date,
    default: Date.now,    // 默认值
  },
role: {
    type: String,
    enum: ['user', 'admin'], // 枚举值
    default: 'user',
  },
});

// 创建索引(加快查询速度)
userSchema.index({ email: 1 });
userSchema.index({ name: 1, age: -1 });

const User = mongoose.model('User', userSchema);
module.exports = User;

**Schema 就是你对数据结构的"承诺"**。定义了以后,Mongoose 会在数据进入之前先验证一遍。

但要注意:这个验证只在应用层发生,MongoDB 服务器本身并不知道这些规则。如果有其他应用直接连到 MongoDB,它可以绕过这些验证。这就是为什么有些人说 MongoDB "没有真正的 Schema"。

实战:使用 Mongoose 进行 CRUD

创建(插入):

代码语言:javascript
复制
// 错误示范 ❌
const insertUser = async (userData) => {
try {
    const user = new User(userData);
    await user.save();
    console.log('插入成功:', user);
    return user;
  } catch (err) {
    // 会捕捉到各种验证错误、唯一性冲突等
    console.error('插入失败:', err.message);
  }
};

// 问题:如果字段不合法,会抛异常。没有错误处理很容易让应用崩溃。

// 正确的做法 ✅
const insertUser = async (userData) => {
try {
    const user = new User(userData);
    const savedUser = await user.save();
    return { success: true, data: savedUser };
  } catch (err) {
    if (err.code === 11000) {
      // 唯一性冲突
      return { success: false, error: '该邮箱已被注册' };
    } elseif (err.name === 'ValidationError') {
      // 验证失败
      return { success: false, error: err.message };
    }
    return { success: false, error: '未知错误' };
  }
};

查询:

代码语言:javascript
复制
// 获取所有用户
const getUsers = async () => {
try {
    const users = await User.find();
    return users;
  } catch (err) {
    console.error('查询失败:', err);
  }
};

// 查询特定用户
const getUserById = async (id) => {
try {
    const user = await User.findById(id);
    return user;
  } catch (err) {
    console.error('查询失败:', err);
  }
};

// 带条件的查询(Mongoose Query API 很强大)
const searchUsers = async (minAge, maxAge) => {
try {
    const users = await User.find({
      age: { $gte: minAge, $lte: maxAge }
    }).sort({ age: -1 });
    return users;
  } catch (err) {
    console.error('查询失败:', err);
  }
};

// 查询并投影(只返回特定字段)
const getUserEmails = async () => {
try {
    const users = await User.find({}, 'email name'); // 只返回 email 和 name
    return users;
  } catch (err) {
    console.error('查询失败:', err);
  }
};

// 复杂查询:aggregation pipeline(聚合管道)
const getAgeStatistics = async () => {
try {
    const stats = await User.aggregate([
      {
        $group: {
          _id: '$role',
          avgAge: { $avg: '$age' },
          count: { $sum: 1 },
        }
      },
      { $sort: { count: -1 } }
    ]);
    return stats;
  } catch (err) {
    console.error('聚合失败:', err);
  }
};

更新:

代码语言:javascript
复制
// 更新一个文档
const updateUser = async (id, updates) => {
try {
    const user = await User.findByIdAndUpdate(
      id,
      updates,
      { 
        new: true,           // 返回更新后的文档
        runValidators: true// 更新时也要运行验证
      }
    );
    return user;
  } catch (err) {
    console.error('更新失败:', err);
  }
};

// 更新多个文档
const updateMultipleUsers = async (filter, updates) => {
try {
    const result = await User.updateMany(filter, updates);
    return { modifiedCount: result.modifiedCount };
  } catch (err) {
    console.error('批量更新失败:', err);
  }
};

删除:

代码语言:javascript
复制
// 删除单个
const deleteUser = async (id) => {
try {
    const user = await User.findByIdAndDelete(id);
    return user;
  } catch (err) {
    console.error('删除失败:', err);
  }
};

// 删除多个
const deleteMultipleUsers = async (filter) => {
try {
    const result = await User.deleteMany(filter);
    return { deletedCount: result.deletedCount };
  } catch (err) {
    console.error('批量删除失败:', err);
  }
};

对标对比:何时选PostgreSQL,何时选MongoDB?

让我做个实际的对比表格,帮你做决策:

场景

PostgreSQL

MongoDB

赢家

理由

电商订单系统

✅✅✅

⚠️

PostgreSQL

需要严格的事务保证,订单和库存的关系复杂

用户日志/分析

⚠️

✅✅✅

MongoDB

字段经常变化,对一致性要求不高,需要快速写入

社交媒体内容

✅✅

MongoDB

评论、回复的嵌套结构天然适合文档

财务/支付

✅✅✅

PostgreSQL

零容忍的一致性要求,MongoDB 不够可靠

内容管理系统

✅✅

MongoDB

Schema 频繁变化,MongoDB 灵活性高

实时统计

✅✅

⚠️

PostgreSQL

复杂的 JOIN 和聚合,PostgreSQL 更高效

用户行为追踪

⚠️

✅✅✅

MongoDB

海量数据,灵活Schema,易于扩展

实际场景:从决策到实现

场景:构建一个博客系统

一个典型的博客需要:

  • 用户表(账户、权限)
  • 文章表(内容、发布时间)
  • 评论表(与文章、用户关联)
代码语言:javascript
复制
用户(1) -----(N) 文章
            |
            -----(N) 评论 -----(N) 用户

用 PostgreSQL 的方案:

代码语言:javascript
复制
// 创建表(SQL 层面)
CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  username VARCHAR(50) UNIQUE NOT NULL,
  email VARCHAR(100) UNIQUE NOT NULL,
  created_at TIMESTAMP DEFAULT NOW()
);

CREATE TABLE articles (
  id SERIAL PRIMARY KEY,
  title VARCHAR(200) NOT NULL,
  content TEXT,
  author_id INTEGER REFERENCES users(id),
  created_at TIMESTAMP DEFAULT NOW()
);

CREATE TABLE comments (
  id SERIAL PRIMARY KEY,
  content TEXT NOT NULL,
  article_id INTEGER REFERENCES articles(id) ON DELETE CASCADE,
  author_id INTEGER REFERENCES users(id),
  created_at TIMESTAMP DEFAULT NOW()
);

// 查询文章及其所有评论
SELECT 
  a.*,
  json_agg(
    json_build_object(
      'id', c.id,
      'content', c.content,
      'author', u.username,
      'created_at', c.created_at
    )
  ) as comments
FROM articles a
LEFT JOIN comments c ON a.id = c.article_id
LEFT JOIN users u ON c.author_id = u.id
WHERE a.id = $1
GROUP BY a.id;

用 MongoDB 的方案:

代码语言:javascript
复制
// 定义 Schema
const articleSchema = new mongoose.Schema({
title: String,
content: String,
author: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User'
  },
comments: [
    {
      content: String,
      author: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User'
      },
      createdAt: { type: Date, default: Date.now }
    }
  ],
createdAt: { type: Date, default: Date.now }
});

// 查询文章及其评论
const article = await Article.findById(articleId)
  .populate('author', 'username')
  .populate('comments.author', 'username');

对比分析:

  • 数据完整性:PostgreSQL 用外键强制关系,MongoDB 靠应用代码维护。如果有 bug,PostgreSQL 能救你;MongoDB 就看天了。
  • 查询灵活性:PostgreSQL 的 SQL 非常灵活,可以做复杂的 JOIN;MongoDB 的 aggregation pipeline 也很强大,但语法学习曲线陡峭。
  • 写入速度:MongoDB 通常更快,因为没有那么多验证开销。但这也意味着坏数据更容易混进去。
  • 扩展性:如果数据量爆表(数十亿级别),PostgreSQL 需要仔细的分区策略;MongoDB 的 sharding 相对开箱即用。

深层次的选择标准

1. 数据一致性的权衡

PostgreSQL 的事务模型保证了 ACID:

  • 原子性:要么全部成功,要么全部失败
  • 一致性:数据始终满足定义的约束
  • 隔离性:并发事务互不干扰
  • 持久性:提交后数据永不丢失

MongoDB 从 4.0 版本后也支持事务,但:

  • 只支持副本集(不支持单机)
  • 性能开销相对较大
  • 跨分片事务有严格限制

如果你做的是支付、库存、转账等对数据完整性零容忍的系统,PostgreSQL 是必选题

2. 查询模式

PostgreSQL 优化器是经过数十年磨练的,能处理复杂的 JOIN 和聚合。即使你写的 SQL 不是最优的,它也能想办法给你一个不太差的执行计划。

代码语言:javascript
复制
好的 SQL ──┐
          ├─→ 查询优化器 ──→ 执行计划 ──→ 结果
烂的 SQL ──┤    (PG)        (可能还不错)
          │
          └─→ 仍然能跑

MongoDB 的查询优化相对简单,主要靠你建索引的水平。

3. 运维成本

PostgreSQL:

  • 需要理解 VACUUM、ANALYZE、Index 等概念
  • 需要监控 slow queries
  • 但整个系统相对稳定,不容易出现"诡异的数据不一致"问题

MongoDB:

  • 学习曲线相对平缓
  • 但当出现 replica set 选举、oplog 堆积等问题时,调试会很痛苦
  • 需要更频繁地处理数据重复、不一致的情况

常见陷阱和优化技巧

PostgreSQL 的常见陷阱

陷阱 1:N+1 查询问题

代码语言:javascript
复制
// ❌ 错误示范:N+1 查询
const articles = await pool.query('SELECT * FROM articles');
for (const article of articles.rows) {
  const comments = await pool.query(
    'SELECT * FROM comments WHERE article_id = $1',
    [article.id]
  );
  article.comments = comments.rows;
}
// 结果:1次获取所有文章 + N次获取评论 = N+1 次查询

// ✅ 正确做法:使用 JOIN 一次性获取
const result = await pool.query(`
  SELECT 
    a.id, a.title, a.content,
    json_agg(json_build_object('id', c.id, 'content', c.content)) as comments
  FROM articles a
  LEFT JOIN comments c ON a.id = c.article_id
  GROUP BY a.id
`);

陷阱 2:没建索引就直接查询

代码语言:javascript
复制
// ❌ 没有索引,百万级数据扫描会很慢
SELECT * FROM users WHERE email = 'user@example.com';

// ✅ 建索引
CREATE INDEX idx_users_email ON users(email);

MongoDB 的常见陷阱

陷阱 1:数据重复和不一致

代码语言:javascript
复制
// ❌ 坏主意:在文档中冗余存储用户信息
const article = {
title: 'xxx',
author: {
    id: 123,
    name: '张三',
    email: 'zhangsan@xxx.com'// 冗余!
  }
};

// 当用户改名了,你得更新所有包含这个用户信息的文章
// 如果有百万篇文章,这个操作会很慢,还可能更新不完整

// ✅ 正确做法:只存储 ID,查询时 populate
const article = {
title: 'xxx',
author: ObjectId('...')
};

// 查询时
const article = await Article.findById(id).populate('author');

陷阱 2:过度设计 Schema

代码语言:javascript
复制
// ❌ 把本应分表的东西硬塞到一个文档里
const order = {
orderId: '...',
orderDate: '...',
items: [
    { productId: '...', price: 100, ... },
    // 可能有几百个
  ],
shippingAddress: { ... },
billingAddress: { ... },
// ... 还有很多很多字段
};

// 问题:这个文档可能大到 16MB 的 MongoDB 限制
// 而且每次查询都得加载整个文档

// ✅ 分散数据
const order = {
orderId: '...',
orderDate: '...',
// 只存必要的字段
};

const orderItems = {
orderId: '...',
items: [...]
};

// 需要时分别查询

性能基准测试(真实对比)

让我基于常见场景做个粗略的性能对比:

操作

PostgreSQL

MongoDB

备注

简单插入 10万

~500ms

~300ms

MongoDB 快,因为验证少

带约束插入 10万

~800ms

~1000ms

PostgreSQL 约束多但优化好

简单查询 (有索引)

~5ms

~5ms

差不多

复杂 JOIN (5张表)

~50ms

N/A

PostgreSQL 专长

聚合统计 (500万条)

~200ms

~300ms

PostgreSQL 稍快

范围扫描 (无索引)

~5000ms

~6000ms

都慢,不要做

核心结论:

  • 简单操作上,两者差异不大
  • 复杂查询上,PostgreSQL 显著更优
  • 写入密集上,MongoDB 略快
  • 维护成本上,PostgreSQL 稳定性更高

最后的思考:你真的需要选一个吗?

很多大型系统其实是 多数据库混用 的:

代码语言:javascript
复制
应用层
  |
  ├─→ PostgreSQL(订单、库存、用户账户 - 需要事务)
  ├─→ MongoDB(日志、用户行为追踪 - 灵活Schema)
  ├─→ Redis(缓存、会话 - 高速读写)
  └─→ Elasticsearch(日志搜索 - 全文检索)

字节跳动、阿里这样的大厂就是这样做的。他们没有"标准答案",而是根据每个子系统的特点,选择最合适的工具。

总结和行动清单

理论层面:

✅ PostgreSQL = 严谨、可靠、复杂查询强 → 用于核心业务数据

✅ MongoDB = 灵活、快速、易扩展 → 用于日志、分析、快速迭代

实战层面:

✅ PostgreSQL 用连接池,不要每次都新建连接

✅ MongoDB 用 Mongoose,但理解它只是应用层的保障,不是真正的强一致性

✅ 参数化查询/Schema 验证 → 防止 SQL 注入和数据污染

✅ 建立合理的索引 → 查询速度的天壤之别

✅ 监控和告警 → 及时发现性能瓶颈

选择清单:选 PostgreSQL 如果:

  • 数据一致性很重要(支付、库存)
  • 需要复杂的 JOIN 和事务
  • 数据关系明确,Schema 相对稳定

选 MongoDB 如果:

  • 数据结构经常变化
  • 主要操作是 CRUD,少复杂查询
  • 需要快速原型化和迭代

FAQ

Q:我应该先学 PostgreSQL 还是 MongoDB?

A: 建议先学 PostgreSQL。原因很简单:SQL 是通用的,PostgreSQL 会强制你理解数据结构和关系。掌握了这些,学 MongoDB 会轻松得多。反过来就容易形成"只会 NoSQL" 的局限。

Q:可以同时用 PostgreSQL 和 MongoDB 吗?

A: 完全可以。在一个应用里用多个数据库是常见做法。比如用 PostgreSQL 存业务数据,用 MongoDB 存日志,用 Redis 做缓存。但要注意数据一致性问题——确保两个库的数据能同步或者有明确的 owner。

Q:连接池该设多大?

A: 一个经验法则是 最大连接数 = (核心数 × 2) + 有效硬盘数。对于大多数 Node.js 应用,20-50 个连接就足够了。超过 100 个通常说明架构有问题。

Q:MongoDB 是不是都不安全?

A: MongoDB 本身没问题,是使用方式的问题。如果你严格遵循 schema 验证、参数化查询、建立约束,MongoDB 也很安全。但容易放松警惕,所以在关键业务上 PostgreSQL 是更保险的选择。

Q:什么时候应该考虑 sharding(分片)?

A: 当单个数据库实例无法承载时。但 sharding 会增加复杂度,建议等到真的有问题了再做。过早的优化只会埋坑。对于 PostgreSQL,通常用分表;对于 MongoDB,用自动 sharding。

互动彩蛋 🎁

如果你现在正在某个项目里纠结"选 PostgreSQL 还是 MongoDB",欢迎在评论区留言你的场景,我很想看看大家都在做什么样的项目,遇到了什么样的问题。

你也可以分享这篇文章给你的同事,相信这个思考维度会对他们的架构设计有所启发。

如果想持续获得这样的硬核技术内容,记得关注《前端达人》。我们定期产出 React、Node.js、浏览器原理等深度好文,帮你从表面理解走向本质掌握。

点赞 ✨、分享 🔄、推荐给朋友 👥 ——这是对内容最好的鼓励,也能帮助更多开发者做出更好的技术决策。

下期见!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-02-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端达人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一个比喻:理解关系数据库 vs 文档数据库
  • PostgreSQL:严谨的数据守护者
    • 为什么选PostgreSQL?
    • Node.js 连接 PostgreSQL:深入 pg 库
    • 连接池:避免连接炸裂
    • 实战:数据的CRUD操作
  • MongoDB:灵活的数据冒险家
    • 为什么选MongoDB?
    • Node.js 连接 MongoDB:使用 Mongoose
    • 定义 Schema 和 Model
    • 实战:使用 Mongoose 进行 CRUD
  • 对标对比:何时选PostgreSQL,何时选MongoDB?
  • 实际场景:从决策到实现
    • 场景:构建一个博客系统
  • 深层次的选择标准
    • 1. 数据一致性的权衡
    • 2. 查询模式
    • 3. 运维成本
  • 常见陷阱和优化技巧
    • PostgreSQL 的常见陷阱
    • MongoDB 的常见陷阱
  • 性能基准测试(真实对比)
  • 最后的思考:你真的需要选一个吗?
  • 总结和行动清单
  • FAQ
    • Q:我应该先学 PostgreSQL 还是 MongoDB?
    • Q:可以同时用 PostgreSQL 和 MongoDB 吗?
    • Q:连接池该设多大?
    • Q:MongoDB 是不是都不安全?
    • Q:什么时候应该考虑 sharding(分片)?
  • 互动彩蛋 🎁
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档