-- B+Tree 索引(默认) CREATE INDEX idx_name ON users(name);
-- 唯一索引 CREATEUNIQUE INDEX uk_email ON users(email);
-- 复合索引 CREATE INDEX idx_name_age ON users(name, age);
-- 前缀索引 CREATE INDEX idx_content ON articles(content(100));
-- 全文索引 CREATE FULLTEXT INDEX ft_title ON articles(title, content);
索引使用原则
最左前缀原则
1 2 3 4 5 6
-- 索引 (a, b, c) WHERE a =1-- 使用索引 WHERE a =1AND b =2-- 使用索引 WHERE a =1AND b =2AND c =3-- 使用索引 WHERE b =2-- 不使用索引 WHERE a =1AND c =3-- 只使用 a
避免索引失效
1 2 3 4 5 6
-- 索引失效的情况 WHERE name LIKE'%john%'-- 前导模糊查询 WHEREYEAR(created_at) =2024-- 对字段使用函数 WHERE id +1=100-- 对字段进行计算 WHERE status !='active'-- 不等于 WHERE status ISNULL-- IS NULL(部分场景)
2.2 SQL 优化
查询优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
-- 避免 SELECT * SELECT id, name, email FROM users WHERE status ='active';
-- 使用覆盖索引 SELECT id, name FROM users WHERE name ='John'; -- 如果索引是 (name),且查询字段只有 id 和 name,则无需回表
-- 使用 EXPLAIN 分析查询 EXPLAIN SELECT*FROM users WHERE email ='john@example.com';
-- 优化分页查询 -- 低效 SELECT*FROM orders LIMIT 1000000, 10; -- 高效 SELECT*FROM orders WHERE id >1000000 LIMIT 10; -- 或使用延迟关联 SELECT*FROM orders o JOIN (SELECT id FROM orders LIMIT 1000000, 10) tmp ON o.id = tmp.id;
JOIN 优化
1 2 3 4 5 6 7 8 9
-- 确保关联字段有索引 CREATE INDEX idx_user_id ON orders(user_id);
-- 小表驱动大表 SELECT*FROM small_table s JOIN large_table l ON s.id = l.small_id;
-- 范围分区 CREATE TABLE logs ( id INT, message TEXT, created_at TIMESTAMP ) PARTITIONBYRANGE (YEAR(created_at)) ( PARTITION p2022 VALUES LESS THAN (2023), PARTITION p2023 VALUES LESS THAN (2024), PARTITION p2024 VALUES LESS THAN (2025), PARTITION pfuture VALUES LESS THAN MAXVALUE );
-- 排名函数 SELECT name, department, salary, RANK() OVER (PARTITIONBY department ORDERBY salary DESC) as rank, DENSE_RANK() OVER (PARTITIONBY department ORDERBY salary DESC) as dense_rank, ROW_NUMBER() OVER (PARTITIONBY department ORDERBY salary DESC) as row_num FROM employees;
-- 聚合窗口函数 SELECT date, amount, SUM(amount) OVER (ORDERBYdate) as running_total, AVG(amount) OVER (ORDERBYdateROWSBETWEEN6 PRECEDING ANDCURRENTROW) as moving_avg FROM sales;
-- 取值窗口函数 SELECT name, salary, LAG(salary) OVER (ORDERBY salary) as prev_salary, LEAD(salary) OVER (ORDERBY salary) as next_salary, FIRST_VALUE(salary) OVER (ORDERBY salary) as lowest_salary, LAST_VALUE(salary) OVER (ORDERBY salary ROWSBETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as highest_salary FROM employees;