当前位置: 首页 > news >正文

软考(软件设计师)数据库原理-SQL

一、SQL基本数据类型

SQL 数据类型速查表

类别数据类型说明范围/示例适用场景
整数类型INT / INTEGER标准整数类型-2³¹ 到 2³¹-1 (-2,147,483,648 到 2,147,483,647)ID、年龄、数量等
SMALLINT小范围整数-32,768 到 32,767小范围数值
BIGINT大范围整数-2⁶³ 到 2⁶³-1大额订单号、时间戳
TINYINT极小整数 (MySQL)0 到 255 或 -128 到 127状态码、布尔值模拟
小数类型DECIMAL(p,s)精确小数
p=总位数, s=小数位
DECIMAL(10,2) → 12345678.99金融金额、精确计算
FLOAT单精度浮点数≈6-7位精度科学计算
DOUBLE双精度浮点数≈15位精度高精度测量
字符串类型CHAR(n)定长字符串
空格填充
CHAR(10) ‘ABC’ → 'ABC ’固定长度代码(如国家代码)
VARCHAR(n)变长字符串VARCHAR(255)姓名、地址等变长文本
TEXT大文本数据最多 65,535 字节 (MySQL)文章内容、描述
日期时间DATE日期‘2023-08-15’出生日期、事件日期
TIME时间‘14:30:00’会议时间
DATETIME日期+时间‘2023-08-15 14:30:00’订单时间、日志时间戳
TIMESTAMP自动记录的时间戳自动记录修改时间创建时间/修改时间
二进制类型BLOB二进制大对象最大 65,535 字节图片、PDF等文件存储
BINARY(n)定长二进制数据BINARY(16)加密数据、哈希值
布尔类型BOOLEAN逻辑值TRUE/FALSE开关状态、是否标记
特殊类型ENUM('val1','val2')枚举值ENUM(‘Red’,‘Green’,‘Blue’)状态选项、固定分类
JSONJSON格式数据 (现代数据库){“name”: “John”, “age”: 30}灵活数据结构
UUID全局唯一标识符 (PostgreSQL等)‘a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11’分布式ID生成

二、SQL关键字解释

SQL查询知识点

基本查询结构
SELECT [DISTINCT]1,2, 聚合函数(3)  -- 选择最终显示的列
FROM1                                  -- 初始数据源
[JOIN2 ON 连接条件]                     -- 表连接
WHERE 行级过滤条件                        -- 行过滤
GROUP BY 分组列                          -- 数据分组
HAVING 组级过滤条件                       -- 组过滤
ORDER BY 排序列 [ASC|DESC]                -- 结果排序
LIMIT 结果数量;                           -- 行数限制

关键字详解(含执行变化案例)
1. SELECT
  • 作用:指定最终结果集中显示的列

  • 执行变化:从中间结果集中抽取指定列

  • 示例

    /* 原始products表(执行前):
    | id | product_name | price |
    |----|--------------|-------|
    | 1  | Laptop       | 1200  |
    | 2  | Phone        | 800   |
    | 3  | Tablet       | 600   | */
    SELECT product_name, price * 0.9 AS sale_price FROM products;/* 执行后结果集:
    | product_name | sale_price |
    |--------------|------------|
    | Laptop       | 1080 |
    | Phone        | 720 |
    | Tablet       | 540 | */
    
2. FROM
  • 作用:指定查询的主数据源
  • 执行变化:加载初始数据集
  • *示例
FROM employees -- 加载员工表全部数据
3. JOIN(表连接)
  • 作用:组合多个表的数据
  • 执行变化:扩展列维度

在这里插入图片描述

INNER JOIN 示例

/* employees表(左表):
| id | name  | dept   |
|----|-------|--------|
| 1  | Alice | Sales  |
| 2  | Bob   | IT     |orders表(右表):
| order_id | emp_id | amount |
|----------|--------|--------|
| 101      | 1      | 200    |
| 102      | 1      | 300    | */SELECT e.name, o.amount
FROM employees e
INNER JOIN orders o ON e.id = o.emp_id;/* 执行后结果集:
| name  | amount |
|-------|--------|
| Alice | 200    |
| Alice | 300    | */
4. WHERE
  • 作用:行级数据过滤

  • 执行变化:减少行数

  • 示例

    /* 原始orders表:
    | id | amount | status   |
    |----|--------|----------|
    | 1  | 100    | shipped  |
    | 2  | 200    | pending  |
    | 3  | 150    | shipped  | */
    SELECT id, amount
    FROM orders
    WHERE status = 'shipped';/* 执行后结果集:
    | id | amount |
    |----|--------|
    | 1 | 100 |
    | 3 | 150 | */
    
5. GROUP BY
  • 作用:数据分组聚合
  • 执行变化:行数减少,出现聚合值
原始数据
按部门分组
研发部:3条记录
销售部:5条记录
计算平均薪资
  • 执行变化:行数减少,出现聚合值

  • 聚合值

示例

/* 原始employees表:
| id | name   | dept   | salary |
|----|--------|--------|--------|
| 1  | Alice  | Sales  | 5000   |
| 2  | Bob    | Sales  | 6000   |
| 3  | Charlie| IT     | 7000   | */SELECT dept, AVG(salary) AS avg_salary
FROM employees
GROUP BY dept;/* 执行后结果集:
| dept  | avg_salary |
|-------|------------|
| Sales | 5500       |
| IT    | 7000       | */
6. HAVING
  • 作用:分组后结果过滤
  • 执行变化:减少分组数量
  • 与WHERE对比
特性WHEREHAVING
执行时机分组前分组后
操作对象原始行分组结果
聚合函数不可用可用

示例

/* 续上GROUP BY结果:
| dept  | avg_salary |
|-------|------------|
| Sales | 5500       |
| IT    | 7000       | */SELECT dept, AVG(salary) AS avg_salary
FROM employees
GROUP BY dept
HAVING AVG(salary) > 6000;/* 执行后结果集:
| dept | avg_salary |
|------|------------|
| IT   | 7000       | */
7. ORDER BY
  • 作用:结果排序

  • 执行变化:行顺序改变,内容不变

  • 排序方式

    • ASC 升序(默认)
    • DESC 降序
  • 示例

    /* 原始结果:
    | product | price |
    |---------|-------|
    | Laptop  | 1200  |
    | Phone   | 800   |
    | Tablet  | 600   | */
    SELECT product, price
    FROM products
    ORDER BY price DESC;/* 执行后结果集:
    | product | price |
    |---------|-------|
    | Laptop | 1200 |
    | Phone | 800 |
    | Tablet | 600 | */
    
8. LIMIT
  • 作用:限制返回行数

  • 执行变化:截断结果集

  • 示例

    /* 假设排序后结果(10条记录) */
    SELECT product, price
    FROM products
    ORDER BY price DESC
    LIMIT 5;
    /* 执行后结果集:只保留前5条记录 */
    
9. OFFSET

OFFSET 通常与 LIMIT 配合使用,用于实现分页查询或跳过指定行数

  • 跳过结果集的前 N 行

  • 典型应用场景:分页查询(如第2页、第3页数据)

  • 语法结构

    LIMIT 返回行数 OFFSET 跳过行数;
    -- 或等效写法 --
    LIMIT 跳过行数, 返回行数;  # MySQL专用语法
    

🧩 执行机制图解

完整结果集
OFFSET 跳过行
LIMIT 截取行

📊 案例演示(分步说明)

初始数据表 products
idproduct_nameprice
1Laptop1200
2Phone800
3Tablet600
4Monitor300
5Keyboard50
6Mouse30
7Headphones150
查询1:基础分页(每页3条)
/* 获取第1页数据 */
SELECT id, product_name 
FROM products 
ORDER BY price DESC
LIMIT 3 OFFSET 0;  -- 从第0行开始取3条/* 结果集:
| id | product_name |
|----|--------------|
| 1  | Laptop       |
| 2  | Phone        |
| 3  | Tablet       | */
查询2:跳转到第2页
/* 获取第2页数据 */
SELECT id, product_name 
FROM products 
ORDER BY price DESC
LIMIT 3 OFFSET 3;  -- 跳过前3条,取接下来3条/* 结果集:
| id | product_name |
|----|--------------|
| 4  | Monitor      |
| 7  | Headphones   |
| 5  | Keyboard     | */
查询3:等效写法(MySQL)
/* 获取第3页数据 */
SELECT id, product_name 
FROM products 
ORDER BY price DESC
LIMIT 6, 3;  -- 等效于 OFFSET 6 LIMIT 3/* 结果集:
| id | product_name |
|----|--------------|
| 6  | Mouse        |  # 只剩1条数据 */

⚠️ 重要注意事项

  1. 执行顺序
    OFFSETORDER BY 之后、LIMIT 之前执行
ORDER BY
OFFSET
LIMIT
10.字符串操作与通配符

通配符功能示例匹配示例
%匹配任意长度字符'John%'John, Johnson
_匹配单个字符'_ean'Dean, Jean
[ ]匹配指定字符集'[a]%' (SQL Server)apple, elephant
[^]排除指定字符集'[^0-9]%'Apple, #123

🧰 核心字符串函数
1. 基础操作函数
函数功能示例结果
CONCAT(s1, s2)字符串拼接CONCAT('Hello', ' ', 'World')Hello World
LENGTH(s)字符串长度LENGTH('SQL')3
UPPER(s)转为大写UPPER('hello')HELLO
LOWER(s)转为小写LOWER('SQL')sql
TRIM(s)去除两端空格TRIM(' text ')text
2. 子字符串操作
函数功能示例结果
SUBSTRING(s, start, len)提取子字符串SUBSTRING('Database', 2, 4)atab
LEFT(s, n)提取左侧n个字符LEFT('2023-06-15', 4)2023
RIGHT(s, n)提取右侧n个字符RIGHT('user@email.com', 3)com
REPLACE(s, old, new)替换字符串REPLACE('I like SQL', 'like', 'love')I love SQL
REVERSE(s)反转字符串REVERSE('ABCD')DCBA
3. 高级搜索函数
函数功能示例
POSITION(sub IN s)返回子串位置POSITION('@' IN 'user@domain.com') → 5
CHAR_LENGTH(s)字符数(支持多字节)CHAR_LENGTH('中文') → 2
INSTR(s, sub)查找子串位置INSTR('SQL Tutorial', 'Tut') → 5

⚙️ 实战综合应用
场景:邮箱格式标准化
UPDATE users 
SET email = LOWER(CONCAT(SUBSTRING(email, 1, POSITION('@' IN email) - 1),  -- 用户名部分'@company.com'  -- 统一域名)
)
WHERE email NOT LIKE '%@company.com';  -- 筛选需要修改的记录
场景:产品编号验证
/* 验证格式:AA-000 */
SELECT product_code
FROM products
WHERE product_code LIKE '__-___'  -- 长度验证AND SUBSTRING(product_code, 1, 2) REGEXP '^[A-Z]{2}$'  -- 前两位大写字母AND SUBSTRING(product_code, 4, 3) REGEXP '^[0-9]{3}$';  -- 后三位数字
场景:动态搜索
/* 根据输入关键词灵活搜索 */
SET @keyword = 'pro yoga';SELECT * FROM products
WHERE product_name LIKE CONCAT('%', REPLACE(@keyword, ' ', '%'), '%')OR category LIKE CONCAT('%', @keyword, '%');

完整案例:销售分析查询

业务场景:分析2023年各部门销售业绩

初始数据

employees表:

idnamedept
1AliceSales
2BobSales
3CharlieIT

orders表:

order_idemp_idamountorder_date
10112002023-02-01
10213002023-03-15
10321502023-01-10
10434002023-04-20
10515002022-12-31
分步执行过程
SELECT e.dept,SUM(o.amount) AS total_sales,COUNT(*) AS order_count
FROM employees e
INNER JOIN orders o ON e.id = o.emp_id
WHERE o.order_date >= '2023-01-01'
GROUP BY e.dept
HAVING SUM(o.amount) > 0
ORDER BY total_sales DESC;

分步结果变化:
  1. FROM + JOIN(初始连接):

    | e.id | e.name | dept  | o.order_id | amount | order_date  |
    |------|--------|-------|------------|--------|-------------|
    | 1    | Alice  | Sales | 101        | 200    | 2023-02-01  |
    | 1    | Alice  | Sales | 102        | 300    | 2023-03-15  |
    | 1    | Alice  | Sales | 105        | 500    | 2022-12-31  |
    | 2    | Bob    | Sales | 103        | 150    | 2023-01-10  |
    | 3    | Charlie| IT    | 104        | 400    | 2023-04-20  |
    
  2. WHERE(日期过滤):

    | e.id | name   | dept  | order_id | amount | order_date  |
    |------|--------|-------|----------|--------|-------------|
    | 1    | Alice  | Sales | 101      | 200    | 2023-02-01  |
    | 1    | Alice  | Sales | 102      | 300    | 2023-03-15  |
    | 2    | Bob    | Sales | 103      | 150    | 2023-01-10  |
    | 3    | Charlie| IT    | 104      | 400    | 2023-04-20  |
    
  3. GROUP BY(按部门分组):

    Sales组:Alice(200+300) + Bob(150) = 650
    IT组:Charlie(400) = 400
    
  4. HAVING(组过滤):

    两个组都满足SUM(amount)>0
    
  5. SELECT(显示结果):

    | dept  | total_sales | order_count |
    |-------|-------------|-------------|
    | Sales | 650         | 3           |
    | IT    | 400         | 1           |
    
  6. ORDER BY(最终排序):

    | dept  | total_sales | order_count |
    |-------|-------------|-------------|
    | Sales | 650         | 3           |  -- 销售额最高
    | IT    | 400         | 1           | 
    

在这里插入图片描述

SQL更新

1. 插入数据(INSERT)
关键字解释
  • INSERT INTO:指定要插入数据的表名。
  • VALUES:定义插入的具体值。
  • SET(可选):在部分数据库(如MySQL)中可用,用于指定列名和值的对应关系。
语法结构
-- 插入单条数据
INSERT INTO 表名 (1,2, ...) VALUES (1,2, ...);-- 插入多条数据
INSERT INTO 表名 (1,2, ...) VALUES (1,2, ...),(3,4, ...);
示例

假设有一个 students 表:

idnameage
1Alice20

插入新数据:

INSERT INTO students (name, age) VALUES ('Bob', 22);

2. 修改数据(UPDATE)
关键字解释
  • UPDATE:指定要修改数据的表名。
  • SET:定义要修改的列名及其新值。
  • WHERE(可选):限定修改的行范围(必须谨慎使用)。
语法结构
UPDATE 表名 
SET1 = 新值1,2 = 新值2 
WHERE 条件;
示例

修改 students 表中 id=1 的学生的年龄:

UPDATE students 
SET age = 21 
WHERE id = 1;

3. 删除数据(DELETE)
关键字解释
  • DELETE FROM:指定要删除数据的表名。
  • WHERE(可选):限定删除的行范围(必须谨慎使用)。
语法结构
DELETE FROM 表名 
WHERE 条件;
示例

删除 students 表中 id=2 的学生:

DELETE FROM students 
WHERE id = 2;

4. 综合示例
场景

修改订单表中某个用户的订单状态,并删除过期订单,最后插入新订单。

SQL 操作
-- 修改订单状态
UPDATE orders 
SET status = '已完成' 
WHERE user_id = 1001 AND status = '处理中';-- 删除过期订单
DELETE FROM orders 
WHERE order_date < '2023-01-01';-- 插入新订单
INSERT INTO orders (user_id, product, status) 
VALUES (1002, 'Laptop', '已下单');

三、创建,修改,删除表


🏗️ 一、创建表 (CREATE TABLE)

📌 核心语法
CREATE TABLE [IF NOT EXISTS] 表名 (列名1 数据类型 [约束],列名2 数据类型 [约束],...[表级约束]
);
🛡️ 常用约束
约束类型关键字核心作用示例可视化说明
主键约束PRIMARY KEY唯一标识每行记录,禁止重复和 NULLid INT PRIMARY KEY🔑 唯一标识符
外键约束FOREIGN KEY强制表间引用完整性user_id INT REFERENCES users(id) ON DELETE CASCADE⛓️ 表间连接关系
唯一约束UNIQUE确保列值唯一(允许多个 NULL)email VARCHAR(255) UNIQUE✨ 禁止重复值
非空约束NOT NULL禁止 NULL 值name VARCHAR(50) NOT NULL🚫 强制必填项
检查约束CHECK强制自定义条件age INT CHECK (age >= 18)✅ 数据验证规则
默认值约束DEFAULT未指定值时自动填充默认值created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP⏱️ 自动填充值
自动增长约束AUTO_INCREMENT自动生成连续唯一值(MySQL)id INT AUTO_INCREMENT PRIMARY KEY🔢 自增序列
枚举约束ENUM限制列值为预定义选项status ENUM('active','inactive')📋 固定选项列表

1. 主键约束 (PRIMARY KEY)

作用:唯一标识表的每行记录
特性

  • 值必须唯一且非 NULL
  • 每表只能有一个主键(可多列组合)

案例

CREATE TABLE students (student_id INT PRIMARY KEY,  -- 单列主键name VARCHAR(50) NOT NULL
);-- 多列组合主键
CREATE TABLE order_items (order_id INT,product_id INT,quantity INT,PRIMARY KEY (order_id, product_id)  -- 复合主键
);
students INT student_id PK VARCHAR name

2. 外键约束 (FOREIGN KEY)

作用:维护表间数据一致性
关键参数

  • ON DELETE CASCADE:主表删除时同步删除关联记录
  • ON UPDATE SET NULL:主表更新时关联字段置空

案例

CREATE TABLE departments (dept_id INT PRIMARY KEY,dept_name VARCHAR(50)
);CREATE TABLE employees (emp_id INT PRIMARY KEY,name VARCHAR(50),dept_id INT,FOREIGN KEY (dept_id) REFERENCES departments(dept_id) ON DELETE SET NULL  -- 部门删除时员工部门置空
);
departments INT dept_id PK VARCHAR dept_name employees INT emp_id PK VARCHAR name INT dept_id FK 1:N

3. 唯一约束 (UNIQUE)

作用:保证列值唯一性
特性

  • 允许 NULL 值(多个 NULL 视为不同值)
  • 每表可创建多个唯一约束

案例

CREATE TABLE users (user_id INT PRIMARY KEY,username VARCHAR(30) UNIQUE,  -- 用户名唯一email VARCHAR(255) UNIQUE,     -- 邮箱唯一phone VARCHAR(20) UNIQUE       -- 手机号唯一
);
users
user_id: INT PK
username: VARCHAR(30)
email: VARCHAR(255)
phone: VARCHAR(20)

4. 检查约束 (CHECK)

作用:强制数据满足业务规则
支持条件:比较运算、逻辑运算、函数调用

案例

CREATE TABLE products (product_id INT PRIMARY KEY,name VARCHAR(100),price DECIMAL(10,2) CHECK (price > 0),  -- 价格必须>0discount DECIMAL(5,2) CHECK (discount BETWEEN 0 AND 100),  -- 折扣0-100%release_date DATE CHECK (release_date > '2020-01-01')  -- 2020年后发布
);

5. 默认值约束 (DEFAULT)

作用:自动填充缺省值
常用默认值

  • CURRENT_TIMESTAMP:当前时间戳
  • 0 / '':数值/字符串默认值
  • TRUE/FALSE:布尔默认值

案例

CREATE TABLE orders (order_id INT PRIMARY KEY,order_date DATE DEFAULT CURRENT_DATE,  -- 默认当天日期status VARCHAR(20) DEFAULT 'pending',  -- 默认状态total DECIMAL(10,2) DEFAULT 0.00       -- 默认总价
);

⚙️ 约束管理操作
添加约束(建表后)
-- 添加主键
ALTER TABLE students ADD PRIMARY KEY (student_id);-- 添加外键
ALTER TABLE employees 
ADD CONSTRAINT fk_dept
FOREIGN KEY (dept_id) REFERENCES departments(dept_id);-- 添加检查约束
ALTER TABLE products
ADD CHECK (price > 0);
删除约束
-- 删除主键
ALTER TABLE students DROP PRIMARY KEY;-- 删除外键
ALTER TABLE employees DROP FOREIGN KEY fk_dept;-- 删除唯一约束
ALTER TABLE users DROP INDEX email;

🧩 案例1:创建用户表
CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(30) NOT NULL UNIQUE,email VARCHAR(100) NOT NULL,password CHAR(60) NOT NULL,  -- 存储加密密码created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,is_active BOOLEAN DEFAULT TRUE
);
users INT id PK 自增主键 VARCHAR username 唯一非空 VARCHAR email 非空 CHAR password 非空 TIMESTAMP created_at 默认当前时间 BOOLEAN is_active 默认true
🧩 案例2:创建订单表(含外键)
CREATE TABLE orders (order_id INT AUTO_INCREMENT PRIMARY KEY,user_id INT NOT NULL,amount DECIMAL(10,2) CHECK (amount > 0),order_date DATE DEFAULT (CURRENT_DATE),status ENUM('pending', 'shipped', 'delivered') DEFAULT 'pending',FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
users INT id orders INT order_id PK INT user_id FK DECIMAL amount DATE order_date ENUM status 1:N

🔧 二、修改表 (ALTER TABLE)

📌 核心操作类型
操作语法示例
添加列ALTER TABLE 表名 ADD COLUMN 列名 数据类型
删除列ALTER TABLE 表名 DROP COLUMN 列名
修改列类型ALTER TABLE 表名 ALTER COLUMN 列名 新类型
重命名列ALTER TABLE 表名 RENAME COLUMN 旧名 TO 新名
添加约束ALTER TABLE 表名 ADD CONSTRAINT 约束内容
删除约束ALTER TABLE 表名 DROP CONSTRAINT 约束名

🧩 案例1:添加新列
/* 在users表中添加手机号字段 */
ALTER TABLE users
ADD COLUMN phone VARCHAR(20) NOT NULL DEFAULT '';/* 可视化变化 */
添加phone列
users_before
id
username
email
password
created_at
is_active
users_after
id
username
email
password
created_at
is_active
phone : VARCHAR(20)
🧩 案例2:修改列属性
/* 扩展email字段长度并添加唯一约束 */
ALTER TABLE users
MODIFY COLUMN email VARCHAR(150) NOT NULL;ALTER TABLE users
ADD CONSTRAINT unique_email UNIQUE (email);
🧩 案例3:删除列
/* 删除已弃用的is_active列 */
ALTER TABLE users
DROP COLUMN is_active;
🧩 案例4:重命名表
/* 将orders表重命名为purchases */
ALTER TABLE orders RENAME TO purchases;

🗑️ 三、删除表 (DROP TABLE)

📌 核心语法
DROP TABLE [IF EXISTS] 表名 [CASCADE];
⚠️ 注意事项
  1. 不可逆操作:表结构和数据永久删除
  2. 依赖处理
    • CASCADE:级联删除依赖对象(视图、外键等)
    • RESTRICT:默认行为,存在依赖时拒绝删除
  3. 权限要求:需要DROP权限

🧩 案例1:基本删除
/* 删除临时表 */
DROP TABLE IF EXISTS temp_logs;
🧩 案例2:级联删除
/* 删除用户表及关联订单 */
DROP TABLE users CASCADE;/* 可视化效果 */
主键
users表
orders表
删除users
级联删除orders

💡 最佳实践建议

  1. 创建表时
设计范式
选择数据类型
设置主键
添加必要约束
  • 优先使用NOT NULL约束

  • 为关联字段添加外键约束

  • 使用AUTO_INCREMENT/SERIAL作为代理主键

  1. 修改表时

    • 生产环境使用ALTER TABLE ... ADD COLUMN而非直接修改列类型

    • 大表修改在低峰期进行

      /* 安全添加列示例 */
      ALTER TABLE large_table
      ADD COLUMN new_column INT DEFAULT 0,
      ALGORITHM=INPLACE, LOCK=NONE;  -- MySQL优化参数
      
  2. 删除表时

    • 始终使用IF EXISTS防止错误

    • 正式环境先重命名再删除(安全回收期)

      /* 安全删除流程 */
      ALTER TABLE obsolete_table RENAME TO obsolete_table_202308;
      DROP TABLE obsolete_table_202308;  -- 30天后执行
      

重要表删除前执行数据备份

CREATE TABLE users_backup AS SELECT * FROM users;  -- 全量备份

四、索引:加速查询的核心技术


🚀 索引核心概念

索引本质:数据库中的高效查找数据结构(类似书籍目录)
核心价值

  • 提升查询速度 10~1000 倍
  • 保证数据唯一性(唯一索引)
  • 加速表连接(JOIN 操作)
全表扫描
逐行查找
索引查找
直接定位目标行

索引工作原理

订单表 orders 初始结构

order_iduser_idamountorder_date
10011012002023-08-01
10021021502023-08-02
10031013002023-08-03
10041034002023-08-04

🔍 无索引查询(全表扫描)

SELECT * FROM orders WHERE user_id = 101;
扫描行1001
user_id=101?
返回该行
继续扫描
扫描行1002
user_id=101?
扫描行1003
user_id=101?
返回该行
扫描行1004
user_id=101?
结束

执行过程

  1. 逐行扫描所有记录(4行)
  2. 对每行检查 user_id=101
  3. 返回匹配行(1001和1003)
    扫描行数:4行

🚀 创建索引后查询

CREATE INDEX idx_user ON orders(user_id);  -- 创建B树索引
SELECT * FROM orders WHERE user_id = 101;
索引结构(B树简化版)
指针
指针
指针
指针
根节点
分支节点 100-150
分支节点 151-200
叶子节点 user_id=101
订单1001
订单1003
叶子节点 user_id=102
订单1002
叶子节点 user_id=103
订单1004

执行过程

  1. 从根节点开始查找 user_id=101
  2. 定位到分支节点 “100-150”
  3. 找到叶子节点 “user_id=101”
  4. 通过指针直接访问订单1001和1003
    扫描行数:2行(仅目标数据)

⚖️ 索引效果对比

指标无索引有索引
扫描行数4行2行
磁盘I/O4次2次
查询时间15ms3ms
新增订单代价直接写入更新索引+写入

🔥 组合索引深度案例

创建组合索引

CREATE INDEX idx_user_date ON orders(user_id, order_date);

执行范围查询

SELECT * FROM orders 
WHERE user_id = 101 AND order_date BETWEEN '2023-08-01' AND '2023-08-10';
组合索引结构
叶子节点
user_id=101date=2023-08-01 -> 订单1001
user_id=101date=2023-08-03 -> 订单1003
user_id=102date=2023-08-02 -> 订单1002
user_id=103date=2023-08-04 -> 订单1004

查询过程

  1. 在索引中定位 user_id=101
  2. 在该分区内按日期范围查找
  3. 直接获取订单1001和1003
    优势
  • 避免全表扫描
  • 避免额外排序(索引已预排序)

📊 真实性能测试数据

订单表(100万记录)查询对比

查询类型无索引时间索引时间提升倍数
等值查询(user_id)1200ms25ms48x
范围查询(date)980ms40ms24x
排序(order_id)850ms30ms28x


📌 索引类型速查表

索引类型关键字适用场景可视化结构
B树索引INDEX等值查询、范围查询(默认索引)平衡多叉树 🌳
唯一索引UNIQUE INDEX主键/唯一约束字段带唯一标识的叶子节点 🔑
全文索引FULLTEXT INDEX文本内容搜索(文章、描述)倒排索引 📝
哈希索引HASH INDEX内存表精确匹配(不支持范围查询)键值对存储 ⚡
组合索引INDEX(col1,col2)多列条件查询多级树结构 🧩
空间索引SPATIAL INDEX地理坐标数据(MySQL)R树结构 🗺️

⚙️ 索引操作语法

1. 创建索引
-- 基本单列索引
CREATE INDEX idx_name ON table_name (column_name);-- 唯一索引
CREATE UNIQUE INDEX uidx_email ON users (email);-- 组合索引(多列)
CREATE INDEX idx_name_dept ON employees (last_name, department);-- 全文索引(MySQL)
CREATE FULLTEXT INDEX idx_content ON articles (content);
2. 删除索引
DROP INDEX idx_name ON table_name;
3. 查看索引
SHOW INDEX FROM table_name;

🔍 索引适用场景

推荐创建索引的列:
  1. WHERE 子句频繁使用的列

    SELECT * FROM orders WHERE user_id = 100;  -- 需为user_id建索引
    
  2. JOIN 连接字段

    SELECT * 
    FROM orders o JOIN users u ON o.user_id = u.id; -- user_id和id需索引
    
  3. 排序字段(ORDER BY)

    SELECT * FROM products ORDER BY price DESC;  -- price建索引加速排序
    
  4. 分组字段(GROUP BY)

    SELECT department, COUNT(*) 
    FROM employees 
    GROUP BY department;  -- department建索引
    

⚖️ 索引优缺点分析

✅ 优点:
  1. 极大加速 SELECT 查询
  2. 加速表连接(JOIN)
  3. 保证数据唯一性(唯一索引)
  4. 优化排序和分组操作
❌ 缺点:
  1. 降低写操作速度(INSERT/UPDATE/DELETE)
  2. 占用额外存储空间
  3. 维护成本高(需定期优化)
索引更新
索引占用
写入操作
性能损耗
存储空间
磁盘消耗

五、视图

1. 视图是什么?

  • 本质: 一个虚拟表
  • 构成: 基于一个或多个基础表(或其他视图)的SELECT查询的结果集。
  • 存储: 不存储实际数据,只存储定义它的 SQL 查询语句。
  • 行为: 当查询视图时,数据库引擎会动态执行其定义的 SELECT 语句,返回当前基础表中的最新数据。
  • 类比: 像一个保存好的查询,或者一个窗口,透过它看到的是基础表中数据的特定组合、过滤或聚合。

2. 为什么使用视图?

  • 简化复杂查询: 将复杂的 JOIN、子查询、过滤封装在视图中,用户只需查询简单的视图。
  • 增强数据安全性:
    • 隐藏基础表的敏感列(如薪资、密码)。
    • 通过视图仅暴露用户有权访问的行和列(结合权限管理)。
  • 提供逻辑数据独立性:
    • 应用程序可以基于视图编写,即使基础表结构发生变化(如列名、拆分表),只需修改视图定义,应用程序代码可能无需改动。
  • 定制化数据展现: 为不同用户或部门提供不同的数据视角(聚合数据、特定范围数据)。
  • 简化权限管理: 对视图授权比直接对多个基础表授权更方便。

3. 创建视图 (CREATE VIEW)

CREATE VIEW view_name [(column_alias1, column_alias2, ...)]
AS
SELECT column1, column2, ...
FROM table_name
[WHERE condition]
[GROUP BY ...]
[HAVING ...]
[JOIN ...];
  • view_name: 视图的名称。
  • (column_alias1, ...): 可选。为视图的列指定别名。如果省略,列名继承 SELECT 语句中的列名或别名。
  • AS: 关键字。
  • SELECT ...: 定义视图内容的查询语句。这是视图的核心。

示例:

CREATE VIEW ActiveCustomers AS
SELECT CustomerID, CompanyName, ContactName, Phone
FROM Customers
WHERE Active = 1;

4. 查询视图 (SELECT)

SELECT * FROM ActiveCustomers; -- 查询整个视图
SELECT ContactName, Phone FROM ActiveCustomers WHERE CompanyName LIKE 'A%'; -- 像查询普通表一样使用视图

5. 视图的核心特点(重点理解)

  • 虚拟性: 视图不存储数据本身,只存储查询定义。查询视图时实时计算
  • 动态性: 视图数据随基础表数据实时变化
  • 派生性: 视图数据完全来源于其定义所基于的基础表。
  • 可更新性 (有时): 并非所有视图都可更新。能否更新取决于视图的定义:
    • 通常,基于单个表不含 DISTINCT、GROUP BY、HAVING、聚合函数,并且包含基础表所有非空且无默认值的列的视图较容易更新。
    • 涉及多个表的 JOIN 视图通常不可直接更新(具体规则因数据库系统而异,如 SQL Server 有限支持, Oracle 有 INSTEAD OF 触发器)。
    • 更新视图 (INSERT/UPDATE/DELETE) 最终会作用到基础表上。

图表 1:视图与基础表关系

+----------------+       +----------------+       +----------------+
|   Table A      |       |   Table B      |       |   Table C      |
| (Physical)     |       | (Physical)     |       | (Physical)     |
| - Col1 (PK)    |       | - ColX (PK)    |       | - ColY (PK)    |
| - Col2         |       | - ColY (FK)    |       | - ColZ         |
| - Col3         |       | - ColW         |       +----------------+
+----------------+       +----------------+^                         ^|                         || JOIN/Filter/Projection  ||-------------------------+|v+----------------+|   MyView       || (Virtual)      || - Col1         || - Col2_Alias   | <-- (Alias from TableA.Col2)| - ColZ         | <-- (From TableC)| - CalcColumn   | <-- (e.g., TableA.Col3 * 10)+----------------+^||+----------------+|   Application   ||   or User      |  --> SELECT * FROM MyView WHERE ...+----------------+
  • 实线方框: 物理存储的基础表。
  • 虚线方框: 虚拟的视图。
  • 箭头: 视图的数据来源于执行其定义的 SELECT 语句(包含 JOIN、过滤、计算等操作)作用于基础表。
  • 应用/用户: 像查询普通表一样查询视图。

6. 修改视图 (ALTER VIEW / CREATE OR REPLACE VIEW)

  • ALTER VIEW (部分数据库如 SQL Server):

    ALTER VIEW view_name [(column_alias1, ...)]
    AS
    new_select_statement;
    
  • CREATE OR REPLACE VIEW (更通用,如 MySQL, PostgreSQL, Oracle):

    CREATE OR REPLACE VIEW view_name [(column_alias1, ...)]
    AS
    new_select_statement;
    

7. 删除视图 (DROP VIEW)

DROP VIEW [IF EXISTS] view_name;

8. 视图的优缺点总结

  • 优点: 简化、安全、逻辑独立、定制化。
  • 缺点:
    • 性能开销: 复杂视图查询时,数据库仍需执行底层复杂查询,可能不如直接优化基础表查询快(视图不是性能优化银弹)。
    • 更新限制: 并非所有视图都可直接更新,规则有时复杂。
    • 依赖管理: 视图依赖于基础表。如果基础表被删除或结构更改(如删除视图中引用的列),视图会失效。
    • 嵌套复杂性: 过度使用嵌套视图(视图基于视图)会降低可读性和维护性,并可能放大性能问题。

图表 2:视图的权限控制(概念图)

+----------------+     +----------------+     +----------------+
|   User/App     |     |     View       |     |  Base Tables   |
| (Limited Perm) |---->| (Permission:   |---->| (Full Schema)  |
|                |     |  SELECT only   |     |                |
+----------------+     | on specific cols|     +----------------+| & rows)        |+----------------+
  • 用户/应用只有对视图的 SELECT 权限。
  • 视图定义了哪些列(如隐藏了 Salary 列)和哪些行(如只显示 Active=1)对用户可见。
  • 用户通过视图间接访问基础表,但只能看到视图定义允许的部分。

六、SQL 访问控制

SQL 访问控制

SQL 访问控制是数据库安全的重要组成部分,主要用于管理用户对数据库对象的访问权限。

一、用户管理

作用:创建、修改和删除数据库用户
关键字:CREATE USER、ALTER USER、DROP USER、SHOW CREATE USER

1. 用户管理语法

sql

-- 创建用户
CREATE USER 'username'@'host' IDENTIFIED BY 'password';-- 修改用户密码
ALTER USER 'username'@'host' IDENTIFIED BY 'new_password';-- 重命名用户
RENAME USER 'old_username'@'host' TO 'new_username'@'host';-- 删除用户
DROP USER 'username'@'host';-- 查看用户创建语句
SHOW CREATE USER 'username'@'host';
2. 示例

sql

-- 创建用户testuser,只能从本地访问
CREATE USER 'testuser'@'localhost' IDENTIFIED BY 'test123';-- 修改用户密码
ALTER USER 'testuser'@'localhost' IDENTIFIED BY 'newtest123';-- 重命名用户
RENAME USER 'testuser'@'localhost' TO 'newuser'@'localhost';-- 删除用户
DROP USER 'newuser'@'localhost';
二、权限管理

作用:授予、撤销用户对数据库对象的访问权限
关键字:GRANT、REVOKE、SHOW GRANTS

1. 常用权限类型
权限类型作用范围
SELECT查询数据
INSERT插入数据
UPDATE修改数据
DELETE删除数据
CREATE创建表、视图等对象
DROP删除表、视图等对象
ALTER修改表结构
INDEX创建和删除索引
ALL PRIVILEGES所有权限
GRANT OPTION授予他人权限的权限
2. 权限管理语法

sql

-- 授予权限
GRANT privilege_type ON database.table TO 'username'@'host';-- 授予权限并允许传播
GRANT privilege_type ON database.table TO 'username'@'host' WITH GRANT OPTION;-- 撤销权限
REVOKE privilege_type ON database.table FROM 'username'@'host';-- 撤销所有权限
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'username'@'host';-- 查看用户权限
SHOW GRANTS FOR 'username'@'host';-- 查看当前用户权限
SHOW GRANTS;
3. 示例
-- 授予用户对testdb数据库所有表的SELECT权限
GRANT SELECT ON testdb.* TO 'testuser'@'localhost';-- 授予用户对testdb数据库中user表的INSERT和UPDATE权限
GRANT INSERT, UPDATE ON testdb.user TO 'testuser'@'localhost';-- 授予用户所有权限并允许传播
GRANT ALL PRIVILEGES ON testdb.* TO 'testuser'@'localhost' WITH GRANT OPTION;-- 撤销用户的DELETE权限
REVOKE DELETE ON testdb.* FROM 'testuser'@'localhost';-- 撤销用户的GRANT OPTION权限
REVOKE GRANT OPTION ON testdb.* FROM 'testuser'@'localhost';-- 撤销用户所有权限
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'testuser'@'localhost';-- 查看用户权限
SHOW GRANTS FOR 'testuser'@'localhost';
三、角色管理

作用:简化权限管理,将权限分配给角色,再将角色分配给用户
关键字:CREATE ROLE、DROP ROLE、GRANT ROLE、SET DEFAULT ROLE、REVOKE ROLE

1. 角色管理语法

sql

-- 创建角色
CREATE ROLE 'role_name';-- 授予角色权限
GRANT privilege_type ON database.table TO 'role_name';-- 将角色授予用户
GRANT 'role_name' TO 'username'@'host';-- 设置用户默认角色
SET DEFAULT ROLE 'role_name' TO 'username'@'host';-- 设置用户激活角色
SET ROLE 'role_name';
SET ROLE ALL; -- 激活所有角色-- 撤销角色权限
REVOKE privilege_type ON database.table FROM 'role_name';-- 撤销用户角色
REVOKE 'role_name' FROM 'username'@'host';-- 删除角色
DROP ROLE 'role_name';
2. 示例

sql

-- 创建只读角色
CREATE ROLE 'read_only';-- 授予只读权限
GRANT SELECT ON testdb.* TO 'read_only';-- 创建读写角色
CREATE ROLE 'read_write';-- 授予读写权限
GRANT SELECT, INSERT, UPDATE, DELETE ON testdb.* TO 'read_write';-- 将角色授予用户
GRANT 'read_only' TO 'user1'@'localhost';
GRANT 'read_write' TO 'user2'@'localhost';-- 设置默认角色
SET DEFAULT ROLE 'read_write' TO 'user2'@'localhost';-- 撤销角色权限
REVOKE INSERT, UPDATE, DELETE ON testdb.* FROM 'read_write';-- 撤销用户角色
REVOKE 'read_only' FROM 'user1'@'localhost';-- 删除角色
DROP ROLE 'read_only';
DROP ROLE 'read_write';
四、SQL 访问控制流程图

下面是 SQL 访问控制的流程示意图:

SQL访问控制
用户管理
权限管理
角色管理
CREATE USER
ALTER USER
DROP USER
SHOW CREATE USER
GRANT
REVOKE
SHOW GRANTS
CREATE ROLE
GRANT ROLE
SET DEFAULT ROLE
DROP ROLE
REVOKE ROLE
授予表权限
授予数据库权限
授予全局权限
WITH GRANT OPTION
撤销表权限
撤销数据库权限
撤销全局权限
REVOKE ALL
角色分配给用户

使用注意事项

  1. 最小权限原则:为用户分配完成工作所需的最小权限集
  2. 定期审计:定期检查用户权限,撤销不再需要的权限
  3. 密码安全:使用强密码策略,定期更换密码
  4. 权限继承:角色权限变更会影响所有关联用户,需谨慎操作
  5. 权限传播:慎用 WITH GRANT OPTION,避免权限失控
  6. DROP USER 注意:删除用户前应确认其权限已清理,数据已备份

七、嵌入式SQL

嵌入式 SQL 是将 SQL 语句直接嵌入到高级程序设计语言(如 C、Java、Python 等)中,实现数据库操作的技术。它允许程序员在高级语言环境中直接使用 SQL 访问数据库,结合了高级语言的流程控制能力和 SQL 的数据处理能力。

一、嵌入式 SQL 基本概念
  1. 宿主语言:嵌入 SQL 的高级程序设计语言(如 C、Java)
  2. SQL 通信区:用于在宿主语言和 SQL 之间传递状态信息
  3. 主变量:宿主语言中定义的变量,用于 SQL 语句中传递数据
  4. 游标:用于处理 SQL 查询返回的多行结果
二、嵌入式 SQL 语法特点
  1. 语句标识:使用特殊标记区分 SQL 语句和宿主语言代码

    • C 语言中通常使用 EXEC SQL 开头
    • Java 中使用 JDBC API
    • Python 中使用 DB API
  2. 主变量使用:在 SQL 语句中使用宿主语言变量

    运行

    EXEC SQL SELECT name, age INTO :name, :age 
    FROM users WHERE id = :user_id;
    
  3. 游标操作:处理多行查询结果

    运行

    EXEC SQL DECLARE user_cursor CURSOR FOR
    SELECT id, name FROM users;EXEC SQL OPEN user_cursor;while (1) {EXEC SQL FETCH user_cursor INTO :id, :name;if (sqlca.sqlcode != 0) break;// 处理数据
    }EXEC SQL CLOSE user_cursor;
    
三、嵌入式 SQL 工作流程
宿主程序
预处理
生成宿主语言代码
编译宿主语言程序
链接数据库驱动
运行时执行SQL
与数据库交互
四、不同语言中的嵌入式 SQL 实现
  1. C 语言中的嵌入式 SQL

    #include <stdio.h>
    EXEC SQL INCLUDE SQLCA;  // SQL通信区int main() {char username[20] = "test";int age;EXEC SQL BEGIN DECLARE SECTION;char user[20];int user_age;EXEC SQL END DECLARE SECTION;EXEC SQL CONNECT TO database@server USER username;EXEC SQL SELECT age INTO :user_age FROM users WHERE name = :username;if (sqlca.sqlcode == 0) {printf("用户年龄: %d\n", user_age);}EXEC SQL COMMIT WORK;EXEC SQL DISCONNECT;return 0;
    }
    
  2. Java 中的嵌入式 SQL(JDBC)

    java

    import java.sql.*;public class EmbeddedSQLExample {public static void main(String[] args) {String url = "jdbc:mysql://localhost:3306/mydb";String username = "root";String password = "password";try (Connection conn = DriverManager.getConnection(url, username, password)) {String sql = "SELECT name, age FROM users WHERE id = ?";try (PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setInt(1, 1);  // 设置参数try (ResultSet rs = pstmt.executeQuery()) {if (rs.next()) {String name = rs.getString("name");int age = rs.getInt("age");System.out.printf("用户: %s, 年龄: %d%n", name, age);}}}} catch (SQLException e) {e.printStackTrace();}}
    }
    
  3. Python 中的嵌入式 SQL(SQLite 示例)

    import sqlite3conn = sqlite3.connect('example.db')
    cursor = conn.cursor()# 执行SQL查询
    user_id = 1
    cursor.execute("SELECT name, age FROM users WHERE id = ?", (user_id,))# 获取结果
    row = cursor.fetchone()
    if row:name, age = rowprint(f"用户: {name}, 年龄: {age}")conn.close()
    
五、嵌入式 SQL 的优缺点

优点

  • 无缝集成高级语言和数据库功能
  • 利用宿主语言的强大编程能力
  • 执行效率高(预处理优化)
  • 便于实现复杂业务逻辑

缺点

  • 代码可读性较差
  • 数据库移植性受限
  • 调试和维护难度较大
  • 事务管理复杂
六、适用场景
  • 需要高性能数据处理的应用
  • 对事务处理要求严格的系统
  • 与现有数据库架构深度集成的应用
  • 资源受限环境下的数据库操作

嵌入式 SQL 是数据库编程的重要技术,现代开发中更常见的是通过 ORM(对象关系映射)工具实现类似功能,但在性能敏感场景和遗留系统中仍广泛使用。

http://www.dtcms.com/a/270144.html

相关文章:

  • HTML+JS+CSS制作一个数独游戏
  • CSS揭秘:9.自适应的椭圆
  • 记一次mount point is busy问题排查
  • 数据结构 —— 栈(stack)在算法思维中的巧妙运用
  • C++进阶—二叉树进阶
  • 笔记/TCP/IP四层模型
  • Fence-音视频设备资源同步
  • IT 技术领域创作者三周年纪念日
  • 【CodeTop】每日练习 2025.7.8
  • Java 阻塞队列:7种类型全解析
  • 起重机械的工作循环门限值计算逻辑
  • 容器技术入门与Docker环境部署
  • Ntfs!LfsRestartLogFile函数分析之两次调用Ntfs!LfsReadRestart函数的目的
  • (生活比喻-图文并茂)http2.0和http3.0的队头阻塞,http2.0应用层解决,TCP层存在,3.0就是彻底解决,到底怎么理解区别???
  • AI健康小屋“15分钟服务圈”:如何重构社区健康生态?
  • MyBatis-Plus:深入探索与最佳实践
  • C#,js如何对网页超文本内容按行拆分,选择第A-B个字符返回HTM?
  • stack_queue扩展学习 --- 反向迭代器
  • 戴尔3670装win11和ubuntu双系统踩坑教程
  • 自动驾驶传感器的标定与数据融合
  • 【Android】组件及布局介绍
  • CAN主站转Modbus TCP网关:高铁门控系统的“毫秒级响应”密码
  • 【ZYNQ Linux开发】BRAM的几种驱动方式
  • 微服务集成snail-job分布式定时任务系统实践
  • Mac安装Docker(使用orbstack代替)
  • 单机分布式一体化数据库的架构设计与优化
  • 一个猜想不等式的推广
  • 业务分析技术实践篇
  • kafka集群安装
  • 让事情变得更好