2.1SQL 学习:先懂数据库概念再学 SQL

2.1SQL 学习:先懂数据库概念再学 SQL

开篇:为什么学SQL前要先搞懂数据库概念

我入行第一年,领导丢给我一个数据库账号,说"去把昨天的订单数据查出来"。我打开Navicat,看到左边一长串陌生的表名,完全不知道从哪里下手。后来硬着头皮学了SQL语法,写了个SELECT * FROM orders,跑出来结果,但完全不明白为什么数据存在"表"里,为什么订单号不能重复。直到有一次我写DELETE语句忘了加WHERE,把整张表清空了,才被迫去搞懂数据库的底层概念。

很多新人学SQL,一上来就背语法,但连"表""字段""主键""索引"是什么都没搞清楚。这样学出来的SQL,写对了是运气,写错了是常态。这一章不讲任何SQL语法,只讲关系型数据库的核心概念。学完之后,你会彻底搞懂:

  • 数据为什么存在"表"里,而不是一个Excel文件

  • 订单号为什么不能重复

  • 用户表和订单表怎么通过"外键"关联

  • 为什么加了索引查询就变快

这些概念是SQL学习的"地基"。地基不牢,后面学再多语法也会在各种报错里反复折腾。

学习前准备:一支笔、一张纸,梳理一下你日常工作中接触到的电商数据(订单、用户、商品),思考它们之间的逻辑关系。

关系型数据库的核心定义

用电商场景说清楚"关系型数据库"

关系型数据库,简单说就是用"表格"来存储数据,并且表格之间可以建立关联的数据库。它和我们平时用的Excel很像,但更强大、更安全、更适合处理海量数据。

在电商系统里,你不会把所有数据塞进一张大表,而是拆分成多张小表:

  • 订单表:存每一笔交易

  • 用户表:存每一个用户的信息

  • 商品表:存每一个商品的详情

然后通过"关系"(比如订单表中的user_id关联用户表的user_id)把这些表连接起来。这就是"关系型"名字的由来。

和非关系型数据库的核心区别

维度 关系型数据库 非关系型数据库
数据存储方式 二维表格(行+列) JSON、键值对、文档等
数据一致性 强一致性(支持事务) 最终一致性
适用场景 订单、用户、库存等需要精确一致的数据 日志、缓存、社交关系等
电商典型代表 MySQL、PostgreSQL、Oracle Redis、MongoDB、Elasticsearch

在电商数据分析工作中的不可替代性

电商的核心业务数据(订单、用户、商品、库存)必须使用关系型数据库,原因有三:

  • 数据一致性:下单扣库存必须同时成功或同时失败,否则会超卖。关系型数据库的事务机制能保证这一点。

  • 复杂查询:分析"买了A商品的用户还买了什么",需要多表关联,这是关系型数据库的强项。

  • 数据完整性:订单号不能重复、用户ID必须存在,关系型数据库的主键和外键约束能自动保证。

我的踩坑经历 :我入行时听说MongoDB很火,就用它来存订单数据。结果写复盘分析时,要统计"每个店铺每个月的GMV",MongoDB的聚合框架复杂得要命,而且经常算错。后来老老实实换回MySQL,用SQL几行就搞定了。电商数据分析,关系型数据库是首选,别折腾

数据库核心概念详解

定义

数据库就是一个存放数据的"仓库"。在电商系统里,一个数据库可能包含:订单表、用户表、商品表、库存表等。

电商场景下的实际作用

  • 隔离不同业务的数据:一个电商公司可能有"交易库""用户库""日志库"

  • 统一管理权限:谁可以读哪个库、写哪个表

  • 方便备份和恢复:整个库可以一键备份

真实案例

天猫的后台,订单数据存在trade_db数据库里,用户信息存在user_db数据库里。数据分析师通常只有trade_db的只读权限,不能修改数据。

SQL 复制代码
-- 查看当前数据库
SELECT DATABASE();

-- 切换到订单库
USE trade_db;

-- 查看该库下所有表
SHOW TABLES;

实操避坑提醒 :不要在生产环境(正式库)里随便建自己的测试表。应该申请一个个人测试库,或者用CREATE TEMPORARY TABLE建临时表,用完自动删除。

表/数据表核心概念详解

定义

是数据库中存储数据的基本单位。它由行和列组成,和Excel里的Sheet非常像。

电商场景下的实际作用

一张表只存一类业务实体。电商系统最常见的三张表:

  • 订单表:记录每一笔交易

  • 用户表:记录每一个注册用户

  • 商品表:记录每一个上架商品

真实案例

SQL 复制代码
-- 订单表结构示例
CREATE TABLE orders (
    order_id VARCHAR(50),
    user_id INT,
    amount DECIMAL(10,2),
    create_time DATETIME
);
SQL 复制代码
-- 查看表结构
DESC orders;

字段/列核心概念详解

定义

字段(也叫列)是表中某一类数据的集合。每个字段有固定的数据类型(数字、文本、日期等)。

电商场景下的实际作用

字段定义了"这张表记录什么信息"。比如订单表必须包含:订单号、用户ID、金额、时间。

真实案例

字段名 数据类型 含义
order_id VARCHAR(50) 订单号(文本)
user_id INT 用户ID(整数)
amount DECIMAL(10,2) 金额(小数,保留两位)
create_time DATETIME 下单时间(日期时间)
SQL 复制代码
-- 查询指定字段
SELECT order_id, amount FROM orders;

避坑提醒

  • 字段类型选错会导致数据丢失。比如用INT存金额,小数会被截断。应该用DECIMAL(10,2)

  • 字段命名不要用拼音首字母(如ddh代表订单号),用清晰的英文或中文。

行/记录核心概念详解

定义

(也叫记录)是表中的一条具体数据。一行就是一条完整的业务记录。

电商场景下的实际作用

订单表中的每一行,代表一笔订单的详细信息。

真实案例

SQL 复制代码
-- 插入一行订单记录
INSERT INTO orders (order_id, user_id, amount, create_time)
VALUES ('ORD001', 1001, 299.00, '2025-01-01 10:23:45');

-- 查询该行
SELECT * FROM orders WHERE order_id = 'ORD001';

上述查询返回的一行数据就是一条记录。

主键核心概念详解

定义

主键 是表中用来唯一标识每一行的字段(或字段组合)。主键的值不能重复,也不能为空。

电商场景下的设置规则

  • 订单表的主键通常是order_id(订单号)

  • 用户表的主键通常是user_id(用户ID)

  • 如果一张表没有自然唯一的字段,可以加一个自增ID作为主键(如id

实际作用

  • 保证数据不重复:同一个订单号不会出现两次

  • 快速查找:通过主键查数据最快

  • 作为外键被其他表引用

真实案例

SQL 复制代码
-- 带主键的订单表
CREATE TABLE orders (
    order_id VARCHAR(50) PRIMARY KEY,  -- 主键
    amount DECIMAL(10,2)
);

-- 尝试插入重复主键会报错
INSERT INTO orders VALUES ('ORD001', 299.00);  -- 成功
INSERT INTO orders VALUES ('ORD001', 399.00);  -- 报错:Duplicate entry

避坑提醒

  • 千万不要用"姓名"做主键。同名同姓的人会冲突,而且姓名可能会改。

  • 不要用业务含义不稳定的字段做主键。比如手机号(用户可能换号)。

  • 复合主键(多个字段组合)是允许的,但会增加复杂度。电商中常见的是订单行表(订单号+商品行号)。

SQL 复制代码
-- 复合主键示例:订单明细表
CREATE TABLE order_items (
    order_id VARCHAR(50),
    line_no INT,
    product_id INT,
    quantity INT,
    PRIMARY KEY (order_id, line_no)
);

我的踩坑经历 :我第一次设计表时,用user_phone做主键。后来一个用户换了手机号,我改不了主键,只能删了重插,关联的数据全乱了。从那以后,所有表都用无业务含义的自增ID做主键。

外键核心概念详解

定义

外键 是用来关联两张表的字段。它指向另一张表的主键。

使用规则

  • 外键的值必须在被引用表的主键中存在(否则会报错)

  • 外键可以为空(比如匿名订单没有用户ID)

实际作用

  • 保证数据一致性:不会出现"订单的用户ID在用户表里不存在"

  • 实现表关联:通过外键可以把订单表和用户表连接起来

电商场景下的真实案例

SQL 复制代码
-- 用户表
CREATE TABLE users (
    user_id INT PRIMARY KEY,
    user_name VARCHAR(50)
);

-- 订单表,user_id是外键
CREATE TABLE orders (
    order_id VARCHAR(50) PRIMARY KEY,
    user_id INT,
    amount DECIMAL(10,2),
    FOREIGN KEY (user_id) REFERENCES users(user_id)
);

-- 正常插入
INSERT INTO users VALUES (1001, '张三');
INSERT INTO orders VALUES ('ORD001', 1001, 299.00);  -- 成功

-- 外键约束阻止插入不存在的user_id
INSERT INTO orders VALUES ('ORD002', 9999, 199.00);  -- 报错:Cannot add foreign key constraint
SQL 复制代码
-- 通过外键关联查询:查询订单对应的用户名
SELECT o.order_id, o.amount, u.user_name
FROM orders o
JOIN users u ON o.user_id = u.user_id;

避坑提醒

  • 外键会降低写入性能(每次插入订单都要检查user_id是否存在)。在数据仓库或分析库中,有时会省略外键约束,但逻辑上仍然保持关联。

  • 删除用户时,如果该用户有订单,会报错。需要先删除订单或设置ON DELETE CASCADE

SQL 复制代码
-- 级联删除:删除用户时自动删除其订单
CREATE TABLE orders (
    order_id VARCHAR(50) PRIMARY KEY,
    user_id INT,
    amount DECIMAL(10,2),
    FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE
);

索引核心概念详解

定义

索引 是一种数据结构,用来加速查询。就像书的目录,让你不用翻遍整本书就能找到内容。

电商场景下的核心作用

  • 加速WHERE条件筛选(如WHERE user_id = 12345

  • 加速ORDER BY排序

  • 加速JOIN关联

适用场景

  • 经常作为查询条件的字段:如user_idorder_status

  • 经常需要排序的字段:如create_time

  • 需要唯一约束的字段:如order_id(主键自动是唯一索引)

大促订单数据查询索引优化真实案例

双11期间,订单表有几千万行。运营要查"用户12345的所有订单"。没有索引时,数据库要扫描全表几千万行,可能几十秒才能返回。加上idx_user_id索引后,直接定位到该用户的几行数据,毫秒级返回。

SQL 复制代码
-- 没有索引时,查看查询计划(全表扫描)
EXPLAIN SELECT * FROM orders WHERE user_id = 12345;
-- type = ALL, rows = 几千万

-- 创建索引
CREATE INDEX idx_user_id ON orders(user_id);

-- 再次查看查询计划(使用索引)
EXPLAIN SELECT * FROM orders WHERE user_id = 12345;
-- type = ref, rows = 少量
SQL 复制代码
-- 联合索引示例:经常按user_id和create_time同时查询
CREATE INDEX idx_user_time ON orders(user_id, create_time);

-- 该索引可以加速以下查询:
SELECT * FROM orders WHERE user_id = 12345 AND create_time > '2025-01-01';
-- 也能加速只按user_id的查询(最左前缀原则)
SELECT * FROM orders WHERE user_id = 12345;
-- 但不能加速只按create_time的查询
SELECT * FROM orders WHERE create_time > '2025-01-01';  -- 不会使用该索引

避坑提醒

  • 索引不是越多越好。每个索引都会占用磁盘空间,并且会降低写入(INSERT、UPDATE、DELETE)的速度。

  • 不要在低区分度的字段上建索引,比如gender(只有男/女),索引几乎无效。

  • 联合索引要遵循"最左前缀"原则。(a,b)索引可以加速WHERE a=1,但不能加速WHERE b=1

我的踩坑经历 :有一次我为了优化查询,在一个大表上建了7-8个索引,结果写入速度慢得离谱,每插入一条数据要等好几秒。后来删掉不必要的索引,只保留最常用的2个,写入速度恢复正常。索引是双刃剑,够用就好

综合实操案例:服饰类目天猫店铺核心业务数据与关系型数据库概念的全匹配映射

案例背景

某服饰类目天猫店铺的核心业务数据包括:

  • 订单:订单号、用户ID、商品ID、数量、金额、下单时间

  • 用户:用户ID、注册时间、会员等级

  • 商品:商品ID、商品名称、类目、价格

请将这些业务数据映射到关系型数据库的概念上:需要建几张表?每张表的主键是什么?表之间如何通过外键关联?哪些字段需要加索引?

分步操作

步骤1:确定需要建几张表

根据业务实体:订单、用户、商品 → 3张表。

步骤2:设计每张表的字段和主键

SQL 复制代码
-- 用户表
CREATE TABLE users (
    user_id INT PRIMARY KEY AUTO_INCREMENT,
    register_time DATETIME,
    vip_level INT
);

-- 商品表
CREATE TABLE products (
    product_id INT PRIMARY KEY AUTO_INCREMENT,
    product_name VARCHAR(100),
    category VARCHAR(50),
    price DECIMAL(10,2)
);

-- 订单表
CREATE TABLE orders (
    order_id VARCHAR(50) PRIMARY KEY,
    user_id INT,
    product_id INT,
    quantity INT,
    amount DECIMAL(10,2),
    create_time DATETIME
);

步骤3:确定外键关联

SQL 复制代码
-- 添加外键约束
ALTER TABLE orders ADD FOREIGN KEY (user_id) REFERENCES users(user_id);
ALTER TABLE orders ADD FOREIGN KEY (product_id) REFERENCES products(product_id);

步骤4:确定需要加索引的字段

SQL 复制代码
-- 经常按时间范围查询
CREATE INDEX idx_orders_create_time ON orders(create_time);

-- 经常查某个用户的订单
CREATE INDEX idx_orders_user_id ON orders(user_id);

-- 经常查某个商品的销售情况
CREATE INDEX idx_orders_product_id ON orders(product_id);

步骤5:验证表关系

SQL 复制代码
-- 查询每个订单的用户名和商品名
SELECT 
    o.order_id,
    u.user_name,
    p.product_name,
    o.amount,
    o.create_time
FROM orders o
JOIN users u ON o.user_id = u.user_id
JOIN products p ON o.product_id = p.product_id
LIMIT 10;

案例小结

通过这个映射,你学会了如何把电商业务需求转化为关系型数据库的表结构设计。这是写SQL之前最重要的准备工作。

📌 电商数据合规提示:在设计用户表时,不要存储用户手机号、地址等敏感信息。如果确实需要,应该加密存储,并且设置严格的访问权限。外键关联的用户ID应使用内部脱敏ID,而不是手机号或身份证。

本章踩坑清单与合规总结

新手常见踩坑

错误 后果 正确做法
用姓名或手机号做主键 数据冲突或无法修改 用无业务含义的自增ID
不建外键,靠程序保证一致性 数据可能不一致 逻辑上保持外键关联,分析库可不加物理外键
索引建太多 写入慢,占用空间 只给常用查询字段加索引
字段类型用错(金额用INT) 小数丢失 金额用DECIMAL,日期用DATETIME
SQL 复制代码
-- 错误示例:金额用INT
CREATE TABLE orders (amount INT);  -- 299.99会被存为299

-- 正确示例
CREATE TABLE orders (amount DECIMAL(10,2));

电商数据合规提示

  • 主键设计:不要使用用户手机号、身份证号作为主键。这些属于个人敏感信息,且可能变更。

  • 外键关联:在设计用户表时,用户ID应使用内部生成的随机ID,而不是手机号。外键关联的字段不能包含敏感信息。

  • 索引和查询:即使你有索引,也不要查询全量用户数据。遵守最小必要原则,只查询分析必需的字段。

结语

关系型数据库的核心概念是SQL学习的"第一块砖"。搞懂数据库、表、字段、行、主键、外键、索引,你才能理解SQL语句为什么这么写、为什么有时候快有时候慢。

有问题的评论区留言,我看到会回复。

相关推荐
~ rainbow~2 小时前
前端转型全栈(四)——常见的错误及解决方案
数据库·oracle·全栈
Cat_Rocky3 小时前
redis哨兵模式
数据库·redis
YoseZang3 小时前
【机器学习】【手工】Streaming Machine Learning 流数据学习 – 应对变化的机器学习方法(一)
人工智能·学习·机器学习
广师大-Wzx3 小时前
一篇文章看懂MySQL数据库(下)
java·开发语言·数据结构·数据库·windows·python·mysql
hef2884 小时前
golang如何使用range over func_golang range over func迭代器使用方法
jvm·数据库·python
chh5634 小时前
C++--模版初阶
c语言·开发语言·c++·学习·算法
qq_380619165 小时前
html如何查看windows
jvm·数据库·python
爱学习的小邓同学5 小时前
MySQL --- MySQL数据库基础
数据库·mysql
wgzrmlrm745 小时前
如何加固SQL环境部署_删除默认安装的示例数据库
jvm·数据库·python