1. MySQL 常用 SQL 语句全景解析
作为关系型数据库的标杆产品,MySQL 的 SQL 语句体系构成了数据操作的基石。根据我十年 DBA 经验,系统掌握这些语句能提升 70% 的数据库操作效率。本文将从实际工作场景出发,分类详解高频使用的 SQL 语句及其隐藏技巧。
提示:所有示例基于 MySQL 8.0 版本,部分语法在 5.7 及以下版本可能存在差异
1.1 基础查询语句精要
SELECT 语句的完整语法结构包含 7 个核心子句,正确的执行顺序是:
sql复制FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
实际工作中最易混淆的是 WHERE 和 HAVING 的区别:
- WHERE 在分组前过滤原始数据
- HAVING 在分组后过滤聚合结果
典型查询示例:
sql复制/* 多表联合查询 */
SELECT
u.user_id,
u.username,
COUNT(o.order_id) AS order_count
FROM
users u
LEFT JOIN
orders o ON u.user_id = o.user_id
WHERE
u.register_time > '2023-01-01'
GROUP BY
u.user_id
HAVING
order_count > 5
ORDER BY
order_count DESC
LIMIT 10;
1.2 数据操作语句实战
INSERT 语句有三种高效写法:
sql复制/* 标准插入 */
INSERT INTO products (name, price) VALUES ('Laptop', 5999);
/* 批量插入(事务效率提升10倍) */
INSERT INTO products (name, price) VALUES
('Phone', 3999),
('Tablet', 1999),
('Watch', 999);
/* 从查询结果插入 */
INSERT INTO product_archive
SELECT * FROM products WHERE status = 'discontinued';
UPDATE 的原子性操作技巧:
sql复制/* 避免锁表的大数据量更新 */
UPDATE large_table
SET status = 'active'
WHERE id IN (
SELECT id FROM (
SELECT id FROM large_table
WHERE create_time < '2023-01-01'
LIMIT 1000
) tmp
);
1.3 高级查询技巧
窗口函数的典型应用场景:
sql复制/* 计算移动平均 */
SELECT
date,
sales,
AVG(sales) OVER (ORDER BY date ROWS 6 PRECEDING) AS 7day_avg
FROM daily_sales;
/* 分组排名 */
SELECT
department_id,
employee_name,
salary,
RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS dept_rank
FROM employees;
CTE (Common Table Expression) 的递归查询:
sql复制WITH RECURSIVE org_tree AS (
/* 基础查询 */
SELECT id, name, parent_id, 1 AS level
FROM organization
WHERE parent_id IS NULL
UNION ALL
/* 递归部分 */
SELECT o.id, o.name, o.parent_id, ot.level + 1
FROM organization o
JOIN org_tree ot ON o.parent_id = ot.id
)
SELECT * FROM org_tree ORDER BY level;
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据库对象管理语句
2.1 表结构操作大全
创建表的完整语法示例:
sql复制CREATE TABLE `users` (
`user_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`username` VARCHAR(50) NOT NULL,
`password_hash` CHAR(64) NOT NULL COMMENT 'SHA-256加密',
`email` VARCHAR(100) UNIQUE,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`user_id`),
UNIQUE INDEX `idx_username` (`username`),
INDEX `idx_email` (`email`(20))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_0900_ai_ci
COMMENT='用户基本信息表';
修改表结构的注意事项:
sql复制/* 安全添加列(避免锁表) */
ALTER TABLE large_table
ADD COLUMN new_column INT DEFAULT 0,
ALGORITHM=INPLACE, LOCK=NONE;
/* 在线修改列类型 */
ALTER TABLE products
MODIFY COLUMN price DECIMAL(10,2) NOT NULL,
ALGORITHM=INPLACE;
2.2 索引优化语句
索引创建的最佳实践:
sql复制/* 复合索引顺序原则 */
CREATE INDEX idx_name ON orders (user_id, status, create_time);
/* 函数索引 */
CREATE INDEX idx_name_lower ON users ((LOWER(username)));
/* 隐藏索引(测试索引效果) */
ALTER TABLE products ALTER INDEX idx_price INVISIBLE;
查看索引使用情况的诊断语句:
sql复制/* 查看索引使用统计 */
SELECT
object_schema,
object_name,
index_name,
count_read,
count_fetch
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE index_name IS NOT NULL
ORDER BY count_read DESC;
/* 查看未使用索引 */
SELECT
t.TABLE_SCHEMA,
t.TABLE_NAME,
s.INDEX_NAME,
s.COLUMN_NAME
FROM
INFORMATION_SCHEMA.STATISTICS s
JOIN
INFORMATION_SCHEMA.TABLES t
ON s.TABLE_SCHEMA = t.TABLE_SCHEMA
AND s.TABLE_NAME = t.TABLE_NAME
LEFT JOIN
performance_schema.table_io_waits_summary_by_index_usage u
ON u.OBJECT_SCHEMA = s.TABLE_SCHEMA
AND u.OBJECT_NAME = s.TABLE_NAME
AND u.INDEX_NAME = s.INDEX_NAME
WHERE
u.INDEX_NAME IS NULL
AND t.TABLE_SCHEMA NOT IN ('mysql', 'sys', 'information_schema', 'performance_schema');
3. 事务与锁机制语句
3.1 事务控制语句
事务隔离级别的设置与查看:
sql复制/* 设置会话级隔离级别 */
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
/* 查看当前隔离级别 */
SELECT @@transaction_isolation;
/* 典型事务示例 */
START TRANSACTION;
INSERT INTO order_header (...) VALUES (...);
SET @last_order_id = LAST_INSERT_ID();
INSERT INTO order_items (order_id, ...)
VALUES (@last_order_id, ...), (@last_order_id, ...);
COMMIT;
保存点(SAVEPOINT)的使用场景:
sql复制START TRANSACTION;
INSERT INTO audit_log (...) VALUES (...);
SAVEPOINT before_update;
UPDATE accounts SET balance = balance - 100 WHERE user_id = 123;
/* 检查业务条件 */
IF (SELECT balance FROM accounts WHERE user_id = 123) < 0 THEN
ROLLBACK TO SAVEPOINT before_update;
INSERT INTO error_log (...) VALUES (...);
END IF;
COMMIT;
3.2 锁监控与处理
查看当前锁情况的诊断语句:
sql复制/* 查看InnoDB锁状态 */
SELECT
r.trx_id waiting_trx_id,
r.trx_mysql_thread_id waiting_thread,
r.trx_query waiting_query,
b.trx_id blocking_trx_id,
b.trx_mysql_thread_id blocking_thread,
b.trx_query blocking_query
FROM
information_schema.innodb_lock_waits w
INNER JOIN
information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
INNER JOIN
information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;
死锁处理的最佳实践:
sql复制/* 死锁自动重试逻辑 */
DELIMITER //
CREATE PROCEDURE safe_transfer(
IN from_account INT,
IN to_account INT,
IN amount DECIMAL(10,2),
IN max_retries INT
)
BEGIN
DECLARE retry_count INT DEFAULT 0;
DECLARE success BOOLEAN DEFAULT FALSE;
WHILE retry_count < max_retries AND NOT success DO
BEGIN
DECLARE EXIT HANDLER FOR 1213 /* ER_LOCK_DEADLOCK */
BEGIN
SET retry_count = retry_count + 1;
SELECT CONCAT('Deadlock encountered, retrying (', retry_count, ')') AS message;
DO SLEEP(LEAST(1, retry_count * 0.1)); /* 指数退避 */
END;
START TRANSACTION;
UPDATE accounts SET balance = balance - amount WHERE account_id = from_account;
UPDATE accounts SET balance = balance + amount WHERE account_id = to_account;
INSERT INTO transaction_log (...) VALUES (...);
COMMIT;
SET success = TRUE;
END;
END WHILE;
IF NOT success THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Transaction failed after retries';
END IF;
END //
DELIMITER ;
4. 存储过程与触发器
4.1 存储过程开发规范
完整的存储过程模板:
sql复制DELIMITER //
CREATE PROCEDURE process_monthly_report(
IN p_year INT,
IN p_month INT,
OUT p_status VARCHAR(20)
)
/*
过程说明:生成月度销售报告
创建人:DBA团队
修改记录:
2023-05-01 初始版本
*/
BEGIN
DECLARE v_start_date DATE;
DECLARE v_end_date DATE;
DECLARE v_record_count INT DEFAULT 0;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
@sqlstate = RETURNED_SQLSTATE,
@errno = MYSQL_ERRNO,
@text = MESSAGE_TEXT;
INSERT INTO error_log(error_time, procedure_name, error_code, error_message)
VALUES(NOW(), 'process_monthly_report', @errno, @text);
SET p_status = 'ERROR';
ROLLBACK;
END;
/* 参数校验 */
IF p_year < 2000 OR p_year > YEAR(CURDATE()) + 1 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Invalid year parameter';
END IF;
IF p_month < 1 OR p_month > 12 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Invalid month parameter';
END IF;
/* 计算日期范围 */
SET v_start_date = DATE(CONCAT(p_year, '-', p_month, '-01'));
SET v_end_date = LAST_DAY(v_start_date);
START TRANSACTION;
/* 清除旧数据 */
DELETE FROM monthly_report
WHERE report_year = p_year AND report_month = p_month;
/* 插入新数据 */
INSERT INTO monthly_report(...)
SELECT ... FROM sales_data
WHERE sale_date BETWEEN v_start_date AND v_end_date;
SET v_record_count = ROW_COUNT();
/* 更新统计信息 */
UPDATE report_metadata
SET last_generated = NOW(),
record_count = v_record_count
WHERE report_type = 'MONTHLY';
COMMIT;
SET p_status = 'COMPLETED';
END //
DELIMITER ;
4.2 触发器开发陷阱
审计日志触发器的正确实现:
sql复制DELIMITER //
CREATE TRIGGER after_user_update
AFTER UPDATE ON users
FOR EACH ROW
BEGIN
DECLARE change_description TEXT DEFAULT '';
/* 检测用户名变更 */
IF NEW.username <> OLD.username THEN
SET change_description = CONCAT(change_description,
'Username changed from ', OLD.username, ' to ', NEW.username, '; ');
END IF;
/* 检测邮箱变更 */
IF NEW.email <> OLD.email THEN
SET change_description = CONCAT(change_description,
'Email changed from ', IFNULL(OLD.email, 'NULL'), ' to ', IFNULL(NEW.email, 'NULL'), '; ');
END IF;
/* 只有实际发生变更才记录 */
IF change_description <> '' THEN
INSERT INTO user_audit_log (
user_id,
change_time,
changed_by,
change_type,
description
) VALUES (
NEW.user_id,
NOW(),
@current_user_id, /* 应用程序设置的会话变量 */
'UPDATE',
change_description
);
END IF;
END //
DELIMITER ;
重要提示:触发器内禁止使用SELECT查询其他表,否则可能导致隐式锁和性能问题
5. 性能优化专项语句
5.1 执行计划分析
EXPLAIN 的高级用法:
sql复制/* 传统执行计划 */
EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND status = 'completed';
/* JSON格式详细计划 */
EXPLAIN FORMAT=JSON
SELECT p.* FROM products p
JOIN inventory i ON p.product_id = i.product_id
WHERE i.quantity < p.min_stock;
/* 分析优化器跟踪 */
SET optimizer_trace="enabled=on";
SELECT * FROM users WHERE username LIKE 'test%';
SELECT * FROM information_schema.optimizer_trace;
SET optimizer_trace="enabled=off";
5.2 查询重写技巧
常见低效查询的优化方案:
原始查询:
sql复制SELECT DISTINCT u.*
FROM users u
WHERE u.user_id IN (
SELECT DISTINCT user_id FROM orders
WHERE order_date > DATE_SUB(NOW(), INTERVAL 1 YEAR)
)
ORDER BY u.register_date DESC;
优化方案1(使用JOIN):
sql复制SELECT DISTINCT u.*
FROM users u
JOIN (
SELECT DISTINCT user_id
FROM orders
WHERE order_date > DATE_SUB(NOW(), INTERVAL 1 YEAR)
) o ON u.user_id = o.user_id
ORDER BY u.register_date DESC;
优化方案2(使用EXISTS):
sql复制SELECT u.*
FROM users u
WHERE EXISTS (
SELECT 1 FROM orders o
WHERE o.user_id = u.user_id
AND o.order_date > DATE_SUB(NOW(), INTERVAL 1 YEAR)
)
ORDER BY u.register_date DESC;
5.3 系统变量调优
关键性能参数查看与设置:
sql复制/* 查看当前缓冲池设置 */
SELECT @@innodb_buffer_pool_size/1024/1024 AS buffer_pool_size_mb;
/* 动态调整线程缓存 */
SET GLOBAL thread_cache_size = 32;
/* 持久化设置(MySQL 8.0+) */
SET PERSIST max_connections = 200;
SET PERSIST innodb_flush_neighbors = 0;
临时表优化的监控语句:
sql复制/* 查看临时表使用情况 */
SHOW GLOBAL STATUS LIKE 'Created_tmp%';
/* 临时表配置建议 */
SET GLOBAL tmp_table_size = 64*1024*1024;
SET GLOBAL max_heap_table_size = 64*1024*1024;
6. 备份与恢复关键语句
6.1 逻辑备份策略
mysqldump 的进阶用法:
bash复制# 全库备份(排除系统库)
mysqldump --single-transaction --skip-lock-tables \
--ignore-table=mysql.user --ignore-table=mysql.db \
--databases app_db1 app_db2 > full_backup.sql
# 分表备份脚本
for table in $(mysql -NBe "SHOW TABLES FROM app_db")
do
mysqldump --single-transaction --quick app_db $table > ${table}.sql
done
# 只备份结构
mysqldump --no-data --routines --triggers app_db > schema.sql
# 只备份数据
mysqldump --no-create-info --skip-triggers app_db > data.sql
6.2 物理备份技术
InnoDB 物理备份的预处理语句:
sql复制/* 创建备份锁(MySQL 8.0+) */
LOCK INSTANCE FOR BACKUP;
/* 此时可以复制数据文件 */
UNLOCK INSTANCE;
/* 克隆插件使用(MySQL 8.0+) */
INSTALL PLUGIN clone SONAME 'mysql_clone.so';
CREATE USER clone_user@'%' IDENTIFIED BY 'password';
GRANT BACKUP_ADMIN ON *.* TO clone_user@'%';
/* 本地克隆 */
CLONE LOCAL DATA DIRECTORY = '/path/to/backup';
6.3 时间点恢复流程
二进制日志操作关键命令:
sql复制/* 查看当前二进制日志状态 */
SHOW MASTER STATUS;
/* 查看所有二进制日志文件 */
SHOW BINARY LOGS;
/* 从特定位置提取SQL */
mysqlbinlog --start-position=123456 --stop-position=234567 \
--database=app_db /var/lib/mysql/binlog.000123 > recovery.sql
/* 重要恢复命令 */
SET GLOBAL sql_log_bin = 0; -- 临时禁用二进制日志
SOURCE recovery.sql; -- 执行恢复脚本
SET GLOBAL sql_log_bin = 1; -- 重新启用
7. 安全管控语句集
7.1 用户权限管理
最小权限原则的实施示例:
sql复制/* 应用账号创建 */
CREATE USER 'app_readonly'@'192.168.1.%'
IDENTIFIED WITH caching_sha2_password BY 'complex_password'
REQUIRE SSL;
/* 精确到列级的权限控制 */
GRANT SELECT (id, name, email), UPDATE (email)
ON app_db.users TO 'app_readonly'@'192.168.1.%';
/* 存储过程执行权限 */
GRANT EXECUTE ON PROCEDURE app_db.generate_report TO 'reporter'@'%';
/* 查看有效权限 */
SHOW GRANTS FOR CURRENT_USER;
7.2 数据加密方案
透明数据加密(TDE)配置:
sql复制/* 生成加密密钥 */
INSTALL COMPONENT "file://component_keyring_file";
SET GLOBAL keyring_encrypted_file_data = '/etc/mysql/keyring/keyring';
SET GLOBAL keyring_file_data = '/etc/mysql/keyring/keyring';
/* 加密表空间 */
ALTER TABLE sensitive_data ENCRYPTION = 'Y';
/* 加密重做日志 */
SET GLOBAL innodb_redo_log_encrypt = ON;
8. 监控诊断语句库
8.1 性能瓶颈分析
慢查询分析黄金语句:
sql复制/* 查看当前慢查询设置 */
SELECT @@long_query_time, @@slow_query_log, @@slow_query_log_file;
/* 优化后的慢查询日志分析 */
SELECT
sql_text,
COUNT(*) AS execution_count,
SUM(query_time) AS total_time,
SUM(rows_sent) AS total_rows_sent,
SUM(rows_examined) AS total_rows_examined
FROM mysql.slow_log
WHERE start_time > NOW() - INTERVAL 7 DAY
GROUP BY sql_text
ORDER BY total_time DESC
LIMIT 10;
8.2 资源使用监控
InnoDB 状态关键指标:
sql复制/* 缓冲池命中率 */
SELECT
(1 - (SELECT variable_value
FROM performance_schema.global_status
WHERE variable_name = 'Innodb_buffer_pool_reads') /
(SELECT variable_value
FROM performance_schema.global_status
WHERE variable_name = 'Innodb_buffer_pool_read_requests'))
* 100 AS hit_rate;
/* 锁等待分析 */
SELECT
event_name,
count_star,
sum_timer_wait/1000000000 AS total_seconds,
avg_timer_wait/1000000000 AS avg_seconds
FROM performance_schema.events_waits_summary_global_by_event_name
WHERE event_name LIKE 'wait/synch/mutex/innodb/%'
ORDER BY sum_timer_wait DESC
LIMIT 10;
9. 高可用与复制语句
9.1 主从复制配置
GTID 复制配置命令:
sql复制/* 主库配置 */
SET GLOBAL gtid_mode = ON;
SET GLOBAL enforce_gtid_consistency = ON;
/* 创建复制账号 */
CREATE USER 'repl'@'%' IDENTIFIED WITH caching_sha2_password BY 'repl_password';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
/* 从库配置 */
CHANGE MASTER TO
MASTER_HOST = 'master_host',
MASTER_USER = 'repl',
MASTER_PASSWORD = 'repl_password',
MASTER_AUTO_POSITION = 1;
START SLAVE;
9.2 复制状态监控
复制延迟诊断语句:
sql复制/* 查看复制线程状态 */
SHOW REPLICA STATUS\G
/* 计算Seconds_Behind_Master的替代方案 */
SELECT
ABS(TIMESTAMPDIFF(
SECOND,
SUBSTRING_INDEX(SUBSTRING_INDEX(
(SELECT variable_value
FROM performance_schema.global_status
WHERE variable_name = 'Slave_received_heartbeats'),
':', 2), ':', -1),
NOW()
)) AS estimated_lag_seconds;
10. 实用技巧与陷阱规避
10.1 日期处理技巧
时区转换的可靠方案:
sql复制/* 存储UTC时间,显示本地时间 */
CREATE TABLE events (
id BIGINT PRIMARY KEY,
event_time DATETIME NOT NULL DEFAULT UTC_TIMESTAMP(),
timezone VARCHAR(50) NOT NULL DEFAULT 'Asia/Shanghai'
);
/* 查询时转换 */
SELECT
id,
CONVERT_TZ(event_time, 'UTC', timezone) AS local_time
FROM events;
/* 日期范围查询优化 */
SELECT * FROM logs
WHERE log_time BETWEEN
'2023-01-01 00:00:00' AND '2023-01-31 23:59:59.999';
10.2 批量操作优化
大数据量更新的分片技巧:
sql复制/* 使用存储过程实现分片更新 */
DELIMITER //
CREATE PROCEDURE batch_update_users(IN batch_size INT)
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE min_id INT;
DECLARE max_id INT;
DECLARE current_id INT;
SELECT MIN(user_id), MAX(user_id) INTO min_id, max_id FROM users;
SET current_id = min_id;
WHILE current_id <= max_id DO
UPDATE users
SET last_active = NOW(),
login_count = login_count + 1
WHERE user_id BETWEEN current_id AND current_id + batch_size - 1;
SET current_id = current_id + batch_size;
COMMIT;
DO SLEEP(0.1); /* 减轻服务器负载 */
END WHILE;
END //
DELIMITER ;
10.3 元数据查询技巧
数据库文档自动生成语句:
sql复制SELECT
t.TABLE_SCHEMA,
t.TABLE_NAME,
t.TABLE_COMMENT,
c.COLUMN_NAME,
c.COLUMN_TYPE,
c.IS_NULLABLE,
c.COLUMN_DEFAULT,
c.COLUMN_COMMENT,
k.CONSTRAINT_NAME,
k.CONSTRAINT_TYPE,
k.REFERENCED_TABLE_NAME,
k.REFERENCED_COLUMN_NAME
FROM
INFORMATION_SCHEMA.TABLES t
JOIN
INFORMATION_SCHEMA.COLUMNS c ON t.TABLE_SCHEMA = c.TABLE_SCHEMA AND t.TABLE_NAME = c.TABLE_NAME
LEFT JOIN
INFORMATION_SCHEMA.KEY_COLUMN_USAGE k ON c.TABLE_SCHEMA = k.TABLE_SCHEMA
AND c.TABLE_NAME = k.TABLE_NAME
AND c.COLUMN_NAME = k.COLUMN_NAME
WHERE
t.TABLE_SCHEMA NOT IN ('mysql', 'sys', 'information_schema', 'performance_schema')
ORDER BY
t.TABLE_SCHEMA, t.TABLE_NAME, c.ORDINAL_POSITION;
关键经验:定期使用 CHECK TABLE 和 ANALYZE TABLE 维护数据健康
sql复制/* 表维护语句 */
CHECK TABLE important_table FAST QUICK;
ANALYZE TABLE frequently_updated_table;
OPTIMIZE TABLE large_table_with_deletes;
