-- 按月分区订单表 CREATE TABLE orders_partitioned ( id BIGINTPRIMARY KEY, user_id BIGINTNOT NULL, amount DECIMAL(10,2) NOT NULL, status TINYINT NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL ) PARTITIONBYRANGE (YEAR(created_at)) ( PARTITION p2023 VALUES LESS THAN (2024), PARTITION p2024 VALUES LESS THAN (2025), PARTITION p2025 VALUES LESS THAN (2026), PARTITION p_future VALUES LESS THAN MAXVALUE );
-- 按月分区(更细粒度) CREATE TABLE orders_monthly ( id BIGINTPRIMARY KEY, user_id BIGINTNOT NULL, amount DECIMAL(10,2) NOT NULL, status TINYINT NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL ) PARTITIONBYRANGE (UNIX_TIMESTAMP(created_at)) ( PARTITION p202401 VALUES LESS THAN (UNIX_TIMESTAMP('2024-02-01')), PARTITION p202402 VALUES LESS THAN (UNIX_TIMESTAMP('2024-03-01')), PARTITION p202403 VALUES LESS THAN (UNIX_TIMESTAMP('2024-04-01')), -- ... 更多分区 PARTITION p_future VALUES LESS THAN MAXVALUE );
-- 用户ID哈希分区 CREATE TABLE user_logs ( id BIGINTPRIMARY KEY, user_id BIGINTNOT NULL, action VARCHAR(100) NOT NULL, data JSON, created_at DATETIME NOT NULL ) PARTITIONBY HASH(user_id) PARTITIONS 16;
-- 复合分区:时间 + 哈希 CREATE TABLE audit_logs ( id BIGINTPRIMARY KEY, table_name VARCHAR(50) NOT NULL, record_id BIGINTNOT NULL, action VARCHAR(20) NOT NULL, old_data JSON, new_data JSON, user_id BIGINT, created_at DATETIME NOT NULL ) PARTITIONBYRANGE (YEAR(created_at)) SUBPARTITION BY HASH(record_id) ( PARTITION p2024 VALUES LESS THAN (2025) ( SUBPARTITION p2024_h0, SUBPARTITION p2024_h1, SUBPARTITION p2024_h2, SUBPARTITION p2024_h3 ), PARTITION p2025 VALUES LESS THAN (2026) ( SUBPARTITION p2025_h0, SUBPARTITION p2025_h1, SUBPARTITION p2025_h2, SUBPARTITION p2025_h3 ) );
🔍 索引优化策略
1. 索引类型选择
📚 B-Tree索引
1 2 3 4 5 6 7 8 9 10 11 12 13
-- 单列索引 CREATE INDEX idx_user_email ON users(email);
-- 复合索引(最左前缀原则) CREATE INDEX idx_order_user_created ON orders(user_id, created_at); CREATE INDEX idx_product_category_price ON products(category_id, price);
-- 覆盖索引(包含查询所需的所有列) CREATE INDEX idx_user_covering ON users(email, username, status, last_login) WHERE status ='active';
-- 函数索引 CREATE INDEX idx_email_domain ON users((SUBSTRING_INDEX(email, '@', -1)));
-- 全文索引用于文本搜索 CREATE TABLE articles ( id BIGINTPRIMARY KEY, title VARCHAR(200) NOT NULL, content TEXT NOT NULL, tags VARCHAR(500), author_id BIGINTNOT NULL, created_at DATETIME NOT NULL,
-- 空间数据表 CREATE TABLE locations ( id BIGINTPRIMARY KEY, name VARCHAR(100) NOT NULL, coordinates POINT NOT NULL, -- MySQL 8.0+ 原生支持 address VARCHAR(255),
SPATIAL INDEX idx_coordinates (coordinates) );
-- 空间查询 SELECT name, ST_Distance(coordinates, ST_GeomFromText('POINT(116.4074 39.9042)')) AS distance FROM locations ORDERBY distance LIMIT 10;
-- ❌ 低效子查询 SELECT u.username, u.email FROM users u WHERE u.id IN ( SELECTDISTINCT user_id FROM orders WHERE created_at >='2024-01-01' );
-- ✅ 优化为JOIN SELECTDISTINCT u.username, u.email FROM users u INNERJOIN orders o ON u.id = o.user_id WHERE o.created_at >='2024-01-01';
-- ❌ 标量子查询 SELECT o.id, o.amount, (SELECTCOUNT(*) FROM order_items WHERE order_id = o.id) as item_count FROM orders o;
-- ✅ 优化为LEFT JOIN SELECT o.id, o.amount, COUNT(oi.id) as item_count FROM orders o LEFTJOIN order_items oi ON o.id = oi.order_id GROUPBY o.id, o.amount;
-- ✅ 延迟关联优化 SELECT o.* FROM orders o INNERJOIN ( SELECT id FROM orders ORDERBY created_at DESC LIMIT 100000, 20 ) t ON o.id = t.id ORDERBY o.created_at DESC;
-- 明确连接顺序(小表在前) EXPLAIN SELECT u.username, COUNT(o.id) as order_count FROM users u STRAIGHT_JOIN orders o ON u.id = o.user_id -- 强制连接顺序 WHERE u.created_at >='2024-01-01' GROUPBY u.id, u.username;
-- 连接缓冲优化 SET optimizer_switch ='join_buffer_size=256K';
-- 嵌套循环连接优化 SELECT/*+ JOIN_ORDER(u,o) */ u.username, o.amount FROM users u JOIN orders o ON u.id = o.user_id WHERE u.status ='active';
📈 连接算法选择
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
-- 强制使用哈希连接(MySQL 8.0.18+) SELECT/*+ HASH_JOIN(u,o) */ u.username, COUNT(o.id) FROM users u JOIN orders o ON u.id = o.user_id GROUPBY u.username;
-- 强制使用合并连接 SELECT/*+ MERGE_JOIN(u,o) */ u.username, o.amount FROM users u JOIN orders o ON u.id = o.user_id WHERE u.created_at >='2024-01-01';
-- 强制使用索引连接 SELECT/*+ INDEX_JOIN(u idx_user_status) */ u.username FROM users u WHERE u.status ='active';
3. 聚合查询优化
📊 GROUP BY优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
-- 宽索引优化GROUP BY CREATE INDEX idx_user_status_created_amount ON orders(user_id, status, created_at, amount);
SELECT user_id, COUNT(*) as order_count, SUM(amount) as total_amount, AVG(amount) as avg_amount FROM orders WHERE status =2AND created_at >='2024-01-01' GROUPBY user_id;
-- 松散索引扫描(MySQL 8.0+) SET optimizer_switch ='loose_scan=on';
SELECT user_id, COUNT(*) FROM orders GROUPBY user_id;
🎯 窗口函数优化
1 2 3 4 5 6 7 8 9 10 11 12 13
-- 传统自连接方式(低效) SELECT o1.id, o1.amount, o1.created_at, SUM(o2.amount) as running_total FROM orders o1 JOIN orders o2 ON o1.user_id = o2.user_id AND o2.created_at <= o1.created_at GROUPBY o1.id, o1.amount, o1.created_at;
-- 窗口函数优化(高效) SELECT id, amount, created_at, SUM(amount) OVER (PARTITIONBY user_id ORDERBY created_at) as running_total, ROW_NUMBER() OVER (PARTITIONBY user_id ORDERBY created_at) as order_seq FROM orders;
CREATE TABLE users ( id BIGINTPRIMARY KEY, username VARCHAR(50) UNIQUENOT NULL, email VARCHAR(100) UNIQUENOT NULL, password_hash VARCHAR(255) NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL );
-- 订单库 CREATE DATABASE order_db; USE order_db;
CREATE TABLE orders ( id BIGINTPRIMARY KEY, user_id BIGINTNOT NULL, amount DECIMAL(10,2) NOT NULL, status TINYINT NOT NULL, created_at DATETIME NOT NULL );
-- 商品库 CREATE DATABASE product_db; USE product_db;
CREATE TABLE products ( id BIGINTPRIMARY KEY, name VARCHAR(200) NOT NULL, price DECIMAL(10,2) NOT NULL, category_id BIGINTNOT NULL, stock INTNOT NULL );
-- 分析具体慢查询 EXPLAIN SELECT u.username, COUNT(o.id) as order_count FROM users u LEFTJOIN orders o ON u.id = o.user_id WHERE u.created_at >='2024-01-01' GROUPBY u.id, u.username;
-- 使用Profile分析查询 SET profiling =1; SELECT*FROM large_table WHERE complex_condition; SHOW PROFILE FOR QUERY 1;
-- 4. 合理使用JOIN SELECT u.name, COUNT(o.id) as order_count FROM users u LEFTJOIN orders o ON u.id = o.user_id WHERE u.created_at >='2024-01-01' GROUPBY u.id, u.name;
-- 5. 使用UNION ALL替代UNION SELECT id, name FROM users WHERE status ='active' UNIONALL SELECT id, name FROM users WHERE created_at >='2024-01-01';