入门
连接到 MySQL
mysql 客户端是 MySQL 的标准 CLI 工具。始终使用 -p(后面不加空格)以便安全地提示输入密码,而不是暴露在 shell 历史记录中。-h 设置主机,-P(大写)设置端口。\s 打印连接状态。使用 -e 在脚本中执行一次性查询。
# connect to local server (prompt for password)
mysql -u root -p
# connect to a remote host on a custom port
mysql -h 192.168.1.100 -P 3307 -u admin -p
# connect directly to a specific database
mysql -u root -p mydb
# non-interactive: run a query and exit
mysql -u root -p -e "SELECT VERSION();"
# show server status inside the client
\s
SELECT VERSION(), CURRENT_USER, DATABASE();数据库管理
使用 utf8mb4(而非 utf8)以支持完整的 Unicode 包括 emoji——MySQL 的 utf8 是 3 字节子集,无法存储所有字符。utf8mb4_unicode_ci 是推荐的排序规则,可正确排序。IF EXISTS/IF NOT EXISTS 可防止脚本报错。DROP DATABASE 会立即删除所有表和数据。
# list all databases
SHOW DATABASES;
# create a database with charset and collation
CREATE DATABASE mydb
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
# switch to a database
USE mydb;
# show the current database
SELECT DATABASE();
# drop a database (irreversible)
DROP DATABASE IF EXISTS mydb;
# alter a database's charset
ALTER DATABASE mydb CHARACTER SET utf8mb4;显示与描述对象
SHOW 命令是 MySQL 特有的内省工具。DESCRIBE 提供快速列概览;SHOW CREATE TABLE 提供可复用的完整 DDL。在命令后加 \G 代替 ; 可垂直输出——对于 SHOW CREATE TABLE 等宽行结果更易读。
# list tables in the current database
SHOW TABLES;
# show table structure (columns, types, keys)
DESCRIBE users;
# equivalent
SHOW COLUMNS FROM users;
# show create statement for a table
SHOW CREATE TABLE users\G
# list indexes on a table
SHOW INDEX FROM users;
# show stored procedures / functions
SHOW PROCEDURE STATUS WHERE Db = 'mydb';
SHOW FUNCTION STATUS WHERE Db = 'mydb';
# list triggers
SHOW TRIGGERS\G服务器状态与变量
MySQL 变量有 SESSION(当前连接)和 GLOBAL 两种作用域。SET GLOBAL 修改运行中的服务器但重启后失效——应将设置持久化到 my.cnf 中。@@var 读取变量值。SHOW STATUS 暴露运行时计数器(连接数、运行时间、吞吐量),可用于监控。
# view a system variable
SHOW VARIABLES LIKE 'max_connections';
SHOW VARIABLES LIKE 'version%';
# view session vs global variable
SELECT @@session.sql_mode, @@global.sql_mode;
# set a variable for the current session
SET sql_mode = 'STRICT_TRANS_TABLES';
SET @@session.foreign_key_checks = 0;
# set globally (needs SUPER/privilege, persists until restart)
SET GLOBAL max_connections = 200;
# show server status counters
SHOW STATUS LIKE 'Threads%';
SHOW STATUS LIKE 'Uptime';注释与语句基础
MySQL 支持三种注释风格:--(需要尾部空格)、/* */ 块注释和 # 到行尾。/*! ... */ 是特殊的可执行注释——其中的代码仅在 MySQL 上运行,被其他 SQL 引擎忽略,适用于可移植的 schema 文件。\G 执行并以垂直方式显示结果。
-- single-line comment (note the space after --)
SELECT 1; -- inline comment
/* multi-line
comment block */
SELECT 2;
# hash-style comment (MySQL-specific, to end of line)
SELECT 3;
# MySQL executable comments: run only on MySQL
SELECT 1 /*!50100 , 2 */; /* the part runs on MySQL >= 5.1 */
# statements end with semicolon; \G ends and prints vertically
SELECT * FROM users\G配置文件 (my.cnf)
my.cnf(Linux)/ my.ini(Windows)保存持久化的服务器和客户端设置,按节组织:[mysqld] 为服务器,[client]/[mysql] 为客户端。innodb_buffer_pool_size 是 InnoDB 最重要的调优参数(通常为内存的 50-75%)。编辑后需重启服务器。用 mysql --help 或 SHOW VARIABLES 验证配置。
# /etc/my.cnf or ~/.my.cnf (Linux/macOS)
# C:\ProgramData\MySQL\MySQL Server 8.0\my.ini (Windows)
[mysqld]
port = 3306
datadir = /var/lib/mysql
max_connections = 200
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
innodb_buffer_pool_size = 2G
slow_query_log = 1
long_query_time = 2
[client]
default-character-set = utf8mb4
[mysql]
prompt = \u@\h [\d]>\_DDL 操作
创建表
CREATE TABLE 定义列、类型、约束和表选项。InnoDB 是默认且推荐的存储引擎(支持事务、行级锁、外键)。AUTO_INCREMENT 使用 BIGINT UNSIGNED 可避免溢出。DECIMAL(p,s) 适合精确存储货币。ENUM 根据固定列表验证值。TIMESTAMP DEFAULT CURRENT_TIMESTAMP 在插入时自动填充。
CREATE TABLE users (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(255) NOT NULL,
birth_date DATE NULL,
status ENUM('active','inactive','banned') NOT NULL DEFAULT 'active',
balance DECIMAL(10,2) NOT NULL DEFAULT 0.00,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX idx_email (email)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;修改表
ALTER TABLE 无需重建数据即可演进 schema。ADD COLUMN 配合 AFTER 可将列放在指定位置(列顺序在 MySQL 中仅影响显示)。MODIFY 修改类型/默认值;RENAME COLUMN(8.0+)比 CHANGE 更简洁。大型 ALTER 操作可能重建并锁定表——大表请使用 pt-online-schema-change 或在线 DDL。RENAME TABLE 是原子操作。
# add a column
ALTER TABLE users
ADD COLUMN phone VARCHAR(20) NULL AFTER email;
# add multiple columns
ALTER TABLE users
ADD COLUMN first_name VARCHAR(50) NULL,
ADD COLUMN last_name VARCHAR(50) NULL;
# modify a column type
ALTER TABLE users
MODIFY COLUMN phone VARCHAR(30) NOT NULL;
# rename a column (MySQL 8+ preserves data)
ALTER TABLE users
RENAME COLUMN phone TO phone_number;
# rename a table
RENAME TABLE users TO members;
ALTER TABLE users RENAME TO members;删除与清空表
DROP TABLE 完全删除表;TRUNCATE 清空数据但保留结构并将 AUTO_INCREMENT 重置为起始值。TRUNCATE 比 DELETE 快得多,因为它跳过了逐行删除和日志记录,但它是 DDL(无法回滚,不触发触发器)。清空被其他表引用的表时需禁用 foreign_key_checks。
# drop a table (removes structure and data)
DROP TABLE IF EXISTS old_logs;
# drop multiple tables
DROP TABLE IF EXISTS temp1, temp2;
# truncate: empty the table, keep structure, reset AUTO_INCREMENT
TRUNCATE TABLE session_data;
# truncate cannot be rolled back in some engines
# (InnoDB: TRUNCATE is DDL, implicitly commits)
SET foreign_key_checks = 0;
TRUNCATE TABLE child_table;
SET foreign_key_checks = 1;AUTO_INCREMENT
AUTO_INCREMENT 为主键生成连续数字——每张表只能有一个。LAST_INSERT_ID() 返回当前会话最近一次 INSERT 生成的 id(按连接隔离,并发安全)。删除、回滚或显式指定值插入后可能出现间隔。重置请使用 ALTER TABLE ... AUTO_INCREMENT = n。
CREATE TABLE orders (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
amount DECIMAL(10,2)
);
# set the next auto-increment value
ALTER TABLE orders AUTO_INCREMENT = 1000;
# insert without specifying id
INSERT INTO orders (amount) VALUES (99.50);
# get the last inserted id
SELECT LAST_INSERT_ID();
# show current AUTO_INCREMENT value
SHOW TABLE STATUS LIKE 'orders'\G表约束
约束在数据库层面强制数据完整性。InnoDB 支持主键、UNIQUE、NOT NULL、CHECK(8.0.16 起强制执行)和外键。FOREIGN KEY ... ON DELETE CASCADE 在父行删除时级联删除子行;SET NULL 将外键置空;RESTRICT/NO ACTION 阻止删除。显式命名约束便于管理。外键 要求两侧列都有索引。
CREATE TABLE orders (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
user_id INT UNSIGNED NOT NULL,
total DECIMAL(10,2) NOT NULL,
status VARCHAR(20) NOT NULL,
# unique constraint
CONSTRAINT uq_order_no UNIQUE (user_id, status),
# check constraint (MySQL 8.0.16+ enforced)
CONSTRAINT chk_total CHECK (total >= 0),
# foreign key with cascading actions
CONSTRAINT fk_orders_user
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE
ON UPDATE RESTRICT
) ENGINE=InnoDB;
# add a constraint later
ALTER TABLE orders
ADD CONSTRAINT chk_status CHECK (status IN ('paid','shipped','cancelled'));临时表
TEMPORARY 表仅存在于当前会话中,在连接关闭时自动删除。它可以遮蔽同名真实表,适用于安全重构或暂存数据。两个会话可以创建同名临时表而互不冲突。它们对其他连接不可见,默认不写入 binlog。
# session-scoped, auto-dropped on disconnect
CREATE TEMPORARY TABLE tmp_active
SELECT id, username FROM users WHERE status = 'active';
# identical name shadowing a real table
CREATE TEMPORARY TABLE users
(id INT, name VARCHAR(50));
# only this session sees the temp table
SELECT * FROM users;
# explicit cleanup
DROP TEMPORARY TABLE IF EXISTS tmp_active;数据类型
数值类型
货币等需要精确性的场景使用 DECIMAL——FLOAT/DOUBLE 是近似值,会累积舍入误差。UNSIGNED 使正数范围翻倍但不允许负值。显示宽度(如 INT(11))在 MySQL 8.0 中已弃用并被忽略——它从未限制存储范围。AUTO_INCREMENT 建议用 BIGINT UNSIGNED 以避免溢出。SERIAL 是代理键的便捷别名。
# integers (with optional UNSIGNED)
TINYINT -- 1 byte, -128..127 or 0..255 (UNSIGNED)
SMALLINT -- 2 bytes
MEDIUMINT -- 3 bytes
INT -- 4 bytes
BIGINT -- 8 bytes (use for large AUTO_INCREMENT)
# fixed-point (exact, for money)
DECIMAL(10,2) -- 10 digits total, 2 after decimal
NUMERIC(8,4)
# floating-point (approximate)
FLOAT -- 4 bytes
DOUBLE -- 8 bytes
# other
BIT(8) -- bit-field
SERIAL -- alias for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE字符串与文本类型
VARCHAR 几乎总是优于 CHAR(会用空格右填充),除非是短固定长度代码。MySQL 的 utf8mb4 每个字符最多 4 字节——VARCHAR(255) 列最多需要 1020 字节加长度,这关系到索引键长度限制(InnoDB 为 3072 字节)。TEXT/BLOB 系列将大数据离页存储;它们不 能有默认值,建索引需指定前缀长度。
# fixed vs variable length
CHAR(10) -- fixed 10 chars, padded with spaces
VARCHAR(255) -- variable, up to 255 chars (stores actual length)
# large text
TINYTEXT -- up to 255 bytes
TEXT -- up to 64 KB
MEDIUMTEXT -- up to 16 MB
LONGTEXT -- up to 4 GB
# binary counterparts
BINARY(16), VARBINARY(255), BLOB, MEDIUMBLOB, LONGBLOB
# national character set
NATIONAL VARCHAR(100) -- same as VARCHAR with utf8mb4
# VARCHAR with charset counts characters, not bytes
VARCHAR(100) CHARACTER SET utf8mb4日期与时间类型
DATETIME 存储字面日期/时间,不感知时区;TIMESTAMP 存储 UTC 并在显示时转换为会话 time_zone,更适合跨时区应用——但在 32 位构建上有 2038 年限制。使用 DATETIME(6)/TIMESTAMP(6) 获取微秒精度。自 MySQL 5.6.5 起 CURRENT_TIMESTAMP 可作为两者的默认值。用 SET time_zone = '+08:00'; 为每个连接设置时区。
DATE -- 'YYYY-MM-DD', range 1000-01-01 .. 9999-12-31
TIME -- 'HH:MM:SS', can be negative for elapsed time
DATETIME -- 'YYYY-MM-DD HH:MM:SS', 8 bytes, no timezone
TIMESTAMP -- stored as UTC, converted to session timezone, 4 bytes
YEAR -- YEAR(4) e.g. 2024
# DATETIME with fractional seconds and auto-default
CREATE TABLE events (
ts DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3)
ON UPDATE CURRENT_TIMESTAMP(3)
);
# TIMESTAMP range: 1970-01-01 .. 2038-01-19 (32-bit limit)
# MySQL 8.0.28+ extends TIMESTAMP to 24 bits of rangeENUM 与 SET 类型
ENUM 紧凑地存储固定列表中的一个字符串值(1-2 字节),在严格模式下拒绝未知值。SET 以位掩码形式存储最多 64 个成员的任意组合。两者修改 schema 成本较高(添加/重排成员需要 ALTER TABLE)且查询不便——许多团队更倾向于查找表或 VARCHAR 配合 CHECK。FIND_IN_SET 有助于查询 SET 列。
# ENUM: exactly one value from a list
CREATE TABLE shirts (
size ENUM('S','M','L','XL') NOT NULL DEFAULT 'M',
color ENUM('red','green','blue') NULL
);
# stored as integer index (1-based), space-efficient
INSERT INTO shirts (size) VALUES ('L'), ('XL');
# SET: zero or more values from a list (bit flags)
CREATE TABLE posts (
tags SET('news','tech','sports','fun') NOT NULL DEFAULT ''
);
INSERT INTO posts (tags) VALUES ('tech,fun');
# query SET members with FIND_IN_SET
SELECT * FROM posts WHERE FIND_IN_SET('tech', tags);JSON 类型
JSON 类型(MySQL 5.7.8+)以二进制格式存储 JSON,写入时验证并支持快速成员访问。它优于在 TEXT 列中存储 JSON,因为可以在其内部建索引和查询。使用 JSON_OBJECT()、JSON_ARRAY() 和 JSON_MERGE_PATCH() 构建值。对于频繁查询的几个键,将其提取到生成列并建索引以获得最佳性能。
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(100),
attrs JSON NOT NULL
);
# insert JSON literals
INSERT INTO products (id, name, attrs) VALUES
(1, 'Widget', '{"color":"red","size":42,"tags":["new","sale"]}'),
(2, 'Gadget', '{"color":"blue","in_stock":true}');
# JSON values are validated on insert and stored binary
SELECT attrs FROM products WHERE id = 1;
# pretty-print JSON
SELECT JSON_PRETTY(attrs) FROM products WHERE id = 1;BLOB 与二进制类型
BLOB 存储任意二进制数据(图片、文件)但查询不便且不能有默认值。对于大文件,建议在数据库中存储路径,文件存放在磁盘/对象存储上。UUID 存储为 BINARY(16)(16 字节)而非 CHAR(36)(36 字节)以提高索引效率——MySQL 8.0 新增 UUID_TO_BIN()/BIN_TO_UUID(),可选项交换以利于索引。
# binary large objects
TINYBLOB -- up to 255 bytes
BLOB -- up to 64 KB
MEDIUMBLOB -- up to 16 MB
LONGBLOB -- up to 4 GB
# fixed-size binary (e.g. hashes, UUIDs)
BINARY(16) -- fixed 16 bytes, right-padded with \0
VARBINARY(255)
# store a UUID as binary for compactness
CREATE TABLE sessions (
id BINARY(16) PRIMARY KEY,
data VARBINARY(1000)
);
INSERT INTO sessions (id, data) VALUES (UUID_TO_BIN(UUID()), '...');
# retrieve as text
SELECT BIN_TO_UUID(id) FROM sessions;