FDE Times 数据在招 FDE 职位 863▼55 近 7 天在招职位数的变化(同口径比较):不计入本周新开始追踪的公司的职位近 7 天新增 71在招公司 181支持远程 24%美国薪资中位数 $200k招聘最多 Palantir 95
ENVI

前线部署工程师(FDE)的专业媒体

书籍与课程

接手没人设计过的客户数据库,先学哈佛这门免费 SQL 课

CS50 SQL 用七周讲透查询、表设计和扩展,练习用真实数据,从 SQLite 讲到 PostgreSQL。

分享微博

要点速览

  • CS50 SQL 在 OpenCourseWare 上免费开放,共七周,从第 0 周的查询讲到第 6 周的扩展。
  • 对 FDE 来说,最有价值的是第 2 周:范式化、主键、外键和 ER 图。
  • 课程先用 SQLite,再过渡到 PostgreSQL 和 MySQL,并讲解复制和预处理语句。
CS50 SQL 的七周路径,从第 0 周“查询”到第 6 周“扩展”,第 2 周“设计”以橙色突出显示。下方是一个前后对比示例。之前:orders 表中客户名称靠手工输入,出现“ABC Company”和“ABC Co”两种写法,报表因此统计出 2 个客户。之后:数据拆分为 customers 和 orders 两张表,用外键关联;数据库拒绝了 customer_id = 99 的那一行,因为该客户不存在。
CS50 SQL 第 2 周讲范式化:客户名称只存在一张表里,外键在脏数据进入报表之前就把它拦下。

哈佛有一门只教一种语言的免费课程。CS50’s Introduction to Databases with SQL(通常简称 CS50 SQL)的课程主页写得很直白:这门课完全围绕 SQL。

不是哈佛学生也能学。所有讲座都放在 OpenCourseWare 上;如果需要证书,可以另外通过 edX 获取。

对想成为前线部署工程师(FDE)的人来说,这门课不是出于好奇随便看看的。客户现场的项目,往往始于一个不是你写的数据库,外加一份没人记得是谁建的电子表格。表设计错了,建在上面的一切,从仪表盘到 Agent,也都跟着错。

两位讲师,七周,一种语言

课程由 David J. Malan 和 Carter Zenke 讲授。Harvard Online 还列出 Zenke 是 Harvard Extension School 的 Preceptor。课程共七周,编号从第 0 周到第 6 周:查询(Querying)、关联(Relating)、设计(Designing)、写入(Writing)、视图(Viewing)、优化(Optimizing)和扩展(Scaling)。

这个顺序对学习者很合理。先要能读数据、理解表与表如何关联,才谈得上自己设计表、写入数据、自动化和优化。

课程先用 SQLite,因为它小巧、便于携带,到最后才引入 PostgreSQL 和 MySQL。练习用的是真实数据,而不是玩具表。

CS50 SQL 也不同于 CS50x。CS50x 广泛覆盖计算机科学,涉及 C、Python、SQL 和 JavaScript;CS50 SQL 只深挖 SQL。两门可以同时学,也可以只学 CS50 SQL。

一家公司算成两家:第 2 周的教训

最有价值的内容在第 2 周“设计”。课程教你把现实世界的实体和关系建模成表,选择合适的数据类型,并通过范式化消除重复、降低出错概率。讲义把这种拆分数据的做法称为 normalizing(范式化),并用 ER 图画出关系。

设想一家物流客户发来一份订单文件,每一行都记录了下单公司的名称。在 1,000 行数据里,同一个客户可能这里写成“ABC Company”,那里写成“ABC Co”。按客户统计营收的报表就会把一家公司拆成两家,任何查询都救不回来。

范式化正好解决这个问题。建一张 customers 表,以 id 为主键,orders 表只存 customer_id。第 2 周的讲座给出两条值得记住的约束:主键必须唯一;外键的值必须存在于关联表的主键列中。

有一步不能省:外键本身不会把“ABC Company”和“ABC Co”合并成一个。导入数据之前,仍然要清理名称的各种写法,在 customers 中合并成一行,再把每条已有订单映射到这个 id。

清理完成后,SQLite 中的最小版本大致如下:

PRAGMA foreign_keys = ON;

CREATE TABLE customers (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL UNIQUE
);

CREATE TABLE orders (
  id INTEGER PRIMARY KEY,
  customer_id INTEGER NOT NULL,
  created_at TEXT,
  FOREIGN KEY (customer_id) REFERENCES customers(id)
);

INSERT INTO customers (id, name) VALUES (1, 'ABC Company');
INSERT INTO orders (customer_id, created_at) VALUES (1, '2026-10-01');  -- 有效
INSERT INTO orders (customer_id, created_at) VALUES (99, '2026-10-01'); -- 被拒绝

第一条订单插入有效;最后一行指向不存在的 99 号客户,数据库会直接拒绝,而不是让错误流进报表。公司名称现在只存在一个地方,改一次,所有订单都随之更正。

开始一个新项目时,第一件事是画出客户数据库的 ER 图。如果发现某张表同时存着客户名称和订单明细,那就是写任何代码之前需要先问清楚的地方。

视图管业务逻辑,索引管速度

第 4、5 周“视图”和“优化”讲的两个工具,新手常常混淆。视图把反复运行的查询自动化;索引让查询跑得更快。

在客户现场,这个区别决定了你要做什么。运营团队每天都问“哪些订单延误超过三天?”,就写一个视图,让所有人复用同一个定义。同一个问题在大表上跑得慢,就需要索引。

视图让整个团队用同一个定义;索引只是让查询更快返回。课程还讲了如何把 SQL 接入 Python 和 Java,这正是应用代码在实际中与数据库协作的方式。

新手常犯的两个错误

第一个是用 SQLite 时忘了 PRAGMA foreign_keys = ON。不开启它,SQLite 不会强制执行外键,上面那条指向 99 号客户的 INSERT 就会悄无声息地通过。建议:每个连接都开启,然后故意插入一行坏数据,确认约束确实生效。

第二个是看到索引能加速查询,就给每一列都建索引。每次写入都要更新所有索引,还会占用额外存储。更稳妥的做法是只给慢查询的 WHERE 或 JOIN 子句中真正出现的列建索引,并在前后各测一次。

从 SQLite 到数据库服务器,以及 SQL 注入陷阱

第 6 周“扩展”点明了许多演示略过的一点:SQLite 是嵌入式数据库,而 MySQL 和 PostgreSQL 是数据库服务器。这一周的讲座还讲了复制,客户系统一旦用户多起来,你就会碰到它。

同样在第 6 周,课程讲解了如何在 MySQL 中用预处理语句防止 SQL 注入。对 FDE 来说,这是必备技能。如果你做的工具接收用户输入,并直接拼接进针对客户真实数据运行的 SQL,一条恶意输入就足以让整张表暴露。

不要拼接字符串,而是在语句中用 ? 作占位符,再把值传进去:

PREPARE find_orders FROM
  'SELECT id, created_at FROM orders WHERE customer_id = ?';
SET @cid = 1;
EXECUTE find_orders USING @cid;
DEALLOCATE PREPARE find_orders;

@cid 的值只会被当作数据,永远不会成为语句的一部分。审查任何接触客户数据库的代码时,这是第一件要检查的事。

按什么顺序学,简历上写什么

如果你已经写了几年 SQL,可以快速浏览第 0、1 周,把大部分时间花在第 2 周和第 6 周。这两周最贴近客户现场的工作:设计表,以及把数据库带进真实环境。

如果你只用过 ORM,就按顺序学完七周,因为每一周都建立在前一周之上。

学完之后,把成果写进简历,而不只是写“会 SQL”。加一行说明你如何把一份真实数据集范式化、设了哪些约束、加了哪些索引,并附上代码仓库链接。

阅读 FDE 岗位描述时,如果看到“data modeling”或“customer data”这类字眼,就准备好一个范式化案例和一张自己画的 ER 图带去面试。这是证明你真正做过、而不只是学过的最具体的方式。

在客户现场,第一个问题通常不是“哪个模型最好”,而是“这张表能不能信”。CS50 SQL 能帮你在客户想到要问之前就给出答案。

这篇文章对你有帮助吗?

4 个信源
路线图上的下一篇 · 阶段 1: 基础认知从 FDE 视角重读吴恩达机器学习课程新版用 Python 取代 Octave,正是客户现场常见的 notebook,每周 10 小时约两个月学完。