MySQL常用指令

40 阅读9分钟

第1部分:数据定义与基础操作

1.1 表结构设计与创建

-- 核心玩家表结构(包含业务所需的所有基础字段)
CREATE TABLE `player` (
    `player_id` INT PRIMARY KEY AUTO_INCREMENT COMMENT '玩家唯一ID',
    `username` VARCHAR(50) UNIQUE NOT NULL COMMENT '登录账号',
    `password_hash` VARCHAR(100) NOT NULL COMMENT '加密密码',
    `nickname` VARCHAR(50) NOT NULL COMMENT '显示昵称',
    `email` VARCHAR(100) UNIQUE COMMENT '绑定邮箱',
    `level` INT DEFAULT 1 COMMENT '玩家等级',
    `experience` BIGINT DEFAULT 0 COMMENT '当前经验值',
    `vip_level` TINYINT DEFAULT 0 COMMENT 'VIP等级',
    `diamonds` INT DEFAULT 0 COMMENT '钻石(充值货币)',
    `gold_coins` BIGINT DEFAULT 1000 COMMENT '金币(游戏货币)',
    `attack_power` INT DEFAULT 10 COMMENT '攻击力',
    `defense_power` INT DEFAULT 5 COMMENT '防御力',
    `max_hp` INT DEFAULT 100 COMMENT '最大生命值',
    `current_hp` INT DEFAULT 100 COMMENT '当前生命值',
    `last_login_ip` VARCHAR(45) COMMENT '最后登录IP',
    `last_login_time` DATETIME COMMENT '最后登录时间',
    `created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '注册时间',
    `is_banned` TINYINT(1) DEFAULT 0 COMMENT '是否封禁',
    `ban_reason` TEXT COMMENT '封禁原因',
    INDEX `idx_level` (`level`),
    INDEX `idx_vip` (`vip_level`),
    INDEX `idx_login_time` (`last_login_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='玩家主表';

1.2 基础数据操作(CRUD)

-- 1. 玩家注册:插入新玩家数据
INSERT INTO `player` (`username`, `password_hash`, `nickname`, `email`) 
VALUES ('player001', 'a1b2c3d4e5', '冒险者小明', 'xiaoming@example.com');

-- 2. 批量插入测试数据(用于开发环境)
INSERT INTO `player` (`username`, `password_hash`, `nickname`, `level`, `vip_level`, `gold_coins`) VALUES
('player002', 'hash002', '战士阿强', 15, 2, 50000),
('player003', 'hash003', '法师小美', 25, 5, 120000),
('player004', 'hash004', '游侠老张', 8, 0, 8000);

-- 3. 玩家登录验证:精确查询
SELECT `player_id`, `nickname`, `level`, `vip_level` 
FROM `player` 
WHERE `username` = 'player001' 
  AND `password_hash` = 'a1b2c3d4e5'
  AND `is_banned` = 0;

-- 4. 玩家信息更新
-- a. 等级提升
UPDATE `player` 
SET `level` = `level` + 1, 
    `experience` = `experience` - 1000,
    `attack_power` = `attack_power` + 5,
    `defense_power` = `defense_power` + 3
WHERE `player_id` = 1 
  AND `experience` >= 1000;

-- b. 货币变动(原子操作,避免并发问题)
UPDATE `player` 
SET `gold_coins` = `gold_coins` - 500,
    `diamonds` = `diamonds` + 50
WHERE `player_id` = 1 
  AND `gold_coins` >= 500;

-- 5. 账号封禁/解封
UPDATE `player` 
SET `is_banned` = 1, 
    `ban_reason` = '使用外挂程序'
WHERE `player_id` = 4;

-- 6. 删除测试数据(实际生产环境极少物理删除)
DELETE FROM `player` 
WHERE `player_id` = 4 
  AND `level` < 10 
  AND `last_login_time` < '2024-01-01';

第2部分:数据查询与分析

2.1 基础查询与筛选

-- 1. 精确查询:查看特定玩家完整信息
SELECT * FROM `player` WHERE `player_id` = 1;

-- 2. 条件组合:查找高等级VIP玩家
SELECT `player_id`, `nickname`, `level`, `vip_level`, `gold_coins`
FROM `player`
WHERE `level` >= 20 
  AND `vip_level` >= 3
  AND `is_banned` = 0
ORDER BY `level` DESC, `vip_level` DESC;

-- 3. 模糊查询:按昵称搜索玩家
SELECT `player_id`, `nickname`, `level`
FROM `player`
WHERE `nickname` LIKE '%冒险%'
  AND `is_banned` = 0
LIMIT 20;

-- 4. 范围查询:查找最近活跃玩家
SELECT `player_id`, `nickname`, `last_login_time`
FROM `player`
WHERE `last_login_time` >= DATE_SUB(NOW(), INTERVAL 7 DAY)
  AND `is_banned` = 0
ORDER BY `last_login_time` DESC;

-- 5. IN查询:批量查询特定玩家
SELECT `player_id`, `nickname`, `level`
FROM `player`
WHERE `player_id` IN (1, 3, 5, 7, 9)
ORDER BY FIELD(`player_id`, 1, 3, 5, 7, 9);

2.2 聚合分析与统计

-- 1. 基础统计:玩家总数、平均等级等
SELECT 
    COUNT(*) AS `total_players`,
    COUNT(CASE WHEN `is_banned` = 1 THEN 1 END) AS `banned_players`,
    AVG(`level`) AS `avg_level`,
    MAX(`level`) AS `max_level`,
    MIN(`level`) AS `min_level`,
    SUM(`gold_coins`) AS `total_gold`
FROM `player`;

-- 2. 分组统计:各等级段玩家分布
SELECT 
    CASE 
        WHEN `level` BETWEEN 1 AND 10 THEN '1-10级'
        WHEN `level` BETWEEN 11 AND 20 THEN '11-20级'
        WHEN `level` BETWEEN 21 AND 30 THEN '21-30级'
        ELSE '30级以上'
    END AS `level_range`,
    COUNT(*) AS `player_count`,
    AVG(`gold_coins`) AS `avg_gold`,
    SUM(`gold_coins`) AS `total_gold`
FROM `player`
WHERE `is_banned` = 0
GROUP BY `level_range`
ORDER BY MIN(`level`);

-- 3. VIP等级分析
SELECT 
    `vip_level`,
    COUNT(*) AS `player_count`,
    AVG(`level`) AS `avg_level`,
    AVG(`gold_coins`) AS `avg_gold`,
    SUM(`diamonds`) AS `total_diamonds`
FROM `player`
WHERE `is_banned` = 0
GROUP BY `vip_level`
HAVING `player_count` > 0  -- HAVING对分组结果筛选
ORDER BY `vip_level`;

-- 4. 活跃度分析(按最后登录时间分组)
SELECT 
    DATE(`last_login_time`) AS `login_date`,
    COUNT(*) AS `active_players`,
    AVG(`level`) AS `avg_level`
FROM `player`
WHERE `last_login_time` >= DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY DATE(`last_login_time`)
ORDER BY `login_date` DESC;

2.3 高级查询技巧

-- 1. 分页查询:玩家排行榜(效率优化版)
SELECT `player_id`, `nickname`, `level`, `vip_level`, `gold_coins`
FROM `player`
WHERE `is_banned` = 0
ORDER BY `level` DESC, `vip_level` DESC
LIMIT 20 OFFSET 0;  -- 第一页:OFFSET 0
-- 第二页:LIMIT 20 OFFSET 20

-- 2. 子查询:查找高于平均等级的玩家
SELECT `player_id`, `nickname`, `level`
FROM `player`
WHERE `level` > (SELECT AVG(`level`) FROM `player` WHERE `is_banned` = 0)
  AND `is_banned` = 0
ORDER BY `level` DESC;

-- 3. 自连接:查找相似等级的玩家(匹配系统)
SELECT 
    a.`player_id` AS `player_a_id`,
    a.`nickname` AS `player_a_name`,
    a.`level` AS `player_a_level`,
    b.`player_id` AS `player_b_id`,
    b.`nickname` AS `player_b_name`,
    b.`level` AS `player_b_level`
FROM `player` a
JOIN `player` b ON a.`player_id` < b.`player_id`  -- 避免重复配对
WHERE ABS(a.`level` - b.`level`) <= 3  -- 等级差不超过3级
  AND a.`is_banned` = 0
  AND b.`is_banned` = 0
LIMIT 10;

第3部分:多表关联实战

3.1 关联表设计与创建

-- 玩家背包表(与player表关联)
CREATE TABLE `player_inventory` (
    `inventory_id` INT PRIMARY KEY AUTO_INCREMENT,
    `player_id` INT NOT NULL,
    `item_id` INT NOT NULL,
    `item_type` VARCHAR(50) NOT NULL COMMENT '装备/消耗品/材料',
    `item_name` VARCHAR(100) NOT NULL,
    `quantity` INT DEFAULT 1,
    `equipped` TINYINT(1) DEFAULT 0 COMMENT '是否装备中',
    `acquired_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (`player_id`) REFERENCES `player`(`player_id`) ON DELETE CASCADE,
    INDEX `idx_player_item` (`player_id`, `item_id`),
    INDEX `idx_player_equipped` (`player_id`, `equipped`)
) COMMENT='玩家背包物品表';

-- 玩家任务表
CREATE TABLE `player_quests` (
    `record_id` INT PRIMARY KEY AUTO_INCREMENT,
    `player_id` INT NOT NULL,
    `quest_id` INT NOT NULL,
    `quest_name` VARCHAR(100) NOT NULL,
    `status` ENUM('未开始','进行中','已完成','已奖励') DEFAULT '未开始',
    `progress` INT DEFAULT 0,
    `total_required` INT NOT NULL,
    `started_time` DATETIME,
    `completed_time` DATETIME,
    FOREIGN KEY (`player_id`) REFERENCES `player`(`player_id`) ON DELETE CASCADE,
    UNIQUE KEY `uq_player_quest` (`player_id`, `quest_id`),
    INDEX `idx_player_status` (`player_id`, `status`)
) COMMENT='玩家任务进度表';

3.2 关联查询实战

-- 1. INNER JOIN:查询玩家及其背包物品
SELECT 
    p.`nickname`,
    p.`level`,
    i.`item_name`,
    i.`quantity`,
    i.`equipped`
FROM `player` p
INNER JOIN `player_inventory` i ON p.`player_id` = i.`player_id`
WHERE p.`player_id` = 1
  AND p.`is_banned` = 0
ORDER BY i.`equipped` DESC, i.`acquired_time` DESC;

-- 2. LEFT JOIN:查询所有玩家(即使没有物品)
SELECT 
    p.`player_id`,
    p.`nickname`,
    COUNT(i.`inventory_id`) AS `item_count`,
    SUM(i.`quantity`) AS `total_items`
FROM `player` p
LEFT JOIN `player_inventory` i ON p.`player_id` = i.`player_id`
WHERE p.`is_banned` = 0
GROUP BY p.`player_id`, p.`nickname`
HAVING `item_count` > 0
ORDER BY `total_items` DESC;

-- 3. 多表JOIN:玩家+任务+背包物品
SELECT 
    p.`nickname`,
    q.`quest_name`,
    q.`status`,
    q.`progress`,
    q.`total_required`,
    i.`item_name` AS `required_item`,
    i.`quantity` AS `item_quantity`
FROM `player` p
INNER JOIN `player_quests` q ON p.`player_id` = q.`player_id`
LEFT JOIN `player_inventory` i ON p.`player_id` = i.`player_id` 
    AND i.`item_name` = q.`quest_name`  -- 假设任务需要特定物品
WHERE p.`player_id` = 1
  AND q.`status` = '进行中'
ORDER BY q.`started_time` DESC;

-- 4. 子查询作为关联条件:查找拥有特定稀有物品的玩家
SELECT 
    p.`player_id`,
    p.`nickname`,
    p.`level`,
    p.`vip_level`,
    (SELECT GROUP_CONCAT(`item_name`) 
     FROM `player_inventory` 
     WHERE `player_id` = p.`player_id` 
       AND `item_type` = '传奇装备'
    ) AS `legendary_items`
FROM `player` p
WHERE EXISTS (
    SELECT 1 
    FROM `player_inventory` i 
    WHERE i.`player_id` = p.`player_id` 
      AND i.`item_type` = '传奇装备'
      AND i.`equipped` = 1
)
AND p.`is_banned` = 0
ORDER BY p.`level` DESC;

3.3 联合查询与临时结果

-- 1. UNION:合并不同条件的查询结果
-- 查找高等级玩家 或 高VIP玩家(去重)
SELECT `player_id`, `nickname`, `level`, `vip_level`, '高等级' AS `category`
FROM `player`
WHERE `level` >= 30 AND `is_banned` = 0
UNION
SELECT `player_id`, `nickname`, `level`, `vip_level`, '高VIP' AS `category`
FROM `player`
WHERE `vip_level` >= 5 AND `is_banned` = 0
ORDER BY `level` DESC, `vip_level` DESC;

-- 2. 使用派生表(子查询作为临时表)
SELECT 
    t.`player_id`,
    t.`nickname`,
    t.`total_gold`,
    t.`item_count`,
    ROUND(t.`total_gold` / NULLIF(t.`item_count`, 0), 2) AS `gold_per_item`
FROM (
    SELECT 
        p.`player_id`,
        p.`nickname`,
        p.`gold_coins` AS `total_gold`,
        COUNT(i.`inventory_id`) AS `item_count`
    FROM `player` p
    LEFT JOIN `player_inventory` i ON p.`player_id` = i.`player_id`
    WHERE p.`is_banned` = 0
    GROUP BY p.`player_id`, p.`nickname`, p.`gold_coins`
) t
WHERE t.`item_count` > 0
ORDER BY `gold_per_item` DESC;

第4部分:数据维护与优化

4.1 表结构维护

-- 1. 增加新字段(如添加手机号字段)
ALTER TABLE `player`
ADD COLUMN `phone_number` VARCHAR(20) UNIQUE COMMENT '绑定手机号' AFTER `email`,
ADD INDEX `idx_phone` (`phone_number`);

-- 2. 修改字段属性
ALTER TABLE `player`
MODIFY COLUMN `gold_coins` BIGINT DEFAULT 0 COMMENT '游戏金币',
MODIFY COLUMN `email` VARCHAR(150) UNIQUE COMMENT '电子邮箱';

-- 3. 添加复合索引优化查询
ALTER TABLE `player`
ADD INDEX `idx_level_vip` (`level`, `vip_level`),
ADD INDEX `idx_login_status` (`last_login_time`, `is_banned`);

-- 4. 删除冗余索引
ALTER TABLE `player`
DROP INDEX `idx_level`,  -- 如果idx_level_vip已经够用
DROP INDEX `idx_vip`;

4.2 数据维护操作

-- 1. 批量更新:为所有活跃玩家发放奖励
UPDATE `player`
SET `gold_coins` = `gold_coins` + 1000,
    `diamonds` = `diamonds` + 50
WHERE `last_login_time` >= DATE_SUB(NOW(), INTERVAL 3 DAY)
  AND `is_banned` = 0;

-- 2. 数据归档:将久未登录玩家标记为不活跃
UPDATE `player`
SET `current_hp` = `max_hp`  -- 恢复满血状态
WHERE `last_login_time` < DATE_SUB(NOW(), INTERVAL 180 DAY)
  AND `is_banned` = 0
  AND `current_hp` < `max_hp`;

-- 3. 数据清理:删除测试账号
DELETE FROM `player`
WHERE `username` LIKE 'test%'
  AND `last_login_time` < DATE_SUB(NOW(), INTERVAL 30 DAY);

-- 4. 使用事务保证数据一致性(在Java中更重要)
START TRANSACTION;

UPDATE `player`
SET `gold_coins` = `gold_coins` - 1000
WHERE `player_id` = 1 AND `gold_coins` >= 1000;

INSERT INTO `player_inventory` (`player_id`, `item_id`, `item_name`, `quantity`)
VALUES (1, 1001, '传奇武器', 1);

COMMIT;  -- 如果任何一步失败,执行ROLLBACK

4.3 性能优化查询

-- 1. 使用EXPLAIN分析查询性能
EXPLAIN SELECT * FROM `player` WHERE `level` BETWEEN 20 AND 30;

-- 2. 强制使用特定索引
SELECT `player_id`, `nickname`, `level`
FROM `player` FORCE INDEX (`idx_level_vip`)
WHERE `level` >= 25
  AND `vip_level` >= 3
ORDER BY `level` DESC
LIMIT 100;

-- 3. 避免SELECT *,只选择需要的列
SELECT `player_id`, `nickname`, `level`, `vip_level`, `last_login_time`
FROM `player`
WHERE `is_banned` = 0
  AND `last_login_time` >= DATE_SUB(NOW(), INTERVAL 1 DAY);

-- 4. 分页优化:使用WHERE代替OFFSET(大数据量时)
-- 传统方式(大数据量时慢):
SELECT * FROM `player` ORDER BY `player_id` LIMIT 20 OFFSET 100000;

-- 优化方式:
SELECT * FROM `player` 
WHERE `player_id` > 100000  -- 上次查询的最后一个ID
ORDER BY `player_id` 
LIMIT 20;