SQL进阶之旅 Day 2:高效的表设计与规范:从基础到实战

【SQL进阶之旅 Day 2】高效的表设计与规范:从基础到实战

开篇

在数据库开发中,一个良好的表设计不仅能够提高查询效率,还能避免冗余数据和一致性问题。本文作为"SQL进阶之旅"系列的第2天,将重点介绍高效的表设计与规范,包括主键、外键、约束以及范式的应用。我们将通过理论讲解、代码示例和实际案例,帮助你掌握这些关键技能。

理论基础

1. 主键(Primary Key)

主键是用于唯一标识表中每一行记录的字段或字段组合。主键必须满足以下条件:

  • 唯一性:每个值都必须唯一。
  • 非空性:主键列不允许为NULL。

主键通常用于加速查询操作,尤其是在频繁进行JOIN操作时。

2. 外键(Foreign Key)

外键是指向另一个表主键的字段,用于维护表之间的关联关系。外键约束可以防止非法数据插入,并确保引用完整性。

3. 约束(Constraints)

除了主键和外键之外,常见的约束还包括:

  • NOT NULL:字段不能为空。
  • UNIQUE:字段值必须唯一。
  • CHECK:字段值必须满足特定条件。
  • DEFAULT:字段未指定值时使用默认值。

4. 范式(Normalization)

范式是一组规则,用于减少数据冗余并提高数据一致性。常见的范式有:

  • 第一范式(1NF):消除重复组,确保每列原子化。
  • 第二范式(2NF):在1NF基础上,消除部分依赖。
  • 第三范式(3NF):在2NF基础上,消除传递依赖。

适用场景

高效的表设计适用于以下业务场景:

  • 高频读写操作的系统,如电商平台订单管理。
  • 数据一致性要求高的金融系统。
  • 多表关联查询较多的数据分析平台。

例如,在电商系统中,如果订单表没有合理的主键和外键约束,可能会导致订单重复、用户信息不一致等问题。

代码实践

我们以一个简单的电商平台为例,展示如何设计高效的表结构。

1. 创建用户表(users)

-- 用户表
CREATE TABLE users (user_id INT PRIMARY KEY AUTO_INCREMENT, -- 主键,自动递增username VARCHAR(50) NOT NULL UNIQUE, -- 唯一用户名,不能为空email VARCHAR(100) NOT NULL,          -- 邮箱,不能为空created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- 默认创建时间
);

2. 创建商品表(products)

-- 商品表
CREATE TABLE products (product_id INT PRIMARY KEY AUTO_INCREMENT, -- 主键product_name VARCHAR(100) NOT NULL,        -- 商品名称price DECIMAL(10, 2) NOT NULL CHECK (price > 0), -- 价格必须大于0stock INT NOT NULL DEFAULT 0               -- 库存,默认为0
);

3. 创建订单表(orders)

-- 订单表
CREATE TABLE orders (order_id INT PRIMARY KEY AUTO_INCREMENT,user_id INT NOT NULL,order_date DATE NOT NULL,total_amount DECIMAL(10, 2) NOT NULL,FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE -- 外键,级联删除
);

4. 创建订单详情表(order_details)

-- 订单详情表
CREATE TABLE order_details (order_detail_id INT PRIMARY KEY AUTO_INCREMENT,order_id INT NOT NULL,product_id INT NOT NULL,quantity INT NOT NULL CHECK (quantity > 0),unit_price DECIMAL(10, 2) NOT NULL,FOREIGN KEY (order_id) REFERENCES orders(order_id) ON DELETE CASCADE,FOREIGN KEY (product_id) REFERENCES products(product_id) ON DELETE RESTRICT -- 限制删除
);

5. 插入测试数据

-- 插入用户
INSERT INTO users (username, email) VALUES ('john_doe', 'john@example.com');-- 插入商品
INSERT INTO products (product_name, price, stock) VALUES ('iPhone 14', 7999.99, 10);-- 插入订单
INSERT INTO orders (user_id, order_date, total_amount)
VALUES (1, '2023-10-01', 7999.99);-- 插入订单详情
INSERT INTO order_details (order_id, product_id, quantity, unit_price)
VALUES (1, 1, 1, 7999.99);

6. 查询示例:获取用户的订单及商品信息

SELECT u.username,o.order_id,p.product_name,od.quantity,od.unit_price,(od.quantity * od.unit_price) AS total_item_price
FROM users u
JOIN orders o ON u.user_id = o.user_id
JOIN order_details od ON o.order_id = od.order_id
JOIN products p ON od.product_id = p.product_id;

执行原理

1. 主键索引

主键会自动创建一个聚簇索引(Clustered Index),使得查询速度更快。MySQL使用InnoDB引擎时,主键决定了数据的物理存储顺序。

2. 外键约束

当插入或更新order_details表中的product_id时,数据库会检查products表中是否存在该ID。如果不存在,则拒绝操作。

3. JOIN操作优化

多表JOIN操作时,建议:

  • 在JOIN字段上建立索引(尤其是外键字段)。
  • 尽量避免在WHERE子句中对JOIN字段进行函数操作。

4. 查询执行计划分析

我们可以使用EXPLAIN来查看查询执行计划:

EXPLAIN SELECT u.username,o.order_id,p.product_name,od.quantity,od.unit_price,(od.quantity * od.unit_price) AS total_item_price
FROM users u
JOIN orders o ON u.user_id = o.user_id
JOIN order_details od ON o.order_id = od.order_id
JOIN products p ON od.product_id = p.product_id;

输出结果如下(简化版):

idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra
1SIMPLEusersindexPRIMARYPRIMARY41Using index condition; Using where
1SIMPLEordersrefuser_iduser_id4example.users.user_id1Using where
1SIMPLEorder_detailsreforder_idorder_id4example.orders.order_id1Using where
1SIMPLEproductseq_refPRIMARYPRIMARY4example.order_details.product_id1NULL

从执行计划可以看出,所有JOIN操作都使用了索引,查询效率较高。

性能测试

1. 测试环境

  • MySQL 8.0
  • InnoDB引擎
  • 表规模:users(10万条)、orders(50万条)、order_details(100万条)

2. 查询性能对比

查询类型平均耗时(优化前)平均耗时(优化后)
单表查询(无索引)500ms50ms
多表JOIN查询800ms120ms

优化手段:

  • orders.user_idorder_details.order_idorder_details.product_id上添加索引。
  • 使用覆盖索引(Covering Index)减少回表查询。

最佳实践

1. 主键选择

  • 使用自增整数(INT/AUTO_INCREMENT)作为主键,避免UUID带来的碎片问题。
  • 对于高并发写入场景,考虑使用BIGINT代替INT

2. 外键使用注意事项

  • 不要滥用外键,避免复杂的级联操作影响性能。
  • 如果业务逻辑已由程序层保证,可以适当放宽外键约束。

3. 索引优化策略

  • 在经常查询的字段上建立索引。
  • 对于频繁更新的字段,避免过多索引。
  • 使用联合索引来支持复合查询条件。

4. 范式与反范式的权衡

  • 范式:适用于写多读少的系统,保证数据一致性。
  • 反范式:适用于读多写少的系统,减少JOIN操作。

案例分析:电商平台订单查询慢的问题

问题描述

某电商平台在高峰期发现“用户订单查询”响应时间超过2秒,严重影响用户体验。

分析过程

  1. 查看SQL语句:涉及多个JOIN操作。
  2. 使用EXPLAIN分析:发现order_details表缺少索引。
  3. 添加索引后,查询时间下降至200ms。

解决方案

  • order_details.order_id上添加索引。
  • orders.user_id也添加索引,优化JOIN效率。

总结

今天我们学习了高效的表设计与规范,包括主键、外键、约束和范式的应用。通过合理设计表结构和使用索引,我们可以显著提升查询性能。以下是今天学到的核心技能:

  • 如何设计主键和外键以保证数据一致性。
  • 如何使用约束确保数据质量。
  • 如何通过范式减少数据冗余。
  • 如何通过索引优化多表JOIN查询。

下一天内容预告

明天我们将进入基础查询优化技巧,学习如何通过WHERE条件优化和JOIN优化进一步提升查询性能。敬请期待!

参考资料

  1. MySQL官方文档 - Constraints
  2. PostgreSQL官方文档 - Constraints
  3. SQLZoo - SQL Tutorial
  4. W3Schools - SQL Tutorial
  5. High Performance MySQL

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/82052.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java—— IO流的应用

带权重的点名系统 案例要求 文件中有学生的信息,每个学生的信息独占一行。包括学生的姓名,性别,权重 要求每次被抽中的学生,再次被抽中的概率在原先的基础上降低一半。 本题的核心就是带权重的随机 分析 权重,权重和…

Docker中部署Alertmanager

在 Docker 中部署 Alertmanager(通常与 Prometheus 告警系统配合使用)的步骤如下: 一、拉取镜像prom/alertmanager docker pull prom/alertmanager二、 创建 Alertmanager 配置文件 首先准备Alertmanager的配置文件 alertmanager.yml(如存…

【大模型面试每日一题】Day 27:自注意力机制中Q/K/V矩阵的作用与缩放因子原理

【大模型面试每日一题】Day 27:自注意力机制中Q/K/V矩阵的作用与缩放因子原理 📌 题目重现 🌟🌟 面试官:请解释Transformer自注意力机制中Query、Key、Value矩阵的核心作用,并分析为何在计算注意力分数时…

AI+能碳管理系统:全生命周期碳管理

在"双碳"目标的时代背景下,AI赋能的能碳管理系统正在重新定义企业碳管理的边界与深度。这套系统犹如一位不知疲倦的碳管家,从原材料采购到产品报废,在每一个价值环节编织起精密的碳管理网络,实现从微观设备到宏观战略的…

k8s1.27版本集群部署minio分布式

需求: 1.创建4个pv,一个pv一个minio-pod。使用sts动态分配pvc(根据存储类找到pv)。----持久化 2.暴露minio的9001端口。(nodeport)----管理界面 镜像:minio/minio:RELEASE.2023-03-20T20-16-18Z--->换国内源 说明…

使用 OpenCV 实现 ArUco 码识别与坐标轴绘制

🎯 使用 OpenCV 实现 ArUco 码识别与坐标轴绘制(含Python源码) Aruco 是一种广泛用于机器人、增强现实(AR)和相机标定的方形标记系统。本文将带你一步一步使用 Python OpenCV 实现图像中多个 ArUco 码的检测与坐标轴…

Qt 控件发展历程 + 目标(1)

文章目录 声明简述控件的发展历程学习目标QWidget属性 简介:这篇文章只是一个引子,介绍一点与控件相关的但不重要的内容(浏览浏览即可),这一章节最为重要的还是要把之后常用且重要的控件属性和作用给学透,学…

socc 19 echash论文部分解读

前言:论文还是得吃透才行,不然很多细节有问题 q1 object和data chunck哪一个大 根据论文,一个 data chunk 通常比一个 object 大,因为它是由多个 object 组合而成的 。 论文中提到,cross-coding 会将多个 object 组合…

w~自动驾驶~合集1

我自己的原文哦~ https://blog.51cto.com/whaosoft/12371169 #世界模型和DriveGPT这类大模型到底能给自动驾驶带来什么ne 以下分享大模型与自动驾驶结合的相关工作9篇论 1、ADAPT ADAPT: Action-aware Driving Caption Transformer(ICRA2023) A…

【paddle】常见的数学运算

根据提供的 PaddlePaddle 函数列表,我们可以将它们按照数学运算、逻辑运算、三角函数、特殊函数、统计函数、张量操作和其他操作等类型进行分类。以下是根据函数功能进行的分类: 取整运算 Rounding functions 代码描述round(x)距离 x 最近的整数floor(…

绘制音频信号的各种频谱图,包括Mel频谱图、STFT频谱图等。它不仅能够绘制频谱图librosa.display.specshow

librosa.display.specshow 是一个非常方便的函数,用于绘制音频信号的各种频谱图,包括Mel频谱图、STFT频谱图等。它不仅能够绘制频谱图,还能自动设置轴标签和刻度,使得生成的图像更加直观和易于理解。 ### 函数签名 python libros…

DDR DFI 5.2 协议接口学习梳理笔记01

备注:本文新增对各种时钟含义做了明确定义区分,避免大家产生误解,这也是5.2版本新引入的。 1. 前言 截止2025年5月,DFI协议最新版本为 5.2,我们首先看一下过去几代的演进: DFI全称DDR PHY Interface,是一种接口协议,定义了 Controller 和 PHY 之间接口的信号、时序以…

windows篡改脚本提醒

✅ 功能简介 该监控系统具备如下主要功能: 📁 目录监控 实时监听指定主目录及其所有子目录内文件的变动情况。 🔒 文件哈希校验 对文件内容生成 SHA256 哈希,确保变更检测基于内容而非时间戳。 🚫 排除机制 支…

文章记单词 | 第102篇(六级)

一,单词释义 apologize /əˈpɒlədʒaɪz/ v. 道歉;认错discharge /dɪsˈtʃɑːrdʒ/ v./n. 排出;释放;解雇; dischargequiver /ˈkwɪvər/ v./n. 颤抖;抖动;箭筒plantation /plnˈteɪʃ…

【DCGMI专题1】---DCGMI 在 Ubuntu 22.04 上的深度安装指南与原理分析(含架构图解)

目录 一、DCGMI 概述与应用场景 二、Ubuntu 22.04 系统准备 2.1 系统要求 2.2 环境清理(可选) 三、DCGMI 安装步骤(详细图解) 3.1 安装流程总览 3.2 分步操作指南 3.2.1 系统更新与依赖安装 3.2.2 添加 NVIDIA 官方仓库 3.2.3 安装数据中心驱动与 DCGM 3.2.4 服务…

主成分分析(PCA)法例题——给定协方差矩阵

已知样本集合的协方差矩阵为 C x 1 10 [ 3 1 1 1 3 − 1 1 − 1 3 ] {\bm C}_x \frac{1}{10} \begin{bmatrix} 3 & 1 & 1 \\ 1 & 3 & -1 \\ 1 & -1 & 3 \end{bmatrix} Cx​101​ ​311​13−1​1−13​ ​ 使用PCA方法将样本向量降到二维 。 求解 计…

uni-app(4):js语法、css语法

1 js语法 uni-app的js API由标准ECMAScript的js API 和 uni 扩展 API 这两部分组成。标准ECMAScript的js仅是最基础的js。浏览器基于它扩展了window、document、navigator等对象。小程序也基于标准js扩展了各种wx.xx、my.xx、swan.xx的API。node也扩展了fs等模块。uni-app基于E…

Idea 配合 devtools 依赖 实现热部署

核心依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency> yaml配置 spring: #…

leetcode513.找树左下角的值:递归深度优先搜索中的最左节点追踪之道

一、题目本质与核心诉求解析 在二叉树算法问题中&#xff0c;"找树左下角的值"是一个典型的结合深度与位置判断的问题。题目要求我们找到二叉树中最深层最左边的节点值&#xff0c;这里的"左下角"有两个关键限定&#xff1a; 深度优先&#xff1a;必须是…

Python入门手册:Python基础语法

Python是一种简洁、易读且功能强大的编程语言&#xff0c;非常适合初学者入门。无论你是编程新手&#xff0c;还是有一定编程基础但想学习Python的开发者&#xff0c;掌握Python的基础语法都是迈向高效编程的第一步。本文将详细介绍Python的基本语法&#xff0c;包括变量和数据…