作为一名天天和数据库打交道的资深老鸟,我见过太多系统上线后“扑街”的场景。很多性能问题,其实从你写下第一条SQL语句时就埋下了伏笔。尤其是那个看似人畜无害的 **SELECT *** ,简直是数据库性能的“隐形杀手”。
别再用“写着方便”当借口了。今天,我直接给你10条实打实的SQL优化骚操作,全程案例代码,让你的数据库跑得飞快。
1. 拒绝SELECT *,点名道姓
这是最基础也最核心的一步。**SELECT *** 会让数据库返回所有字段,不仅产生大量无用数据传输,还会让覆盖索引失效(导致回表查询)。
优化前(低效):
SELECT * FROM orders WHERE customer_id = 101;优化后(高效):
SELECT order_id, order_amount FROM orders WHERE customer_id = 101;效果:某金融系统将SELECT *替换为显式列后,API吞吐量从120 QPS直接飙升至400 QPS,数据传输量减少60%以上。
2. 数据太多了?建立索引直击灵魂
没有索引的查询就是全表扫描,纯属“暴力遍历”。
优化前: 查询48毫秒(全表扫描)
优化后:
CREATE INDEX idx_o_custkey ON orders (o_custkey); -- 建索引SELECT * FROM orders WHERE o_custkey = '1106459';效果:加了索引,查询直接降到18毫秒。
3. 分页深不见底?用“游标”别用OFFSET
深分页(如LIMIT 10000, 20)非常坑,数据库会先查10020行再丢弃前10000行。
优化前(深分页灾难):
SELECT * FROM orders ORDER BY id LIMIT 10 OFFSET 1000;优化后(键集分页):
SELECT id, amount FROM ordersWHERE id > 1000 -- 记住上一页最后一条的IDORDER BY id LIMIT 10;效果:百万级数据分页,响应时间从2秒优化到50毫秒。

4. OR条件太多?拆成UNION ALL
多个OR或IN有时候会让优化器发疯,认为全表扫描更划算。
优化前(索引失效):
SELECT * FROM table WHERE status = 'A' OR status = 'B' OR status = 'C';优化后(拆分查询):
SELECT * FROM table WHERE status='A'UNION ALLSELECT * FROM table WHERE status='B'UNION ALLSELECT * FROM table WHERE status='C';原理:每个子查询独立使用索引,效率倍增。
5. 数据统计太慢?上物化视图
复杂聚合查询(如多表SUM、GROUP BY)每次都实时计算,CPU直接爆表。
优化方案:
-- 创建物化视图(提前算好存起来)CREATE MATERIALIZED VIEW mv_order_summary ASSELECT product_id, SUM(amount) total, COUNT(*) ordersFROM order_details GROUP BY product_id;-- 查询时直接查视图SELECT * FROM mv_order_summary WHERE product_id = 1;效果:复杂查询从3秒降到200毫秒。
6. 数据量巨大?给表“分区”
对于有明显时间范围特征的大表(如订单表),不分区就是跟自己过不去。
优化前(全表扫描): 扫描73毫秒
优化后(分区剪枝):
-- 按日期分区后查询SELECT count(*) FROM orders_partitionedWHERE o_orderdate >= '1996-01-01';效果:通过分区剪枝,只扫描特定物理块,扫描时间从44ms降到13ms。
7. 函数用了索引废?改写WHERE条件
在索引字段上使用函数会导致索引失效。
优化前(索引失效):
SELECT * FROM orders WHERE DATE(order_date) = '2023-01-01';优化后(索引生效):
SELECT * FROM ordersWHERE order_date >= '2023-01-01'AND order_date < '2023-01-02';8. 用了UNION?试试ALL
UNION会做去重操作,非常耗时。如果你确定两个结果集没有重复,或者允许重复,务必用UNION ALL。
优化建议:
-- 没必去重的时候SELECT name FROM users_aUNION ALL -- 替代 UNIONSELECT name FROM users_b;9. NOT IN 坑太多,换 NOT EXISTS
NOT IN在子查询结果包含NULL时会出问题,且执行计划通常较差。
优化前(低效):
SELECT * FROM t1 WHERE c1 NOT IN (SELECT d2 FROM t2);优化后(高效):
SELECT * FROM t1 WHERE NOT EXISTS (SELECT 1 FROM t2 WHERE t1.c1 = t2.d2);10. 更新后还要查?用RETURNING
很多业务场景下,更新完数据后要立马查一次。这会产生两次网络往返。
优化方案(一条SQL搞定):
-- 更新并直接返回更新后的值UPDATE products SET price = price * 1.1WHERE product_id = 1001RETURNING product_id, name, price AS new_price;效果:减少一次数据库交互,高并发场景下TPS提升61%。
以上10条操作,都是经过一线实战检验的“硬核”技巧。别让你的数据库再负重前行了,从今天起,跟SELECT *说再见,用这些骚操作给它装上“火箭推进器”吧!