刚接触MySQL时,我最常被问到的就是"怎么建表"和"怎么查数据"。这两个操作看似简单,但实际工作中发现很多开发者只停留在基础语法层面,遇到复杂业务场景就束手无策。今天我就结合8年数据库运维经验,从底层原理到实战技巧,系统梳理MySQL表操作与查询的完整知识体系。
MySQL作为关系型数据库的代表,其表结构设计直接影响查询性能和数据完整性。一个规范的users表创建应该像这样:
sql复制CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '登录账号',
`password` char(60) NOT NULL COMMENT 'BCrypt加密密码',
`email` varchar(100) DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`),
KEY `idx_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
这个建表语句包含了几个关键设计:
选择合适的数据类型能显著提升存储效率和查询性能。常见陷阱包括:
经验:金额字段建议用DECIMAL(19,4),避免浮点精度问题
索引是把双刃剑,我的索引设计检查清单:
sql复制-- 联合索引经典案例
ALTER TABLE `orders` ADD INDEX `idx_status_created` (`status`, `created_at`);
-- 覆盖索引优化
EXPLAIN SELECT order_id FROM orders WHERE status = 1 AND created_at > '2023-01-01';
使用EXPLAIN分析以下查询:
sql复制EXPLAIN SELECT u.username, o.order_no
FROM users u JOIN orders o ON u.id = o.user_id
WHERE u.status = 1 AND o.amount > 100
ORDER BY o.created_at DESC LIMIT 10;
关键指标解读:
处理过一个生产环境慢查询案例:
sql复制-- 优化前(执行时间2.8s)
SELECT * FROM logs
WHERE DATE(create_time) = '2023-05-20'
ORDER BY id DESC LIMIT 100;
-- 优化后(执行时间0.02s)
SELECT * FROM logs
WHERE create_time >= '2023-05-20 00:00:00'
AND create_time < '2023-05-21 00:00:00'
ORDER BY id DESC LIMIT 100;
优化要点:
MySQL 8.0+支持的窗口函数能实现复杂分析:
sql复制-- 计算每个用户的订单金额排名
SELECT
user_id,
order_amount,
RANK() OVER (PARTITION BY user_id ORDER BY order_amount DESC) as rank_val
FROM orders
WHERE create_time > '2023-01-01';
递归CTE处理树形数据:
sql复制WITH RECURSIVE category_path AS (
-- 基础查询(锚成员)
SELECT id, name, parent_id, 1 AS level
FROM categories WHERE parent_id IS NULL
UNION ALL
-- 递归查询(递归成员)
SELECT c.id, c.name, c.parent_id, cp.level + 1
FROM category_path cp JOIN categories c ON cp.id = c.parent_id
)
SELECT * FROM category_path ORDER BY level;
通过SHOW ENGINE INNODB STATUS检查锁冲突:
code复制---TRANSACTION 3123456, ACTIVE 5 sec
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 123, OS thread handle 140123456789, query id 456 10.0.0.1 user1 updating
UPDATE products SET stock = stock - 1 WHERE id = 100
------- TRX HAS BEEN WAITING 5 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 12 page no 5 n bits 80 index PRIMARY of table `db`.`products` trx id 3123456 lock_mode X locks rec but not gap waiting
解决方法:
典型的分页性能问题:
sql复制-- 低效写法(偏移量大时性能骤降)
SELECT * FROM large_table LIMIT 1000000, 20;
-- 优化方案1:基于主键分页
SELECT * FROM large_table WHERE id > 1000000 ORDER BY id LIMIT 20;
-- 优化方案2:延迟关联
SELECT t.* FROM large_table t
JOIN (SELECT id FROM large_table ORDER BY create_time LIMIT 1000000, 20) tmp
ON t.id = tmp.id;
必备监控项:
sql复制-- 查看当前连接数
SHOW STATUS LIKE 'Threads_connected';
-- 查看慢查询数量
SHOW STATUS LIKE 'Slow_queries';
-- 查看InnoDB缓冲池命中率
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 buffer_pool_hit_ratio;
定期维护命令:
sql复制-- 分析表统计信息
ANALYZE TABLE important_table;
-- 优化碎片化严重的表
OPTIMIZE TABLE fragmented_table;
-- 在线修改大表结构(MySQL 5.6+)
ALTER TABLE large_table
ADD COLUMN new_column INT DEFAULT 0,
ALGORITHM=INPLACE, LOCK=NONE;
在千万级用户系统中,我们通过以上优化手段将核心查询性能提升了15倍。记住,好的数据库设计不是一蹴而就的,需要结合业务特点持续调优。每次schema变更前,务必在测试环境验证执行计划变化。