前面48篇,你把数据装进过变量、装进过文件、装进过CSV和Excel。今天开门迎接编程路上第三个新台阶——数据库。这一篇不急着写SQL,先把一个根本问题掰开揉碎:CSV用得好好的,为什么全世界的软件都在用数据库?想通了这个问题,后面11篇学起来才不迷路。
一、真实场景:一个被自己数据”噎住”的价格监控
接着第48篇的故事讲。你的价格监控工具勤勤恳恳跑了一个月,price_history.csv 从2行长到了2000多行,每天30分钟一轮,机械键盘和无线鼠标的价格历史一条不落。你很满意——直到某天你想问它几个问题:
- “上周三到今天,机械键盘降了几次?”
- “现在把无线鼠标的目标价从90改成120,顺便告诉我:按新目标价,历史里有几天是’该提醒我’的?”
- “把两个商品按’每降价10元记一次’重新统计一份月报。”
用CSV做这三件事,你得:把2000行全部读进内存、写循环逐行比对字符串时间、自己处理”价格是字符串”的老坑(第48篇坑2)、按条件重新拼一份文件……三个问题写三段几乎重复的代码。更要命的是第四件事——
- 你手滑用Excel打开了
price_history.csv,随手删了两行”看起来重复”的记录,保存。第二天监控工具追加新数据时,文件里混进了两种格式的行尾,csv.DictReader直接读乱了。
这就是CSV的天花板:它只负责”存”,不负责”管”。数据一多、问题一复杂、或者多一只手来碰它,纯文件就开始散架。是时候请专业选手出场了。
二、数据库是什么:从”书堆在仓库”到”图书馆”
先抛开技术,用一个类比建立直觉。
CSV就像一摞纸:信息都在上面,但想找东西只能一页页翻;两摞纸没法互相印证;谁都能随手抽走一页。数据库就像一座图书馆:书(数据)还在,但多了三样关键的东西——
| 图书馆的本事 | 数据库里的对应物 | 解决了什么痛 |
|---|
|————|—————-|————|
| 借阅卡目录:按书名/作者/年代秒查 | 查询能力(SQL) | 不用全屋翻书,问一句话就有答案 |
|---|---|---|
| 入馆登记:每本书有编号、类别填错不收 | 约束(编号唯一、类型检查) | 脏数据进不了门 |
| 借还登记:借出和归档要么都记要么都不记 | 事务 | 不会出现”记了一半”的糊涂账 |
| 多人同时借书不打架 | 并发控制 | 两个程序同时读写不互相覆盖 |
| 管理员提前整理好的专题书架 | 索引 | 2000行秒查,200万行也不慌 |
注意看:数据库不是”更快的CSV”,而是”会管理数据的一整套服务”。CSV是一个文件格式,数据库是一个”系统”——这就是为什么第5篇新阶段(49~60篇)值得单独用12篇来学它。
数据库的”表”:长得像Excel,规矩比Excel硬
数据库里存数据的基本单位叫表(table),一行一条记录、一列一个字段——看着和Excel一模一样。比如你监控工具的数据搬进数据库,长这样:
表 prices
+----+--------+----------+--------+---------------------+
| id | 商品ID | 商品名 | 价格 | 时间 |
+----+--------+----------+--------+---------------------+
| 1 | 1 | 机械键盘 | 172.0 | 2026-10-25 09:30 |
| 2 | 2 | 无线鼠标 | 211.0 | 2026-10-25 09:30 |
+----+--------+----------+--------+---------------------+
但它和Excel有三条硬规矩,每条都恰好治一种”CSV散架病”:
- 每一列有类型:价格列就是数字,你往里塞”一百七”这种文字,数据库直接拒收——治”读回来全是字符串,
9 > 10“的坑; - 每一行有唯一编号(id,叫主键):不可能有两行”完全重复却分不清谁是谁”——治”Excel里手滑删重”的坑;
- 想动数据得先”问”:不能拿文本编辑器直接改文件,得用规定的语言(SQL)告诉数据库你要干什么——治”手滑保存把文件搞坏”的坑。
“问问题”的语言:SQL就是数据库的普通话
前面那四个问题,搬进数据库后长什么样?先看个味道(今天只看不学,第50篇起手把手教):
-- 上周三到今天,机械键盘降了几次?
SELECT COUNT(*) FROM prices
WHERE 商品名 = '机械键盘' AND 时间 >= '2026-10-22';
一句话,不用读全表、不用写循环、不用管字符串比较。SQL(结构化查询语言)就是数据库世界的普通话:你用它”问”(查询)、”存”(插入)、”改”(更新)、”删”(删除),数据库用表回答你。全世界的数据库——不管SQLite、MySQL还是PostgreSQL——说的都是这门语言的方言,学会一种,其他都是口音差异。这也是为什么这个阶段的重点是”想清楚要问什么”,而不是死记语法。
三、亲眼感受:2000行的CSV,谁更快、谁更稳?
光说不练假把式。下面这段代码可以完整运行(只用Python自带库,不用装任何东西),它把同一份价格历史分别塞进CSV和SQLite数据库,然后跑同样的查询,你亲眼看看差别:
# db_vs_csv.py — CSV vs 数据库:同题对比实验
import csv
import os
import random
import sqlite3
import time
random.seed(42)
# ---------- 造数据:2万个商品价格记录 ----------
N = 20000
records = []
for i in range(N):
day = 1 + i % 28
records.append({
"商品名": f"商品{i % 500}",
"价格": round(50 + random.random() * 200, 1),
"时间": f"2026-10-{day:02d} 09:30",
})
# ---------- 方案A:写进CSV ----------
t0 = time.time()
with open("prices.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=["商品名", "价格", "时间"])
writer.writeheader()
writer.writerows(records)
print(f"CSV 写入耗时: {time.time() - t0:.3f} 秒")
# ---------- 方案B:写进SQLite数据库 ----------
if os.path.exists("prices.db"):
os.remove("prices.db")
t0 = time.time()
conn = sqlite3.connect("prices.db")
conn.execute("""
CREATE TABLE prices (
id INTEGER PRIMARY KEY AUTOINCREMENT,
商品名 TEXT NOT NULL,
价格 REAL NOT NULL,
时间 TEXT NOT NULL
)
""")
conn.executemany(
"INSERT INTO prices (商品名, 价格, 时间) VALUES (?, ?, ?)",
[(r["商品名"], r["价格"], r["时间"]) for r in records],
)
conn.commit()
print(f"数据库 写入耗时: {time.time() - t0:.3f} 秒")
# ---------- 同一个查询:商品0 在 10-22 之后有几条记录? ----------
t0 = time.time()
count_csv = 0
with open("prices.csv", encoding="utf-8") as f:
for row in csv.DictReader(f):
if row["商品名"] == "商品0" and row["时间"] >= "2026-10-22":
count_csv += 1
print(f"CSV 查询耗时: {time.time() - t0:.3f} 秒,结果 {count_csv} 条")
t0 = time.time()
count_db = conn.execute(
"SELECT COUNT(*) FROM prices WHERE 商品名 = ? AND 时间 >= ?",
("商品0", "2026-10-22"),
).fetchone()[0]
print(f"数据库 查询耗时: {time.time() - t0:.3f} 秒,结果 {count_db} 条")
conn.close()
跑完你大概会看到这样的结果(数字随机器快慢浮动,趋势一致):
CSV 写入耗时: 0.085 秒
数据库 写入耗时: 0.115 秒
CSV 查询耗时: 0.116 秒,结果 6 条
数据库 查询耗时: 0.004 秒,结果 6 条
三个观察,比”谁快”更重要:
- 2万行这个量级,写入都不慢(数据库略慢一点,因为它还顺手做了”安检”),但查询数据库快了将近30倍——而且数据库那句查询是一行代码,CSV那段是五加一行。数据涨到200万行,CSV查询时间跟着涨100倍,数据库(有了索引之后)几乎不动;
- 两边查询结果一模一样(6条)——数据库不是变魔术,它只是把”逐行翻”这件苦力活接过去了;
- 代码里数据库用的是
?占位符,这是防”SQL注入”的标准姿势(第56篇会讲),现在先记住这个长相。
实验做完了,prices.csv 和 prices.db 都可以删掉。这个实验本身就是今天最好的”跟AI说需求”素材——怎么用见第六节。
四、决策清单:什么时候该请数据库出场?
“数据库这么好,是不是以后什么都用数据库?”——不是。选型和选工具一样,看活儿大小。跟AI讨论需求时,把下面这张清单甩给它,让它帮你判断:
| 你的情况 | 用什么 | 为什么 |
|---|
|———|——-|——-|
| 几十行配置、待办清单、一次性的统计结果 | CSV / JSON / 文本文件 | 人能直接打开看,够用就是最好 |
|---|---|---|
| 几千行以上、要反复按条件查 | 数据库 | 查询快,不用每次全量翻 |
| 要保证”两个人/两个程序同时写不出错” | 数据库 | 并发控制是它的看家本领 |
| 数据之间有关系(订单↔客户↔商品) | 数据库(关系型) | 多表关联是它的主场,第54篇 |
| 只是把分析结果发给别人看 | 导出成 CSV / Excel | 数据库是后台,Excel 是给人看的门面 |
| 程序要上线给很多人用 | 数据库 | 几乎没有例外 |
一句话版本:数据是”路过”还是”住下来”?路过(一次性处理、结果导出)用文件就行;住下来(持续积累、反复查询、多人使用)就该搬进数据库。你的价格历史明显是”住下来”的——所以第48篇结尾说,监控工具会在数据库阶段迎来终极形态。
顺带说清这个阶段的技术选型,免得你被名词吓到:这个阶段我们用 SQLite。它是Python自带的”随身数据库”——不用安装服务、不用配置账号,整个数据库就是一个 .db 文件,但查询语言、约束、事务一样不缺。它和MySQL/PostgreSQL的关系,就像”手机计算器”和”财务室的金蝶系统”:都是计算器,但一个随身练手、一个撑企业级应用。先用SQLite把SQL和数据库思维练熟,将来迁移到大数据库,换的只是”接电话的方言”,思维完全通用。
五、三个必踩的坑(先打疫苗)
坑1:把数据库当”什么都能装的神柜”,反过来也别把文件一棒子打死。新手常见两个极端:要么觉得”CSV太low了,从此只用数据库”——结果写个20行的配置文件也搞一套建表连接,杀鸡用牛刀,徒增复杂度;要么觉得”我数据也不多,数据库学了没用”——结果几万行数据每次全量翻,程序越跑越慢。疫苗:做决定前先回答”数据是路过还是住下来”(第四节的清单)。另外记住:数据库和文件不是敌人,是分工——数据库是后台仓库,CSV/Excel是给人看的门面,第58篇会专门学它俩互相搬运。
坑2:把 .db 文件当普通文件随便折腾。这是数据库新手最疼的一跤:程序运行时,直接用文件管理器把 prices.db 复制一份当备份——拷到的可能是个”写到一半”的坏文件,打开就是”file is not a database”;或者更隐蔽的:用文本编辑器打开 .db 想”看看里面”,随手按了 Ctrl+S——数据库文件是二进制格式,文本编辑器一保存就永久损坏。疫苗:.db 文件交给数据库程序管,人不要碰。备份要用数据库自己的导出命令(第57篇),运行中的数据库别直接复制文件。这一课的所有数据操作都走SQL,就是让你从第一天起养成”隔一层”的习惯。
坑3:一上来就钻SQL语法的牛角尖。另一个极端是把数据库课学成”背命令课”:JOIN有几种写法、范式一二三背得滚瓜烂熟,结果老板问”这个需求数据该怎么存”就傻眼了。疫苗:这个阶段真正的核心是”数据思维”——什么数据放一张表、什么拆两张表、问问题时先想”我要的是哪张表的哪些行”。语法忘了随时能问AI(它SQL写得又快又对),但”该问什么问题”AI替不了你。这也是为什么今天一上来不讲语法先讲概念。
六、跟AI协作的正确姿势(数据库概念特供版)
- 拿”问题清单”去问,不拿”技术名词”去问。别问”我要不要学MySQL”(AI只能反问你干嘛用),要问:”我的价格监控工具跑了三个月,CSV有五万行,我经常想查’某商品最近一个月的最低价’,还想要两个程序同时读写不出错——我该继续用CSV还是上数据库?SQLite适合我吗?”把数据量、查询方式、使用场景说清楚,AI给的选型建议才贴身。
- 让AI当”翻译”,把你的问题翻译成数据问题。比如:”我想查’上周三到今天键盘降了几次’,用数据的思路该怎么想?”期待它回答:”这是一次带条件的计数查询——先想清楚三个要素:查哪张表、按什么条件筛(商品名、时间范围)、要什么结果(条数)。”这种”拆问题”的思路比SQL语句本身值钱十倍。
- 跟AI玩”自考”:让它出题,你先答再对答案。“围绕’数据库和CSV的区别’出5道判断题,先别给答案。”你答完贴回去让它批。答错的地方就是概念的裂缝——比如”数据库查询快是因为它不用读文件”(错,它也读,只是读的方式聪明+有索引),裂缝趁早补上。
- 把第三节的对比实验当对话起点。把实验结果贴给AI:”这是我CSV vs SQLite的实测,查询快了几十倍。如果数据涨到100万行,趋势会怎样?我该在什么时候加索引?”它会顺着数据量和索引(第59篇)给你讲出后面课程的地图——带着自己的实测数据提问,AI的回答质量高一个档次。
七、今日小练习
练习1:跑通对比实验,亲眼看一次”差距”。把第三节的 db_vs_csv.py 原样存下来跑一遍,记录四个耗时。然后把 N 从 20000 改成 200000(20万),再跑一遍,把两轮结果并排写下来。回答一个问题:数据量涨10倍,CSV查询和数据库查询各涨了多少倍?
提示:跑之前看一眼硬盘空间够不够(20万行的CSV大概十几MB,无压力);sqlite3 是Python自带的,不用pip安装。如果20万行跑起来明显变慢,这本身就是最有说服力的答案。
练习2:给你的数据”分个诊”。拿纸笔列出手头或打算做的3个”数据活儿”(比如:记账本、公司通讯录、价格历史、游戏存档、每周菜单),按第四节的清单逐个判断:路过还是住下来?该用文件还是数据库?给每个判断写一句理由。
提示:没有标准答案,重在”给理由”。比如”每周菜单——路过,每周重写一次,20行以内,用CSV给人看还方便打印”。写完可以甩给AI批改:”这是我做的选型判断,帮我挑毛病。”
练习3(概念自考):先自答,再让AI批卷。不看文章,用自己的话回答三个问题:①数据库和CSV最本质的区别是什么?②”数据库是更快的CSV”这句话对不对,为什么?③什么情况下你宁可用CSV也不用数据库?答完把你的答案和这篇文章一起发给AI:”帮我批改,指出我理解偏差的地方。”
提示:②是陷阱题——”快”只是结果之一(而且不总是成立,小数据量下CSV写入更快),本质区别是”管理能力”:约束、事务、并发、查询。如果你的答案里出现”因为数据库不用读文件”,那就是②的坑没躲开,回第二节再读一遍。
下篇预告
下一篇(第50篇):SQLite入门 — 给数据搬个新家。概念讲透了,该动手了。下一篇正式学SQL的第一组动作:建一张表(CREATE TABLE)、往里搬数据(INSERT)、再取出来看(SELECT)——把价格监控的历史数据从CSV搬进数据库,亲眼看着”裸奔一个月的数据”住进带管理员的新房子。SQL比你想象的好上手,因为你要做的只是”把想干的事说清楚”。
发表回复