记录学习与后端知识并分享学习代码过程(会飞的鱼Blog)

MySQL索引优化与EXPLAIN分析

会飞的鱼 0 3 2026年6月12日

MySQL索引优化

数据库优化能带来数倍的性能提升,索引优化解决90%的慢查询问题。本文分享3个完整可运行的SQL脚本,涵盖MySQL核心优化技能。

完整索引优化实战

正确的索引设计是数据库性能的基石。

DROP TABLE IF EXISTS users;
CREATE TABLE users (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    email VARCHAR(100) NOT NULL,
    status TINYINT DEFAULT 1,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 创建单列索引
CREATE INDEX idx_users_email ON users(email);

-- 创建唯一索引
CREATE UNIQUE INDEX idx_users_username ON users(username);

-- 创建联合索引(最左前缀原则)
CREATE INDEX idx_status_created ON users(status, created_at);

-- 插入测试数据
INSERT INTO users (username, email, status) VALUES
('user1', 'user1@example.com', 1),
('user2', 'user2@example.com', 1),
('user3', 'user3@example.com', 0);

-- 使用EXPLAIN分析查询
EXPLAIN SELECT * FROM users WHERE email = 'user1@example.com';

-- 覆盖索引优化(避免回表)
EXPLAIN SELECT id, email FROM users WHERE email = 'user1@example.com';

-- 时间范围查询优化
EXPLAIN SELECT * FROM users 
WHERE created_at >= '2024-01-01' 
  AND created_at < '2024-01-02';

完整JOIN查询优化

JOIN功能强大但需要正确使用。

DROP TABLE IF EXISTS orders;
CREATE TABLE orders (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    user_id INT UNSIGNED NOT NULL,
    order_no VARCHAR(32) NOT NULL,
    amount DECIMAL(10,2) NOT NULL DEFAULT 0,
    INDEX idx_user_id (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO orders (user_id, order_no, amount) VALUES
(1, 'ORD001', 99.00),
(1, 'ORD002', 199.00),
(2, 'ORD003', 299.00);

-- INNER JOIN查询
SELECT u.id, u.username, o.order_no, o.amount
FROM users u
INNER JOIN orders o ON u.id = o.user_id
WHERE u.id = 1;

-- 小表驱动大表
SELECT u.id, u.username, o.amount
FROM users u
STRAIGHT_JOIN orders o ON u.id = o.user_id;

-- 创建联合覆盖索引
CREATE INDEX idx_order_user_amount ON orders(user_id, amount);

-- GROUP BY优化
EXPLAIN SELECT user_id, SUM(amount) 
FROM orders 
GROUP BY user_id;

完整事务与锁机制

事务确保金融类应用的数据一致性。

DROP TABLE IF EXISTS goods;
CREATE TABLE goods (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    stock INT UNSIGNED NOT NULL DEFAULT 0,
    version INT UNSIGNED NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO goods (name, stock, version) VALUES
('iPhone 15', 100, 1);

-- 悲观锁(FOR UPDATE)
START TRANSACTION;
SELECT * FROM goods WHERE id = 1 FOR UPDATE;
UPDATE goods SET stock = stock - 1 WHERE id = 1;
COMMIT;

-- 查看更新后的数据
SELECT stock, version FROM goods WHERE id = 1;

-- 乐观锁(版本号)
UPDATE goods 
SET stock = stock - 1, version = version + 1 
WHERE id = 1 AND version = 1;

-- 检查影响行数
SELECT ROW_COUNT();

-- 查看最终库存
SELECT * FROM goods;

MySQL最佳实践

  1. 使用合适的数据类型,避免NULL,优先INT UNSIGNED
  2. 使用utf8mb4字符集支持完整emoji
  3. InnoDB引擎支持事务和行锁
  4. 自增INT主键,不使用UUID
  5. 大数据分页:WHERE id > last_id LIMIT 20
  6. 批量操作:每次1000条记录
  7. 慢查询日志:long_query_time = 1秒

技术分享,欢迎评论区交流讨论。

本文由 @会飞的鱼 于 2026-6-12 发布在 会飞的鱼Blog,如无特别说明,本博文章均为原创,转载请保留出处。

网友评论

    暂无评论

会飞的鱼 在线咨询

在线时间:9:00-22:00
周六、周日:14:00-22:00