数据定义语言(DDL)

学习创建和管理MySQL数据库对象

数据定义语言(DDL)概述

数据定义语言(Data Definition Language,DDL)是SQL语言的一个重要组成部分,用于定义和管理数据库中的各种对象结构。DDL命令允许数据库管理员和开发人员创建、修改和删除数据库对象,如数据库、表、索引、视图等。

主要的DDL命令包括:

  • CREATE - 创建数据库对象
  • ALTER - 修改数据库对象结构
  • DROP - 删除数据库对象
  • TRUNCATE - 清空表数据
  • RENAME - 重命名数据库对象

DDL的重要性

DDL在数据库管理中具有以下重要作用:

  • 数据结构定义 - 定义数据的存储结构和关系
  • 数据完整性 - 通过约束保证数据的准确性和一致性
  • 性能优化 - 通过索引和分区提高查询性能
  • 数据安全 - 通过视图和权限控制保护敏感数据
  • 系统维护 - 支持数据库结构的变更和演化

数据库操作

数据库是MySQL中最高级别的组织单位,包含表、视图、存储过程等对象。

创建数据库

SQL语法
CREATE DATABASE [IF NOT EXISTS] database_name
[CHARACTER SET charset_name]
[COLLATE collation_name]
[ENCRYPTION [=] 'Y'];
SQL示例
-- 创建简单数据库
CREATE DATABASE my_shop;

-- 创建带字符集的数据库
CREATE DATABASE my_blog 
CHARACTER SET utf8mb4 
COLLATE utf8mb4_unicode_ci;

-- 安全创建数据库(如果不存在)
CREATE DATABASE IF NOT EXISTS my_app;

-- 创建加密数据库(MySQL 8.0.16+)
CREATE DATABASE secure_db 
CHARACTER SET utf8mb4 
ENCRYPTION = 'Y';

查看数据库

SQL示例
-- 查看所有数据库
SHOW DATABASES;

-- 查看数据库创建语句
SHOW CREATE DATABASE my_shop;

-- 查看当前数据库
SELECT DATABASE();

-- 查看数据库字符集和排序规则
SELECT schema_name, default_character_set_name, default_collation_name
FROM information_schema.schemata
WHERE schema_name = 'my_shop';

选择数据库

SQL示例
USE my_shop;

修改数据库

SQL语法
ALTER DATABASE database_name
[CHARACTER SET charset_name]
[COLLATE collation_name]
[ENCRYPTION [=] 'Y'];
SQL示例
-- 修改数据库字符集
ALTER DATABASE my_shop
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;

-- 启用数据库加密
ALTER DATABASE my_shop ENCRYPTION = 'Y';

删除数据库

SQL语法
DROP DATABASE [IF EXISTS] database_name;
SQL示例
-- 删除数据库
DROP DATABASE old_database;

-- 安全删除数据库(如果存在)
DROP DATABASE IF EXISTS temporary_db;
注意:DROP DATABASE命令会永久删除数据库及其所有数据,操作前请务必确认。建议在执行前先备份数据。

表操作

表是数据库中存储数据的基本单位,由行和列组成。正确的表设计对数据库性能和数据完整性至关重要。

创建表

SQL语法
CREATE TABLE [IF NOT EXISTS] table_name (
    column1 datatype [constraints],
    column2 datatype [constraints],
    ...
    [table_constraints]
) [table_options];

表选项说明

  • ENGINE - 存储引擎,如InnoDB、MyISAM
  • CHARACTER SET - 字符集
  • COLLATE - 排序规则
  • ROW_FORMAT - 行格式,如COMPACT、DYNAMIC
  • COMMENT - 表注释
SQL示例 - 创建用户表
CREATE TABLE IF NOT EXISTS users (
    user_id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    email VARCHAR(100) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    birth_date DATE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    is_active BOOLEAN DEFAULT TRUE,
    INDEX idx_username (username),
    INDEX idx_email (email),
    INDEX idx_fullname (last_name, first_name)
) ENGINE=InnoDB CHARACTER SET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户信息表';
SQL示例 - 创建产品表
CREATE TABLE products (
    product_id INT AUTO_INCREMENT PRIMARY KEY,
    product_name VARCHAR(100) NOT NULL,
    description TEXT,
    price DECIMAL(10, 2) NOT NULL CHECK (price >= 0),
    cost_price DECIMAL(10, 2) NOT NULL,
    stock_quantity INT DEFAULT 0 CHECK (stock_quantity >= 0),
    category_id INT,
    supplier_id INT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (category_id) REFERENCES categories(category_id),
    FOREIGN KEY (supplier_id) REFERENCES suppliers(supplier_id),
    INDEX idx_product_name (product_name),
    INDEX idx_category (category_id),
    INDEX idx_price (price),
    UNIQUE INDEX idx_product_supplier (product_name, supplier_id)
) ENGINE=InnoDB;
SQL示例 - 创建订单表
CREATE TABLE orders (
    order_id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    total_amount DECIMAL(10, 2) NOT NULL,
    status ENUM('pending', 'confirmed', 'shipped', 'delivered', 'cancelled') DEFAULT 'pending',
    shipping_address TEXT,
    billing_address TEXT,
    notes TEXT,
    FOREIGN KEY (user_id) REFERENCES users(user_id),
    INDEX idx_user_id (user_id),
    INDEX idx_order_date (order_date),
    INDEX idx_status (status)
) ENGINE=InnoDB;

查看表结构

SQL示例
-- 查看所有表
SHOW TABLES;

-- 查看表结构
DESCRIBE users;
DESC users;  -- 简写

-- 查看表创建语句
SHOW CREATE TABLE users;

-- 查看表详细信息
SELECT * FROM information_schema.tables 
WHERE table_schema = 'my_shop' AND table_name = 'users';

-- 查看列信息
SELECT column_name, data_type, is_nullable, column_default, column_comment
FROM information_schema.columns 
WHERE table_schema = 'my_shop' AND table_name = 'users'
ORDER BY ordinal_position;

修改表

ALTER TABLE命令用于修改表结构,是数据库维护中最常用的DDL命令之一。

添加列

SQL语法
ALTER TABLE table_name
ADD COLUMN column_name datatype [constraints]
[FIRST | AFTER existing_column];
SQL示例
-- 添加电话号码列
ALTER TABLE users
ADD COLUMN phone_number VARCHAR(20);

-- 添加带约束的列
ALTER TABLE users
ADD COLUMN last_login TIMESTAMP,
ADD COLUMN login_count INT DEFAULT 0;

-- 在特定位置添加列
ALTER TABLE users
ADD COLUMN middle_name VARCHAR(50) AFTER first_name;

-- 添加列到表首
ALTER TABLE users
ADD COLUMN internal_id INT FIRST;

修改列

SQL语法
ALTER TABLE table_name
MODIFY COLUMN column_name new_datatype [new_constraints]
[FIRST | AFTER existing_column];
SQL示例
-- 修改列数据类型
ALTER TABLE users
MODIFY COLUMN username VARCHAR(100) NOT NULL;

-- 修改默认值
ALTER TABLE products
MODIFY COLUMN stock_quantity INT DEFAULT 10;

-- 修改列位置
ALTER TABLE users
MODIFY COLUMN email VARCHAR(100) AFTER username;

-- 修改多个列
ALTER TABLE users
MODIFY COLUMN first_name VARCHAR(100),
MODIFY COLUMN last_name VARCHAR(100);

删除列

SQL语法
ALTER TABLE table_name
DROP COLUMN column_name;
SQL示例
ALTER TABLE users
DROP COLUMN phone_number;

-- 删除多个列
ALTER TABLE users
DROP COLUMN temp_col1,
DROP COLUMN temp_col2;

重命名列

SQL语法
ALTER TABLE table_name
CHANGE COLUMN old_column_name new_column_name datatype [constraints];
SQL示例
ALTER TABLE users
CHANGE COLUMN first_name given_name VARCHAR(50);

-- 重命名并修改数据类型
ALTER TABLE products
CHANGE COLUMN item_name product_name VARCHAR(200) NOT NULL;

添加约束

SQL示例
-- 添加主键约束
ALTER TABLE table_name
ADD PRIMARY KEY (column_name);

-- 添加外键约束
ALTER TABLE table_name
ADD FOREIGN KEY (column_name) REFERENCES parent_table(parent_column);

-- 添加唯一约束
ALTER TABLE table_name
ADD UNIQUE (column_name);

-- 添加检查约束(MySQL 8.0.16+)
ALTER TABLE products
ADD CONSTRAINT chk_price CHECK (price > cost_price);

删除约束

SQL示例
-- 删除主键约束
ALTER TABLE table_name
DROP PRIMARY KEY;

-- 删除外键约束
ALTER TABLE table_name
DROP FOREIGN KEY constraint_name;

-- 删除唯一约束
ALTER TABLE table_name
DROP INDEX constraint_name;

重命名表

SQL语法
RENAME TABLE old_table_name TO new_table_name;
SQL示例
RENAME TABLE users TO customers;

-- 重命名多个表
RENAME TABLE 
    old_table1 TO new_table1,
    old_table2 TO new_table2;

删除表

SQL语法
DROP TABLE [IF EXISTS] table_name;
SQL示例
DROP TABLE temporary_data;

-- 安全删除表
DROP TABLE IF EXISTS old_table;

-- 删除多个表
DROP TABLE table1, table2, table3;
注意:DROP TABLE命令会永久删除表及其所有数据,操作前请务必确认。建议在执行前先备份数据。

清空表

SQL语法
TRUNCATE TABLE table_name;
SQL示例
TRUNCATE TABLE audit_logs;
TRUNCATE vs DELETE:
  • TRUNCATE删除所有数据并重置自增计数器,比DELETE更快
  • TRUNCATE不能使用WHERE条件,而DELETE可以
  • TRUNCATE是DDL操作,而DELETE是DML操作
  • TRUNCATE不能回滚,而DELETE可以(在事务中)
  • TRUNCATE会释放表空间,而DELETE不会

索引操作

索引是提高查询性能的重要工具,但会增加插入、更新和删除操作的开销。

创建索引

SQL语法
-- 创建普通索引
CREATE INDEX index_name ON table_name (column_name);

-- 创建唯一索引
CREATE UNIQUE INDEX index_name ON table_name (column_name);

-- 创建复合索引
CREATE INDEX index_name ON table_name (col1, col2);

-- 创建全文索引
CREATE FULLTEXT INDEX index_name ON table_name (column_name);

-- 创建空间索引
CREATE SPATIAL INDEX index_name ON table_name (column_name);
SQL示例
-- 在用户名上创建索引
CREATE INDEX idx_username ON users (username);

-- 在姓和名上创建复合索引
CREATE INDEX idx_fullname ON users (last_name, first_name);

-- 在邮箱上创建唯一索引
CREATE UNIQUE INDEX idx_unique_email ON users (email);

-- 在产品描述上创建全文索引
CREATE FULLTEXT INDEX idx_product_desc ON products (description);

-- 创建前缀索引
CREATE INDEX idx_product_name_prefix ON products (product_name(20));

删除索引

SQL语法
DROP INDEX index_name ON table_name;
SQL示例
DROP INDEX idx_username ON users;

查看索引

SQL示例
-- 查看表的所有索引
SHOW INDEX FROM users;

-- 从信息模式查看索引
SELECT index_name, column_name, index_type, non_unique
FROM information_schema.statistics
WHERE table_schema = 'my_shop' AND table_name = 'users';

视图操作

视图是基于SQL查询结果的虚拟表,可以简化复杂查询、提高安全性和实现数据抽象。

创建视图

SQL语法
CREATE VIEW view_name [(column_list)] AS
select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION];
SQL示例
-- 创建活跃用户视图
CREATE VIEW active_users AS
SELECT user_id, username, email, first_name, last_name
FROM users
WHERE is_active = 1;

-- 创建产品销售统计视图
CREATE VIEW product_sales AS
SELECT 
    p.product_name,
    c.category_name,
    SUM(oi.quantity) AS total_sold,
    SUM(oi.quantity * oi.unit_price) AS total_revenue
FROM products p
JOIN categories c ON p.category_id = c.category_id
JOIN order_items oi ON p.product_id = oi.product_id
GROUP BY p.product_id, p.product_name, c.category_name;

-- 创建可更新视图
CREATE VIEW user_profiles AS
SELECT user_id, username, first_name, last_name, email
FROM users
WHERE is_active = 1
WITH CHECK OPTION;

使用视图

SQL示例
-- 查询视图
SELECT * FROM active_users;

-- 对视图进行条件查询
SELECT * FROM product_sales
WHERE total_revenue > 1000
ORDER BY total_sold DESC;

-- 更新视图(如果视图是可更新的)
UPDATE user_profiles
SET first_name = 'John'
WHERE user_id = 1;

修改视图

SQL语法
ALTER VIEW view_name [(column_list)] AS
select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION];
SQL示例
ALTER VIEW active_users AS
SELECT user_id, username, email, first_name, last_name, created_at
FROM users
WHERE is_active = 1;

删除视图

SQL语法
DROP VIEW [IF EXISTS] view_name;
SQL示例
DROP VIEW active_users;

-- 安全删除视图
DROP VIEW IF EXISTS old_view;

表分区

表分区是将大表分割成更小、更易管理的部分,可以提高查询性能和数据管理效率。

创建分区表

SQL示例
-- 按范围分区
CREATE TABLE sales (
    sale_id INT AUTO_INCREMENT,
    sale_date DATE,
    amount DECIMAL(10, 2),
    PRIMARY KEY (sale_id, sale_date)
)
PARTITION BY RANGE (YEAR(sale_date)) (
    PARTITION p0 VALUES LESS THAN (2020),
    PARTITION p1 VALUES LESS THAN (2021),
    PARTITION p2 VALUES LESS THAN (2022),
    PARTITION p3 VALUES LESS THAN (2023),
    PARTITION p_max VALUES LESS THAN MAXVALUE
);

-- 按列表分区
CREATE TABLE employees (
    emp_id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100),
    department VARCHAR(50)
)
PARTITION BY LIST COLUMNS (department) (
    PARTITION p_sales VALUES IN ('Sales', 'Marketing'),
    PARTITION p_tech VALUES IN ('IT', 'Engineering'),
    PARTITION p_other VALUES IN ('HR', 'Finance', 'Operations')
);

管理分区

SQL示例
-- 添加分区
ALTER TABLE sales ADD PARTITION (
    PARTITION p4 VALUES LESS THAN (2024)
);

-- 删除分区
ALTER TABLE sales DROP PARTITION p0;

-- 重组分区
ALTER TABLE sales REORGANIZE PARTITION p_max INTO (
    PARTITION p4 VALUES LESS THAN (2024),
    PARTITION p_max VALUES LESS THAN MAXVALUE
);

DDL最佳实践

设计原则

  • 规范化设计 - 遵循数据库规范化原则,减少数据冗余
  • 命名规范 - 使用有意义的表名和列名,保持一致性
  • 数据类型选择 - 选择最适合数据特性的数据类型
  • 约束使用 - 充分利用约束保证数据完整性
  • 索引策略 - 为常用查询字段创建索引,但避免过度索引

性能考虑

  • 为大型表考虑分区策略
  • 选择合适的存储引擎(通常推荐InnoDB)
  • 考虑字符集和排序规则对性能的影响
  • 为频繁查询的列创建合适的索引
  • 避免在高峰时段执行DDL操作

维护建议

  • 定期分析表结构和性能
  • 监控索引使用情况,删除不必要的索引
  • 使用版本控制管理数据库结构变更
  • 在生产环境执行DDL操作前先在测试环境验证
  • 定期备份数据库结构
DDL操作注意事项:
  • DDL操作通常需要表锁,可能影响数据库性能
  • 在线DDL(MySQL 5.6+)可以减少锁的影响
  • 在生产环境执行DDL前,评估其对业务的影响
  • 考虑使用pt-online-schema-change等工具进行无锁表结构变更
  • 记录所有DDL操作,便于审计和故障恢复

实际应用场景

电子商务系统表设计

SQL示例
-- 创建完整的电商数据库结构
CREATE DATABASE ecommerce 
CHARACTER SET utf8mb4 
COLLATE utf8mb4_unicode_ci;

USE ecommerce;

-- 用户表
CREATE TABLE users (
    user_id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    email VARCHAR(100) NOT NULL UNIQUE,
    password_hash VARCHAR(255) NOT NULL,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    phone VARCHAR(20),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    last_login TIMESTAMP NULL,
    is_active BOOLEAN DEFAULT TRUE,
    INDEX idx_email (email),
    INDEX idx_username (username),
    INDEX idx_created_at (created_at)
);

-- 更多表定义...

下一步学习

掌握了数据定义语言后,您可以继续学习: