从增删改查到性能优化:一份能直接落地的 SQL 完整学习笔记
SQL 这东西,说起来简单,就是“对数据库说话”,但真正能把话说利索的人其实不多。我在带新人和做技术评审时见过太多情况:CRUD 写得飞起,一碰到多表关联、去重统计、条件优先级就开始翻车;或者同样的查询需求,别人 0.1 秒出结果,你的 SQL 跑 10 秒还顺带把数据库锁了半分钟。这篇文章的目标很直接——用一篇文章的篇幅,把 SQL 里的数据定义、数据操作和数据查询三大块从原理到实操讲透,顺手把 sql 去重、between and 边界、where 中 and 和 or 的优先级、with as 临时结果集、窗口函数这些高频踩坑点一并解决。适合零基础入门,也适合干了两三年但始终靠百度拼 SQL 的同学做一次系统梳理。
先说清楚:这里的 SQL 指的是结构化查询语言本身,不是某个具体数据库产品的方言。文中示例在 SQLite、MySQL、PostgreSQL、SQL Server 上基本都能跑通,个别语法差异我会单独标注。
1. 先搞懂 SQL 的三大门派:DDL、DML、DQL
1.1 为什么必须区分这三种语句?
很多初学者学 SQL 就是背单词,select 是查、insert 是插、create 是建表,背完就上手。这种学法最大的问题是,你根本不知道数据库背后在干什么,遇到报错只能瞎试。
其实 SQL 语句按功能分,就是三大类:
- 数据定义语言(DDL,Data Definition Language):负责“建房子”——建库、建表、改表结构、删表。关键词是 create、alter、drop。
- 数据操作语言(DML,Data Manipulation Language):负责“搬家具”——往表里插数据、改数据、删数据。关键词是 insert、update、delete。
- 数据查询语言(DQL,Data Query Language):负责“看房子”——按照各种条件查数据。关键词核心就是 select。
为什么要分这么清?因为不同类型的语句,数据库对它们的处理方式完全不同。DDL 语句执行时通常会隐式提交事务,意思是它一旦执行成功就立刻生效,你没法回滚(在 MySQL 里尤其需要注意)。DML 语句则可以配合事务控制,做到“后悔了还能撤销”。DQL 则只读不改,理论上无论怎么执行都不会破坏数据。理解这一点,你至少不会在生产环境随手 drop 一张表还指望能找回来。
1.2 一本书学 SQL 的最高效路径
我见过太多人学 SQL 的方式,是买一本几百页的大部头,从第一章数据库原理开始读,结果读到第三章就放弃了。说实话,SQL 是门实操语言,正确姿势应该是“带着问题查文档 + 动手建表跑数据”。建议的学习顺序是:
- 第一周:把 DDL 过一遍,自己动手建三张有关联的表(比如用户表、订单表、商品表),反复改字段结构。
- 第二周:主攻 DQL 的单表查询,把 where、group by、order by、limit 用熟。
- 第三到四周:啃多表 join、子查询、窗口函数,配合实际业务问题去写。
- 随时补充:遇到 DML、事务、索引优化的实际问题就专项突破。
我自己带人的时候总是建议他们用 SQLite 起步,因为它零配置、不需要安装数据库服务端,一个文件就是整个库,特别适合练手。等你把 SQL 逻辑练通了,再去摸 SQL Server 或者 MySQL 的安装配置,会发现语言本身根本没变,变的只是环境细节。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据定义(DDL):把表的骨架搭对,后面才不遭罪
2.1 建表语句的正确打开方式
建表是数据库设计的落地环节。语法本身不复杂:
sql复制create table if not exists user_info (
id integer primary key autoincrement,
username varchar(32) not null unique,
email varchar(64) not null,
age integer default 18,
created_at timestamp default current_timestamp
);
这段代码的意思是:创建一张用户信息表,包含自增主键 id、不允许重复的用户名、必填的邮箱、默认年龄 18,以及自动记录创建时间。每一行定义里,除了字段名和类型,后面的 not null、unique、default 这些都属于约束条件。
在实际工作中,我建议即使是做临时表,也要养成写约束的习惯。很多初级工程师觉得约束麻烦,数据先进去再说,结果就是表里一堆重复的脏数据,清洗的时候欲哭无泪。
另一个重要的点是字段类型的选择。以数字为例,MySQL 里有 tinyint、int、bigint 之分,范围不同,占用存储空间也不同。年龄用 tinyint 就够(0 到 255),订单金额要看单位——如果是分,int 能存 21 亿,大概 2000 多万人民币,够用;如果直接存元且涉及大额流水,就得考虑 decimal 或者 bigint。选字段类型的原则是:够用就好,别动不动就 bigint 铺满全表,那是在给数据库加无谓的负担。
2.2 改表和删表:动手之前先问自己三句话
表结构不是一成不变的,业务需求一变,就要用 alter table 来调整:
sql复制-- 新增字段
alter table user_info add column phone varchar(20);
-- 修改字段类型(MySQL 语法)
alter table user_info modify column age smallint default 18;
-- 删除字段
alter table user_info drop column phone;
-- 给字段加索引(查询加速的关键)
create index idx_user_email on user_info(email);
-- 删除整张表(慎用!)
drop table if exists user_info;
改表结构这件事,开发环境里随便折腾,生产环境里就是高危操作。在改任何一张线上表之前,我都要问自己三句话:第一,这个改动会不会锁表?锁表多久?会不会影响正在运行的业务?第二,有没有备份?能不能回滚?第三,有没有通知到所有使用这张表的同事?
关于锁表多说一句:MySQL 5.6 之前,alter table 会锁住整张表,期间所有的读写都卡住。现在大部分版本支持在线 DDL,但也不是完全不锁,特别是大数据量下加索引
