跳转到正文

🗄️ Hello SQL学习 SQL,并了解常用数据库的能力与差异。

22 款可本地运行的数据库 · 浏览器实验 · Docker 验证证据 · 横向选型指南

🎯 典型数据库快速入口 ​

前 5 个为高频使用场景的代表性产品,其余 17 款可在导航栏「更多」下拉中查看完整列表。

数据库类型核心价值快速开始
PostgreSQL 🦄SQL 关系型功能最全面、ACID 标准实现、扩展丰富查看详情 →
MySQL ❤️SQL 关系型Web 应用事实标准、性能优秀、生态成熟查看详情 →
DuckDB 🦆分析型MPP 列式存储、嵌入式分析、SQL 兼容性强查看详情 →
MongoDB 🧬NoSQL 文档JSON 文档模型、横向扩展能力强、开发友好查看详情 →
Redis 🚀NoSQL KV内存高性能、多种数据结构、持久化策略查看详情 →

📊 关键能力横向对比 ​

各数据库在核心功能上的支持方式不同——「关系型」不等于「只能存表格」,「NoSQL」也不等于「没有 ACID」。

能力PostgreSQLMySQLDuckDBMongoDBRedis
ACID 事务✅ 完整支持✅ 完整支持 (InnoDB)❌ 无事务✅ 单文档原子性⚠️ 多命令原子性 (MULTI/EXEC)
JSON 支持✅ jsonb + GIN✅ JSON + 全文索引⚠️ 简单解析✅ 原生 BSON❌ 需字符串序列化
行级锁✅ ROW LEVEL SECURITY⚠️ 应用层实现❌ 无❌ 无❌ 无
分区表✅ 声明式分区⚠️ 分区仅用于分区表❌ 无❌ 无❌ 无
物化视图✅ 原生支持❌ 需外部插件✅ 自动缓存❌ 无❌ 无
流式复制✅ WAL 流复制✅ Binlog 流复制❌ 不适用✅ Replica Set✅ Master-Slave
WASM 版本❌ PGlite 实验❌ 无✅ DuckDB-Wasm✅ MongoDB Atlas Wasm❌ 无

完整选型建议见 数据库对比矩阵。


🧪 WASM 数据库实验台速览 ​

以下数据库可直接在浏览器中运行,无需安装任何软件:

1. SQLite WASM ​

  • 优势: 零依赖、单文件、与 Node.js 版 API 一致
  • 适用: 轻量级离线存储、原型验证、教育演示
  • 体验: 直接在浏览器编写 SQL 并查看结果集

2. DuckDB-Wasm ​

  • 优势: 列式存储、MPP 架构、分析查询性能卓越
  • 适用: 嵌入式数据分析、大规模 CSV/Parquet 处理
  • 体验: 加载大文件进行聚合分析与 OLAP 查询

3. PGlite ​

  • 优势: 完整 PostgreSQL 兼容性、支持扩展
  • 适用: 需要复杂 SQL 特性、函数、触发器的场景
  • 体验: 运行 PostgreSQL 专属 SQL 语句、查看执行计划

4. SurrealDB WASM ​

  • 优势: 图数据库 + 文档数据库 + 关系型数据库三合一
  • 适用: 需要关联查询、图遍历、实时订阅的场景
  • 体验: 编写 SurrealQL 查询语言、查看子图关系

适合目标读者:全栈开发者、前端工程师、数据库初学者、技术爱好者。


📚 SQL 基础学习路线 ​

如果你是数据库新手,建议按以下顺序学习:

  1. 查询与过滤 (/#sql-query) —— SELECT、WHERE、ORDER BY
  2. 聚合、JOIN 与子查询 (/#sql-joins) —— GROUP BY、INNER/LEFT JOIN
  3. CTE 与窗口函数 (/#sql-advanced-query) —— WITH、ROW_NUMBER、RANK
  4. DDL、约束与数据建模 (/#sql-schema) —— CREATE TABLE、PRIMARY KEY、FOREIGN KEY
  5. 事务、锁与并发 (/#sql-transactions) —— BEGIN、COMMIT、ISOLATION LEVEL
  6. 索引与执行计划 (/#sql-indexes-explain) —— B-Tree、HASH、EXPLAIN ANALYZE

适合目标读者:希望系统掌握 SQL 语法的开发者。


🚀 快速上手 ​

bash
git clone https://github.com/xy2401/hello-sql.git && cd hello-sql
npm install
npm run docs:dev          # 默认 http://127.0.0.1:5173,以终端输出为准

以上命令在 hello-sql 仓库根目录执行。环境要求:Node.js 20.19+(20.x)或22.16+,与 package.json 的 engines 一致。按 Ctrl+C 停止开发服务。浏览器需支持本页所用的 WebAssembly 和存储 API。

可以从 WASM 数据库实验台 直接开始运行示例。


SQL 基础 ​

查询与过滤 ​

查询的逻辑顺序 ​

理解 FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT 的逻辑顺序,比背书写顺序更重要。列别名通常不能直接在 WHERE 使用,就是因为过滤发生在投影之前。

NULL 不是普通值 ​

NULL 表示未知或缺失。比较需要 IS NULL,布尔表达式采用三值逻辑。NOT IN 子查询一旦包含 NULL,常产生意外结果;存在性判断优先考虑 EXISTS。

sql
SELECT title, category, score
FROM lessons
WHERE score >= 90
ORDER BY score DESC
LIMIT 10;

💡 在线运行:可在 SQLite 在线工作台 直接执行并观察此 SQL 的结果集。

聚合、JOIN 与子查询 ​

先确定结果粒度 ​

每一行代表什么,是写聚合查询前必须回答的问题。GROUP BY 决定结果粒度;JOIN 前若两边都不是唯一键,行数可能乘法增长。

JOIN 不是“查两个表” ​

  • INNER JOIN 保留匹配组合。
  • LEFT JOIN 保留左侧粒度,右侧缺失补 NULL。
  • 半连接通常用 EXISTS,反连接通常用 NOT EXISTS。
  • 相关子查询是否高效取决于优化器能否改写和索引是否支持。
sql
CREATE TABLE IF NOT EXISTS enrollments (
  lesson_id INTEGER,
  learner TEXT,
  completed INTEGER
);
DELETE FROM enrollments;
INSERT INTO enrollments VALUES (1, 'Alice', 1), (2, 'Alice', 1), (3, 'Bob', 0);

SELECT l.category,
       COUNT(e.learner) AS enrollments,
       SUM(CASE WHEN e.completed = 1 THEN 1 ELSE 0 END) AS completed
FROM lessons AS l
LEFT JOIN enrollments AS e ON e.lesson_id = l.id
GROUP BY l.category
ORDER BY enrollments DESC;

💡 在线运行:可在 SQLite 在线工作台 体验多表连接与条件聚合。

CTE 与窗口函数 ​

CTE 给复杂查询命名,但它是否物化取决于数据库和提示。窗口函数不会像 GROUP BY 那样折叠行,而是在分区内计算排名、累计、移动平均和前后值。

常用窗口维度 ​

PARTITION BY 决定分组,ORDER BY 决定窗口顺序,Frame 决定当前行看到的范围。默认 Frame 在有重复排序键时可能不是“截至当前物理行”,应显式理解 ROWS 与 RANGE。

sql
WITH ranked AS (
  SELECT title, category, score,
         DENSE_RANK() OVER (
           PARTITION BY category
           ORDER BY score DESC
         ) AS category_rank
  FROM lessons
)
SELECT * FROM ranked
ORDER BY category, category_rank;

💡 在线运行:可在 SQLite 在线工作台 执行窗口排名查询。

DDL、约束与数据建模 ​

Schema 不只是存储布局,也是数据契约。NOT NULL、CHECK、UNIQUE、外键和正确的数据类型,应尽量在数据库边界表达。

建模原则 ​

  1. 先确定实体身份和业务唯一性,再决定代理主键。
  2. 把必须始终成立的不变量写成约束。
  3. 规范化减少更新异常;反规范化必须由可测的读取收益驱动。
  4. JSON 适合边界字段,不应成为逃避关系建模的默认容器。
sql
CREATE TABLE IF NOT EXISTS learners (
  id INTEGER PRIMARY KEY,
  email TEXT NOT NULL UNIQUE,
  display_name TEXT NOT NULL,
  created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
);

INSERT OR IGNORE INTO learners(id, email, display_name)
VALUES (1, 'alice@example.com', 'Alice');

SELECT * FROM learners;

💡 在线运行:可在 SQLite 在线工作台 验证 DDL 与唯一约束。

事务、锁与并发 ​

事务把一组读写变成一个失败边界。ACID 并不意味着所有并发异常自动消失;隔离级别、锁粒度、MVCC 快照和业务重试共同决定可见行为。

工程检查表 ​

  • 事务必须尽量短,避免在事务中等待网络调用。
  • 更新顺序保持一致,减少死锁。
  • Serializable 失败需要重试策略。
  • “读后写”要验证丢失更新,不能只依赖应用内判断。
sql
BEGIN;
UPDATE lessons SET score = score + 1 WHERE category = 'SQL 基础';
SELECT title, score FROM lessons WHERE category = 'SQL 基础';
ROLLBACK;

SELECT title, score FROM lessons WHERE category = 'SQL 基础';

💡 在线运行:可在 SQLite 在线工作台 验证事务原子回滚。

索引与执行计划 ​

索引是额外维护的数据结构,用写入、存储和缓存换取特定访问路径。组合索引的列顺序应服务过滤、连接和排序,而不是按字段“重要程度”排列。

不靠猜测优化 ​

  1. 用真实参数和数据分布获取执行计划。
  2. 区分估算行数与实际行数。
  3. 检查扫描、连接算法、排序和临时结果。
  4. 修改索引或 SQL 后重新测量整体工作负载。
sql
CREATE INDEX IF NOT EXISTS idx_lessons_category_score
ON lessons(category, score DESC);

EXPLAIN QUERY PLAN
SELECT title, score
FROM lessons
WHERE category = 'SQL 基础'
ORDER BY score DESC;

💡 在线运行:可在 SQLite 在线工作台 查看执行计划与索引命中。

Released under the MIT License.