别再无脑加索引!掌握这83个场景,才算真正懂SQL优化

阿里云教程6小时前发布
1 1 0

是不是又被慢查询搞崩溃了?

页面转圈圈,老板在催催,急得我们满头包,最后只好双手一摊:“再加个索引试试?”

打住!别再无脑加索引了,数据库快被我们加成刺猬了!

真正的SQL优化,是一门手艺活。从我们写的每一句SQL代码,到数据库怎么存数据、怎么搭架子,都有讲究。

下面整理了83个SQL优化场景示例,从“千万别用SELECT *”这种小细节,到“分库分表”这种大型架构,让我们一起告别野路子,掌握让数据库起飞的正确姿势!

1、避免 SELECT *

场景:我们查询用户详情时排除敏感字段

-- ❌ 返回全部字段(含不需要的敏感字段)
SELECT * FROM users WHERE id = 1001; -- 包含password等无用字段
-- ✅ 明确指定字段(提升性能与安全性)
SELECT user_id, name, email, created_at 
FROM users 
WHERE id = 1001; -- 仅返回必要字段

典型应用:Web接口返回用户公开信息时减少数据传输量。

2、EXISTS 替代 IN 检查活跃订单

场景:我们查询活跃客户的订单

-- ❌ IN子查询可能返回NULL导致漏数据
SELECT * FROM orders 
WHERE customer_id IN (
    SELECT id FROM customers WHERE status = 'active' -- 子查询效率低
);
-- ✅ EXISTS在匹配后立即终止扫描
SELECT * FROM orders o 
WHERE EXISTS (
    SELECT 1 FROM customers c 
    WHERE c.id = o.customer_id 
    AND c.status = 'active'  -- 利用索引快速定位
);

典型应用:电商平台筛选有效订单时避免全表扫描。

3、延迟关联优化千万级数据分页

场景:分页展示用户行为日志

-- ❌ 深分页时OFFSET效率骤降
SELECT * FROM user_logs 
ORDER BY log_time DESC 
LIMIT 10 OFFSET 500000; -- 需扫描50万+10行
-- ✅ 先通过索引定位ID再取数据
SELECT log.* 
FROM user_logs log
JOIN (
    SELECT id FROM user_logs          -- 仅扫描索引
    ORDER BY log_time DESC 
    LIMIT 10 OFFSET 500000
) tmp ON log.id = tmp.id;             -- 回表取10行数据

典型应用:后台管理系统查看历史操作日志。

4、批量更新用户积分

场景:活动期间批量增加用户积分

-- ❌ 循环单条更新(网络I/O翻倍)
UPDATE users SET points = points + 10 WHERE id = 1001;
UPDATE users SET points = points + 10 WHERE id = 1002;
...
-- ✅ 单次批量操作(减少99%开销)
UPDATE users SET points = points + 10 
WHERE id IN (1001, 1002, ..., 10000); -- 一次更新1万用户

典型应用:运营活动批量发放奖励。

5、UNION ALL 拆分OR条件

场景:多条件混合查询日志

-- ❌ OR导致索引失效(type='error'与source='api'无复合索引)
SELECT * FROM system_log 
WHERE log_type = 'error' OR source_module = 'api';
-- ✅ 拆分查询并去重(各自走索引)
SELECT * FROM system_log WHERE log_type = 'error'  -- 索引: log_type
UNION ALL
SELECT * FROM system_log 
WHERE source_module = 'api' 
  AND log_type != 'error';           -- 索引: source_module

典型应用:监控系统多维度检索告警日志。

6、避免函数转换出生日期

场景:我们统计1990年出生用户

-- ❌ 函数计算导致索引失效
SELECT * FROM users 
WHERE YEAR(birthday) = 1990;         -- 无法使用birthday索引
-- ✅ 直接比较日期范围
SELECT * FROM users 
WHERE birthday BETWEEN '1990-01-01' AND '1990-12-31'; -- 走日期索引

典型应用:用户画像按年龄段分析。

7、小表驱动大表JOIN顺序

场景:部门表(小)关联销售表(大)

-- ❌ 大表作驱动表(可能全表扫描)
SELECT s.* FROM sales s 
JOIN departments d ON s.dept_id = d.id; 
-- ✅ 小表驱动大表(强制优化器顺序):STRAIGHT_JOIN是MySQL专属语法
SELECT /*+ STRAIGHT_JOIN */ s.* 
FROM departments d                   -- 100行的小表
JOIN sales s ON d.id = s.dept_id;    -- 驱动1亿行大表
-- ✅ PostgreSQL方案:用LEADING提示
SELECT /*+ LEADING(d s) */ s.* 
FROM departments d
JOIN sales s ON d.id = s.dept_id;
-- ✅ Oracle方案:用ORDERED提示
SELECT /*+ ORDERED */ s.* 
FROM departments d
JOIN sales s ON d.id = s.dept_id;

典型应用:数据仓库中维度表关联实际表。

8、覆盖索引加速订单查询

场景:我们查询用户订单概要

-- 创建覆盖索引(包含所有查询字段)
CREATE INDEX idx_user_orders ON orders (user_id, order_date, amount);
-- ✅ 直接从索引取数据(避免回表)
SELECT user_id, order_date, amount   -- 所有字段均在索引中
FROM orders 
WHERE user_id = 2003;                -- 索引覆盖扫描

典型应用:订单列表页快速加载基础信息。

9、常量条件提前过滤

场景:我们按区域和品类筛选销售数据

-- ❌ JOIN后过滤(可能处理大量无效数据)
SELECT * 
FROM sales s
JOIN products p ON s.product_id = p.id 
WHERE s.region = 'Asia' AND p.category = 'Electronics';
-- ✅ 先过滤区域再JOIN(减少参与JOIN的数据量)
SELECT * 
FROM sales s
JOIN products p ON s.product_id = p.id 
WHERE s.region = 'Asia'              -- 先过滤90%非亚洲数据
  AND p.category = 'Electronics';     -- 再关联产品表

典型应用:BI报表中多层过滤条件优化。

10、避免隐式类型转换

场景:按字符串类型ID查询

-- ❌ 数字与字符串比较(索引失效)
SELECT * FROM devices 
WHERE device_id = 12345;              -- device_id为VARCHAR类型
-- ✅ 保持类型一致(利用索引)
SELECT * FROM devices 
WHERE device_id = '12345';            -- 字符串匹配索引

典型应用:物联网设备管理按设备ID准确查询。

11、用 CASE WHEN 替代多轮扫描

场景:我们根据不同状态统计订单数量

-- ❌ 多次全表扫描(性能低下)
SELECT COUNT(*) AS total_orders FROM orders; 
SELECT COUNT(*) AS pending_orders FROM orders WHERE status = 'pending';
SELECT COUNT(*) AS shipped_orders FROM orders WHERE status = 'shipped';
-- ✅ 单次扫描完成多维度统计
SELECT 
  COUNT(*) AS total_orders,
  SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) AS pending_orders,
  SUM(CASE WHEN status = 'shipped' THEN 1 ELSE 0 END) AS shipped_orders
FROM orders;  -- 一次扫描完成三类统计

典型应用:管理后台的订单状态统计面板。

12、分区表优化时间范围查询

场景:我们查询最近30天日志

-- ❌ 非分区表全量扫描
SELECT * FROM server_logs 
WHERE log_time BETWEEN NOW() - INTERVAL 30 DAY AND NOW(); -- 扫描全年数据
-- ✅ 按月分区表仅扫描相关分区
CREATE TABLE server_logs (
  id INT,
  log_content TEXT,
  log_time DATETIME
) PARTITION BY RANGE (TO_DAYS(log_time)) (
  PARTITION p202309 VALUES LESS THAN (TO_DAYS('2023-10-01')),
  PARTITION p202310 VALUES LESS THAN (TO_DAYS('2023-11-01'))
);
SELECT * FROM server_logs 
WHERE log_time BETWEEN NOW() - INTERVAL 30 DAY AND NOW(); -- 仅扫描最近分区

典型应用:时间序列数据(日志、监控数据)的高效查询。

13、函数索引优化JSON查询

场景:我们查询JSON字段中的特定属性

-- ❌ 无法使用常规索引
SELECT * FROM products 
WHERE JSON_EXTRACT(specs, '$.weight') > 10; -- 全表扫描
-- ✅ 创建函数索引加速查询
CREATE INDEX idx_product_weight ON products( (JSON_EXTRACT(specs, '$.weight')) );
SELECT * FROM products 
WHERE JSON_EXTRACT(specs, '$.weight') > 10; -- 使用函数索引

典型应用:电商平台查询商品规格参数。

14、游标替代方案处理逐行逻辑

场景:根据用户等级批量更新折扣

-- ❌ 游标逐行处理效率极低
DECLARE user_cursor CURSOR FOR 
SELECT id, level FROM users;
OPEN user_cursor;
FETCH NEXT FROM user_cursor...
-- ✅ 批量CASE WHEN更新
UPDATE users SET discount =
  CASE 
    WHEN level = 'VIP' THEN 0.8
    WHEN level = 'Premium' THEN 0.9
    ELSE 1.0
  END; -- 单语句完成全量更新

典型应用:会员系统批量更新权益。

15、物化视图加速复杂聚合

场景:实时显示每日销售排行榜

-- ❌ 每次查询实时聚合(10秒+)
SELECT product_id, SUM(amount) 
FROM orders 
WHERE order_date = CURDATE()
GROUP BY product_id ORDER BY SUM(amount) DESC LIMIT 10;
-- ✅ 创建物化视图定时刷新
CREATE MATERIALIZED VIEW daily_top_sales
REFRESH EVERY 5 MINUTE
AS
SELECT product_id, SUM(amount) AS total_sales
FROM orders 
WHERE order_date = CURDATE()
GROUP BY product_id;
-- 查询物化视图(0.1秒)
SELECT * FROM daily_top_sales ORDER BY total_sales DESC LIMIT 10;

典型应用:实时数据大屏的快速展示。

16、压缩归档历史数据

场景:处理千万级历史订单

-- ❌ 所有数据存在业务表(查询缓慢)
SELECT * FROM orders WHERE order_date < '2020-01-01'; -- 扫描全表
-- ✅ 分区归档历史数据
CREATE TABLE orders_archive (
  LIKE orders INCLUDING INDEXES
) COMPRESSION='ZLIB';  -- 启用压缩
INSERT INTO orders_archive 
SELECT * FROM orders WHERE order_date < '2020-01-01';
DELETE FROM orders WHERE order_date < '2020-01-01';

典型应用:金融系统历史数据存储优化。

17、避免视图嵌套导致的性能黑洞

场景:多层视图关联查询

-- ❌ 嵌套视图导致执行计划混乱
CREATE VIEW v_orders AS SELECT * FROM orders WHERE status = 'completed';
CREATE VIEW v_user_orders AS 
SELECT u.name, v.* 
FROM users u JOIN v_orders v ON u.id = v.user_id;
-- 查询性能极差
SELECT * FROM v_user_orders WHERE amount > 1000;
-- ✅ 扁平化查询结构
SELECT u.name, o.* 
FROM users u 
JOIN orders o ON u.id = o.user_id 
WHERE o.status = 'completed'
  AND o.amount > 1000; -- 直接访问基表

典型应用:报表系统避免过度抽象。

18、位图索引优化低基数字段

场景:性别、状态等枚举值查询

-- ❌ B-Tree索引效率低
CREATE INDEX idx_gender ON users(gender); -- 性别只有2个值
SELECT * FROM users WHERE gender = 'F';
-- ✅ 位图索引大幅提升性能
CREATE BITMAP INDEX idx_bm_gender ON users(gender);
SELECT * FROM users WHERE gender = 'F'; -- 位图快速定位

典型应用:数据仓库中维度字段查询。

19、避免触发器导致的隐式性能损耗

场景:订单创建时更新统计值

-- ❌ 触发器逐行更新(高并发时锁竞争)
CREATE TRIGGER update_order_count 
AFTER INSERT ON orders
FOR EACH ROW 
UPDATE user_stats SET order_count = order_count + 1 
WHERE user_id = NEW.user_id;
-- ✅ 异步批量更新
-- 使用消息队列或定时任务
INSERT INTO order_created_events (user_id) VALUES (123);
-- 每小时批量更新
UPDATE user_stats us
JOIN (
  SELECT user_id, COUNT(*) AS cnt 
  FROM order_created_events 
  GROUP BY user_id
) tmp ON us.user_id = tmp.user_id
SET us.order_count = us.order_count + tmp.cnt;

典型应用:高并发系统的计数器场景。

20、列式存储优化分析查询

场景:十亿级数据聚合分析

-- ❌ 行式存储全表扫描(5分钟+)
SELECT product_type, AVG(price), MAX(quantity)
FROM sales GROUP BY product_type;
-- ✅ 列式存储加速聚合
CREATE TABLE sales_columnar (
  sale_id INT,
  product_type VARCHAR(20),
  price DECIMAL(10,2),
  quantity INT
) ENGINE=ColumnStore;  -- 使用列式引擎
SELECT product_type, AVG(price), MAX(quantity) 
FROM sales_columnar GROUP BY product_type; -- 秒级响应

典型应用:大数据分析平台OLAP场景。

21、使用临时表分解复杂查询

场景:多层级关联的复杂报表生成

-- ❌ 单条复杂SQL难以优化(嵌套5层子查询)
SELECT 
  d.name AS dept_name,
  (SELECT COUNT(*) FROM employees e WHERE e.dept_id = d.id) AS emp_count,
  (SELECT AVG(salary) FROM salaries s WHERE s.emp_id IN 
    (SELECT id FROM employees WHERE dept_id = d.id)
  ) AS avg_salary
FROM departments d;
-- ✅ 分步使用临时表存储中间结果
CREATE TEMPORARY TABLE temp_dept_stats AS
SELECT 
  d.id AS dept_id,
  d.name AS dept_name,
  COUNT(e.id) AS emp_count
FROM departments d
LEFT JOIN employees e ON d.id = e.dept_id
GROUP BY d.id, d.name;
CREATE TEMPORARY TABLE temp_salary_stats AS
SELECT 
  e.dept_id,
  AVG(s.salary) AS avg_salary
FROM employees e
JOIN salaries s ON e.id = s.emp_id
GROUP BY e.dept_id;
-- 最终合并结果
SELECT 
  t1.dept_name,
  t1.emp_count,
  t2.avg_salary
FROM temp_dept_stats t1
JOIN temp_salary_stats t2 ON t1.dept_id = t2.dept_id;

典型应用:数据仓库中ETL过程分阶段处理。

22、利用窗口函数避免自连接

场景:我们计算每个部门内员工的工资排名

-- ❌ 自连接导致O(n²)复杂度
SELECT 
  e1.name,
  e1.department,
  COUNT(e2.id) + 1 AS rank
FROM employees e1
LEFT JOIN employees e2 
  ON e1.department = e2.department 
  AND e1.salary < e2.salary
GROUP BY e1.id; -- 性能随数据量指数级下降
-- ✅ 窗口函数线性扫描
SELECT 
  name,
  department,
  salary,
  RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank
FROM employees; -- 一次扫描完成计算

典型应用:绩效排名、Top N分析等场景。

23、索引下推优化复合条件查询

场景:联合索引条件下非索引列的过滤

-- 表结构:INDEX (age, city)
-- ❌ 旧版本MySQL可能先取行再过滤
SELECT * FROM users 
WHERE age > 20 AND city = 'Beijing' AND name LIKE '张%';
-- ✅ 支持索引下推的数据库自动优化
-- 无需改写SQL,数据库自动将`name LIKE`条件下推至存储引擎
-- 确保使用最新数据库版本(MySQL 5.6+)

典型应用:电商平台多条件筛选商品。

24、异步删除大数据量数据

场景:我们删除千万级历史数据

-- ❌ 直接删除导致长事务阻塞
DELETE FROM user_logs WHERE created_at < '2020-01-01'; -- 执行10分钟+
-- ✅ 分批次异步删除
DELIMITER $$
CREATE PROCEDURE batch_delete()
BEGIN
  DECLARE done INT DEFAULT FALSE;
  WHILE NOT done DO
    DELETE FROM user_logs 
    WHERE created_at < '2020-01-01'
    LIMIT 10000; -- 每次删1万行
    SET done = ROW_COUNT() = 0;
    COMMIT;
    DO SLEEP(1); -- 间隔1秒减少锁竞争
  END WHILE;
END$$
DELIMITER ;
CALL batch_delete();

典型应用:日志系统定期清理过期数据。

25、全文索引替代LIKE模糊查询

场景:商品标题关键字搜索

-- ❌ 通配符LIKE无法使用索引
SELECT * FROM products 
WHERE title LIKE '%智能手机%'; -- 全表扫描
-- ✅ 创建全文索引加速搜索
ALTER TABLE products ADD FULLTEXT INDEX idx_title (title);
SELECT * FROM products 
WHERE MATCH(title) AGAINST('智能手机' IN NATURAL LANGUAGE MODE);

典型应用:内容检索系统、电商搜索。

26、使用Generated Column物化计算列

场景:频繁查询JSON字段的解析值

-- ❌ 每次查询实时解析JSON
SELECT 
  id,
  JSON_EXTRACT(profile, '$.contact.phone') AS phone 
FROM users;
-- ✅ 物化列避免重复计算
ALTER TABLE users
ADD COLUMN phone VARCHAR(20) 
GENERATED ALWAYS AS (JSON_EXTRACT(profile, '$.contact.phone')) STORED;
CREATE INDEX idx_phone ON users(phone); -- 可索引
SELECT id, phone FROM users; -- 直接读取物化列

典型应用:频繁访问的JSON/XML字段提取。

27、CTE递归查询替代循环处理

场景:我们查询部门树形结构

-- ❌ 应用层循环查询(N+1问题)
SELECT * FROM departments WHERE parent_id IS NULL; -- 查顶级部门
-- 然后循环查询每个部门的子部门...
-- ✅ 递归CTE一次获取整棵树
WITH RECURSIVE dept_tree AS (
  SELECT id, name, parent_id, 1 AS level
  FROM departments 
  WHERE parent_id IS NULL
  UNION ALL
  SELECT d.id, d.name, d.parent_id, dt.level + 1
  FROM departments d
  JOIN dept_tree dt ON d.parent_id = dt.id
)
SELECT * FROM dept_tree ORDER BY level, id;

典型应用:组织架构、分类目录等树形数据查询。

28、避免HAVING子句滥用

场景:分组后筛选订单数量

-- ❌ HAVING执行在分组后,效率低
SELECT user_id, COUNT(*) AS order_count 
FROM orders 
GROUP BY user_id
HAVING COUNT(*) > 5; -- 先分组再过滤
-- ✅ WHERE在分组前过滤
SELECT user_id, COUNT(*) AS order_count 
FROM orders 
WHERE EXISTS ( -- 先过滤有效订单
    SELECT 1 FROM order_details od 
    WHERE od.order_id = orders.id AND od.status = 'valid'
)
GROUP BY user_id
HAVING COUNT(*) > 5; 

典型应用:用户行为分析中的条件过滤。

29、空间数据使用R-Tree索引

场景:我们查找附近的加油站

-- ❌ 传统索引无法加速距离计算
SELECT * FROM gas_stations 
WHERE ST_Distance(location, POINT(116.4074, 39.9042)) < 5000; -- 全表扫描
-- ✅ 空间索引加速范围查询
ALTER TABLE gas_stations ADD SPATIAL INDEX(location);
SELECT * FROM gas_stations 
WHERE MBRContains(
  ST_Buffer(POINT(116.4074, 39.9042), 5000),
  location
); -- 使用索引快速筛选候选集

典型应用:LBS应用、地理围栏。

30、使用INSERT … ON DUPLICATE KEY UPDATE避免先查后改

场景:记录用户最后登录时间

-- ❌ 先查询后更新(2次交互)
SELECT id FROM user_login WHERE user_id = 123;
-- 如果存在则UPDATE,否则INSERT
-- ✅ 原子化操作
INSERT INTO user_login (user_id, last_login, login_count) 
VALUES (123, NOW(), 1)
ON DUPLICATE KEY UPDATE 
  last_login = NOW(), 
  login_count = login_count + 1;

典型应用:计数器、状态更新等高并发场景。

31、使用Group Commit优化高并发写入

场景:物联网设备批量上报数据

-- ❌ 单条插入(每秒1000次提交)
INSERT INTO device_data (device_id, value) VALUES (1001, 23.5);
INSERT INTO device_data (device_id, value) VALUES (1002, 18.7);
...
-- ✅ 批量提交+组提交优化
INSERT INTO device_data (device_id, value) 
VALUES (1001, 23.5), (1002, 18.7), ... (10000, 19.2); -- 每批1000条
-- 数据库配置(以InnoDB为例):
SET GLOBAL innodb_flush_log_at_trx_commit = 2; -- 牺牲部分持久性换性能
SET GLOBAL sync_binlog = 0;

典型应用:物联网、日志采集等高频写入场景。

32、使用Skip Locked处理排队系统

场景:分布式任务调度

-- ❌ 悲观锁导致并发阻塞
BEGIN;
SELECT * FROM tasks 
WHERE status = 'pending'
ORDER BY priority DESC 
FOR UPDATE; -- 锁定整个结果集
UPDATE tasks SET status = 'processing' WHERE id = ?;
COMMIT;
-- ✅ 跳过已锁定记录
BEGIN;
SELECT * FROM tasks 
WHERE status = 'pending'
ORDER BY priority DESC 
FOR UPDATE SKIP LOCKED  -- 跳过被锁定的行
LIMIT 1; -- 只取一个任务
UPDATE tasks SET status = 'processing' WHERE id = ?;
COMMIT;

典型应用:高并发任务调度系统。

33、使用Partial Indexes(部分索引)优化高频查询

场景:只查询活跃用户的订单

-- ❌ 全量索引包含无效数据
CREATE INDEX idx_user_orders ON orders(user_id);
SELECT * FROM orders WHERE user_id = 100 AND status = 'active'; -- 索引包含已撤销订单
-- ✅ 创建条件索引
CREATE INDEX idx_active_user_orders ON orders(user_id) WHERE status = 'active';
SELECT * FROM orders 
WHERE user_id = 100 AND status = 'active'; -- 索引体积减少70%

典型应用:电商平台查询有效订单。

34、利用哈希索引加速等值查询

场景:内存表的主键查询

-- ❌ B-Tree索引在内存中非最优
CREATE TABLE session_data (
  session_id CHAR(32) PRIMARY KEY,
  data BLOB
) ENGINE=InnoDB; -- B-Tree索引
-- ✅ 使用哈希索引(内存表)
CREATE TABLE session_data (
  session_id CHAR(32) PRIMARY KEY,
  data BLOB
) ENGINE=MEMORY; -- 默认哈希索引
SELECT data FROM session_data WHERE session_id = 'e4d909c290d0fb1ca068ffaddf22cbd0'; -- O(1)复杂度

典型应用:会话存储、临时缓存表。

35、使用Generated Column进行数据类型转换优化

场景:字符串类型的日期范围查询

-- ❌ 字符串日期无法走索引
CREATE TABLE logs (
  id INT PRIMARY KEY,
  log_date VARCHAR(10) -- 格式'YYYY-MM-DD'
);
SELECT * FROM logs WHERE log_date BETWEEN '2023-01-01' AND '2023-01-31'; -- 全表扫描
-- ✅ 生成列转换类型
ALTER TABLE logs
ADD COLUMN log_date_real DATE 
GENERATED ALWAYS AS (STR_TO_DATE(log_date, '%Y-%m-%d')) STORED;
CREATE INDEX idx_log_date ON logs(log_date_real);
SELECT * FROM logs WHERE log_date_real BETWEEN '2023-01-01' AND '2023-01-31'; -- 日期索引

典型应用:遗留系统日期字段优化。

36、使用Pivot技术替代多重JOIN

场景:将多行属性转为列展示

-- ❌ 多重JOIN导致性能低下
SELECT 
  u.id,
  MAX(CASE WHEN a.type='email' THEN a.value END) AS email,
  MAX(CASE WHEN a.type='phone' THEN a.value END) AS phone
FROM users u
LEFT JOIN attributes a ON u.id = a.user_id
GROUP BY u.id; -- 需要分组计算
-- ✅ 使用PIVOT语法(SQL Server/Oracle)
SELECT *
FROM (
  SELECT user_id, type, value FROM attributes
) AS src
PIVOT (
  MAX(value) FOR type IN ([email], [phone])
) AS pvt; -- 直接行列转换
-- ✅ MySQL兼容方案(用CASE WHEN模拟PIVOT)
SELECT 
  user_id,
  MAX(CASE WHEN type = 'email' THEN value END) AS email,
  MAX(CASE WHEN type = 'phone' THEN value END) AS phone
FROM attributes
GROUP BY user_id;
-- 这是业界广泛采用的“模拟 PIVOT”技术,称为 Conditional Aggregation(条件聚合)

典型应用:用户属性宽表生成。

37、使用Lateral Join优化依赖子查询

场景:我们查询每个用户最近一次订单

-- ❌ 关联子查询效率低
SELECT u.id, u.name,
  (SELECT order_id FROM orders o 
   WHERE o.user_id = u.id 
   ORDER BY order_date DESC LIMIT 1) AS last_order_id
FROM users u;
-- ✅ Lateral Join(PostgreSQL/MySQL 8.0+)
SELECT u.id, u.name, o.order_id
FROM users u
LEFT JOIN LATERAL (
  SELECT order_id 
  FROM orders 
  WHERE user_id = u.id 
  ORDER BY order_date DESC 
  LIMIT 1
) o ON true;

典型应用:获取分组内Top N记录。

38、使用Bloom Filter索引加速大表JOIN

场景:十亿级用户表与百亿级行为表关联

-- ❌ 传统JOIN资源消耗巨大
SELECT u.id, COUNT(b.event_id) 
FROM users u
JOIN behavior b ON u.id = b.user_id 
WHERE u.country = 'CN'
GROUP BY u.id;
-- ✅ 使用Bloom Filter预过滤(Hive/Spark SQL)
SET hive.bloom.filter.enabled=true;
CREATE INDEX idx_user_id ON TABLE behavior (user_id) 
AS 'BLOOMFILTER' WITH DEFERRED REBUILD;
ALTER INDEX idx_user_id ON behavior REBUILD;
-- 查询时自动应用Bloom Filter

典型应用:大数据生态中的JOIN优化。

39、使用向量化执行加速分析查询

场景:十亿条记录的聚合计算

-- ❌ 传统行式处理(慢)
SELECT product_id, AVG(price), SUM(quantity)
FROM sales GROUP BY product_id;
-- ✅ 启用向量化执行(如:PostgreSQL)
SET max_worker_processes = 8;
SET enable_vectorized_engine = on; -- 开启向量化
-- 一样查询速度提升5-10倍

典型应用:数据仓库复杂分析。

40、使用表达式索引优化计算字段

场景:根据完整姓名查询

-- ❌ 无法使用索引
SELECT * FROM employees 
WHERE CONCAT(first_name, ' ', last_name) = '张三';
-- ✅ 创建表达式索引
CREATE INDEX idx_full_name ON employees ((CONCAT(first_name, ' ', last_name)));
SELECT * FROM employees 
WHERE CONCAT(first_name, ' ', last_name) = '张三'; -- 使用索引

典型应用:频繁查询的复合字段。

41、使用BRIN索引优化时序数据

场景:我们按时间范围查询传感器数据

-- ❌ 传统索引体积过大
CREATE INDEX idx_sensor_time ON sensor_data(record_time); -- 索引大小接近数据表
-- ✅ BRIN索引(Block Range Index)
CREATE INDEX idx_brin_time ON sensor_data USING BRIN(record_time); -- 索引极小
SELECT * FROM sensor_data 
WHERE record_time BETWEEN '2023-01-01' AND '2023-01-02';

典型应用:物联网时序数据查询。

42、使用多版本并发控制(MVCC)避免锁竞争

场景:高并发读写场景

-- ❌ 使用锁机制导致阻塞
BEGIN;
SELECT * FROM accounts WHERE id = 1001 FOR UPDATE; -- 行锁
UPDATE accounts SET balance = balance - 100 WHERE id = 1001;
COMMIT;
-- ✅ 基于MVCC的乐观锁
UPDATE accounts SET balance = balance - 100 
WHERE id = 1001 AND balance >= 100; -- 无锁更新,检查版本或条件

典型应用:金融系统账户更新。

43、使用列压缩减少IO开销

场景:大文本字段存储

-- ❌ 未压缩文本占用空间大
CREATE TABLE articles (
  id INT PRIMARY KEY,
  content TEXT -- 平均100KB/篇
);
-- ✅ 启用列压缩
CREATE TABLE articles (
  id INT PRIMARY KEY,
  content TEXT COMPRESSED -- 压缩至30%
);
SELECT content FROM articles WHERE id = 1001; -- 减少70%磁盘IO

典型应用:内容管理系统、日志存储。

44、使用外键索引优化级联操作

场景:删除主表记录时同步子表

-- ❌ 无索引导致级联删除全表扫描
ALTER TABLE orders 
ADD CONSTRAINT fk_user 
FOREIGN KEY (user_id) REFERENCES users(id) 
ON DELETE CASCADE; -- 删除用户时自动删订单
-- 删除用户时:先全表扫描orders找对应user_id
-- ✅ 为外键字段创建索引
CREATE INDEX idx_orders_user_id ON orders(user_id); -- 外键索引
ALTER TABLE orders ADD FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
-- 删除用户时:通过索引快速定位订单

典型应用:关系紧密的级联操作。

45、使用临时表缓存中间结果集

场景:复杂报表多次引用一样子查询

-- ❌ 重复执行一样子查询
SELECT 
  (SELECT AVG(amount) FROM orders WHERE user_id = u.id) AS avg_order,
  (SELECT MAX(amount) FROM orders WHERE user_id = u.id) AS max_order
FROM users u;
-- ✅ 临时表存储聚合结果
CREATE TEMPORARY TABLE temp_user_orders AS
SELECT user_id, AVG(amount) AS avg_order, MAX(amount) AS max_order
FROM orders GROUP BY user_id;
SELECT u.*, t.avg_order, t.max_order
FROM users u
LEFT JOIN temp_user_orders t ON u.id = t.user_id;

典型应用:数据仓库复杂报表。

46、使用异步提交提升写入吞吐

场景:日志类数据高吞吐写入

-- ❌ 同步提交限制写入速度
INSERT INTO access_log (...) VALUES (...); -- 每次提交需等待刷盘
-- ✅ 异步提交(PostgreSQL示例)
SET synchronous_commit = off; -- 异步提交
-- 批量写入日志
INSERT INTO access_log (...) VALUES (...), (...), ...;

典型应用:日志采集、监控数据写入。

47、使用连接池减少连接开销

场景:Web应用高并发访问数据库

-- ❌ 每次请求新建连接(慢)
$conn = new mysqli($host, $user, $pass, $db);
$conn->query("SELECT ...");
-- ✅ 连接池复用连接
$conn = $connection_pool->get_connection();
$conn->query("SELECT ...");
$connection_pool->release_connection($conn);

典型应用:任何Web后端服务。

48、使用预编译语句防止SQL注入+提升性能

场景:动态条件查询

-- ❌ 拼接SQL风险高且无法重用执行计划
String sql = "SELECT * FROM users WHERE name = '" + name + "'";
stmt.executeQuery(sql);
-- ✅ 预编译重用执行计划
PreparedStatement ps = conn.prepareStatement(
  "SELECT * FROM users WHERE name = ?"
);
ps.setString(1, name);
ps.executeQuery();

典型应用:所有动态SQL场景。

49、使用数据库连接代理实现读写分离

场景:读多写少业务场景

-- ❌ 所有查询到主库
$conn = connect_to_master();
$conn->query("SELECT * FROM big_table"); -- 读操作也到主库
-- ✅ 通过代理路由
$conn = connect_to_proxy();
$conn->query("UPDATE ..."); -- 写操作路由到主库
$conn->query("SELECT ..."); -- 读操作路由到从库

典型应用:电商、社交应用等读密集型系统。

50、使用SQL提示(Hint)干预执行计划

场景:优化器选择错误索引

-- ❌ 优化器误选全表扫描
SELECT * FROM orders WHERE status = 'shipped' AND amount > 1000;
-- ✅ 强制指定索引(MySQL示例)
SELECT * FROM orders FORCE INDEX (idx_status_amount)
WHERE status = 'shipped' AND amount > 1000;

典型应用:紧急性能问题处理。

51、使用物化视图日志增量刷新

场景:实时更新销售聚合数据

-- ❌ 全量刷新物化视图导致资源高峰
REFRESH MATERIALIZED VIEW daily_sales; -- 每次全量刷新10分钟
-- ✅ 使用物化视图日志增量刷新
CREATE MATERIALIZED VIEW LOG ON sales 
WITH ROWID, SEQUENCE (sale_id, sale_date, amount);
CREATE MATERIALIZED VIEW daily_sales
REFRESH FAST ON COMMIT
AS
SELECT sale_date, SUM(amount) AS total_sales
FROM sales GROUP BY sale_date;
-- 每次提交后自动增量刷新(秒级完成)

典型应用:实时业务看板数据更新。

52、使用函数索引优化JSON路径查询

场景:高效查询JSONB字段中的嵌套属性

-- ❌ 直接查询无法使用索引
SELECT * FROM products 
WHERE specs->'dimensions'->>'width' > '100'; -- 全表扫描
-- ✅ 创建函数索引
CREATE INDEX idx_product_width ON products 
((CAST(specs->'dimensions'->>'width' AS INTEGER)));
SELECT * FROM products 
WHERE CAST(specs->'dimensions'->>'width' AS INTEGER) > 100; -- 使用索引

典型应用:产品规格参数的高效检索。

53、使用分区交换实现零停机归档

场景:归档历史数据不影响在线业务

-- ❌ 直接删除历史数据导致表锁
DELETE FROM orders WHERE order_date < '2022-01-01'; -- 锁表30分钟
-- ✅ 分区交换归档
-- 创建归档表(一样结构)
CREATE TABLE orders_archive (...) PARTITION BY RANGE (order_date);
-- 交换分区
ALTER TABLE orders 
EXCHANGE PARTITION p2021 
WITH TABLE orders_archive 
WITHOUT VALIDATION; -- 瞬间完成
-- 在后台处理归档表数据

典型应用:金融系统历史数据迁移。

54、使用并行索引扫描加速大表查询

场景:十亿级用户表范围查询

-- ❌ 单线程索引扫描慢
SELECT * FROM users WHERE created_at BETWEEN '2023-01-01' AND '2023-01-31';
-- ✅ 启用并行索引扫描(PostgreSQL)
SET max_parallel_workers_per_gather = 8;
CREATE INDEX idx_users_created ON users(created_at);
-- 一样查询速度提升5倍

典型应用:大数据分析平台的时间范围查询。

55、使用连接池预处理语句

场景:高并发短查询

-- ❌ 每次执行都解析SQL
for each request:
  db.query("SELECT * FROM products WHERE id = ?", [product_id])
-- ✅ 连接池级预处理
// 初始化时准备语句
const stmt = pool.prepare("SELECT * FROM products WHERE id = ?");
// 执行时直接使用预处理句柄
stmt.execute([product_id]); -- 跳过解析和优化阶段

典型应用:微服务架构中的高频查询接口。

56、使用GIN索引加速数组查询

场景:我们查询包含特定标签的文章

-- ❌ 数组字段全扫描
SELECT * FROM articles 
WHERE tags @> ARRAY['technology']; -- 全表扫描
-- ✅ PostgreSQL:数组字段用GIN索引
CREATE INDEX idx_article_tags ON articles USING GIN (tags); -- tags为ARRAY类型
SELECT * FROM articles 
WHERE tags @> ARRAY['technology']; -- 索引加速
-- ✅ MySQL:全文索引用GIN(数组字段需用其他方案,如拆分表)
CREATE FULLTEXT INDEX idx_article_tags ON articles(tags) USING GIN; -- tags为VARCHAR类型(存储逗号分隔标签)

典型应用:内容管理系统的标签过滤。

57、使用哈希聚合替代排序聚合

场景:大数据量分组统计

-- ❌ 排序聚合内存消耗大
SELECT department, COUNT(*) 
FROM employees 
GROUP BY department; -- 使用Sort Group
-- ✅ 使用哈希聚合
SET enable_sort = off; -- 强制哈希聚合
-- 一样查询内存减少70%,速度提升2倍

典型应用:数据仓库中的大分组查询。

58、使用TTL自动过期数据

场景:自动清理验证码记录

-- ❌ 定时任务删除过期数据
DELETE FROM sms_codes 
WHERE created_at < NOW() - INTERVAL '10 minutes'; -- 每分钟执行
-- ✅ 使用TTL(Time-To-Live)
CREATE TABLE sms_codes (
  id SERIAL PRIMARY KEY,
  phone VARCHAR(20),
  code VARCHAR(6),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) WITH (ttl_expiration_expression = 'created_at + INTERVAL ''10 minutes''');
-- 数据库自动后台清理

典型应用:临时数据存储(会话、验证码)。

说明:主流数据库的TTL实现方式(如:MySQL用事件调度器、PostgreSQL用pg_cron插件)

-- ✅ MySQL方案:用事件调度器实现TTL
CREATE TABLE sms_codes (
  id INT AUTO_INCREMENT PRIMARY KEY,
  phone VARCHAR(20),
  code VARCHAR(6),
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 开启事件调度器(全局)
SET GLOBAL event_scheduler = ON;
-- 创建定时清理事件(每1分钟执行)
CREATE EVENT IF NOT EXISTS clean_expired_sms
ON SCHEDULE EVERY 1 MINUTE
DO DELETE FROM sms_codes 
WHERE created_at < NOW() - INTERVAL 10 MINUTE;
-- ✅ PostgreSQL: 使用 pg_cron
CREATE EXTENSION IF NOT EXISTS pg_cron;
SELECT cron.schedule(
'clean-sms-codes', 
'*/1 * * * *', 
  $$DELETE FROM sms_codes WHERE created_at < NOW() - INTERVAL '10 minutes'$$
);

59、使用列式索引加速聚合

场景:实时分析十亿级数据

-- ❌ 传统索引无法加速聚合
SELECT product_id, SUM(quantity) 
FROM sales 
GROUP BY product_id; -- 全表扫描
-- ✅ 使用列式索引(ClickHouse)
CREATE TABLE sales (
  product_id UInt32,
  quantity Float32
) ENGINE = AggregatingMergeTree()
ORDER BY product_id;
-- 查询速度提升100倍

典型应用:实时分析大屏数据计算。

60、使用异步物化视图

场景:跨数据中心数据聚合

-- ❌ 同步查询多个数据库
SELECT a.data FROM db1.a 
UNION ALL
SELECT b.data FROM db2.b; -- 高延迟
-- ✅ 创建异步物化视图
CREATE MATERIALIZED VIEW global_view 
AS
SELECT * FROM db1.a@link1
UNION ALL
SELECT * FROM db2.b@link2
REFRESH EVERY 5 MINUTE; -- 定期异步刷新
-- 查询本地物化视图
SELECT * FROM global_view;

典型应用:分布式系统数据聚合。

61、使用位图索引加速多值查询

场景:用户标签组合查询

-- ❌ 多列OR查询效率低
SELECT * FROM users 
WHERE tag1 = true OR tag2 = true OR tag3 = true;
-- ✅ 位图索引快速合并
CREATE BITMAP INDEX idx_tags ON users(tags);
SELECT * FROM users 
WHERE tags IN ('tag1', 'tag2', 'tag3'); -- 位图索引合并

典型应用:用户画像标签查询。

62、使用向量索引加速类似度搜索

场景:图片特征向量搜索

-- ❌ 全表扫描计算类似度
SELECT * FROM images 
ORDER BY feature_vector <-> '[0.12, 0.34, ...]' 
LIMIT 10; -- 耗时分钟级
-- ✅ 创建向量索引
CREATE INDEX idx_image_vector ON images 
USING ivfflat (feature_vector vector_cosine_ops);
-- 一样查询毫秒级响应

典型应用:AI内容检索系统。

63、使用分页游标替代OFFSET

场景:无限滚动列表

-- ❌ 深分页性能差
SELECT * FROM posts 
ORDER BY created_at DESC 
LIMIT 10 OFFSET 100000; -- 扫描100010行
-- ✅ 使用游标分页
SELECT * FROM posts 
WHERE created_at < '2023-06-01' -- 上一页最后时间
ORDER BY created_at DESC 
LIMIT 10; -- 扫描10行

典型应用:社交媒体动态流。

64、使用全局二级索引加速分库查询

场景:分库分表后非分片键查询

-- ❌ 全分片扫描
SELECT * FROM orders 
WHERE user_id = 123; -- 需查询所有分片
-- ✅ 创建全局二级索引
CREATE GLOBAL INDEX idx_user_orders ON orders(user_id);
-- 直接定位到对应分片

典型应用:分布式数据库查询优化。

65、使用列压缩存储优化IO

场景:存储大文本内容

-- ❌ 未压缩文本占用空间大
CREATE TABLE articles (
  id INT PRIMARY KEY,
  content TEXT -- 平均100KB/篇
);
-- ✅ 列压缩存储
CREATE TABLE articles (
  id INT PRIMARY KEY,
  content TEXT COMPRESSED WITH (compression_level = 7) -- LZ4压缩
);
-- 存储空间减少70%,IO性能提升

典型应用:内容管理系统、日志存储。

66、使用内存表加速临时计算

场景:复杂计算的中间结果

-- ❌ 磁盘临时表速度慢
CREATE TEMPORARY TABLE temp_results (...) ON COMMIT DROP;
-- ✅ 使用内存表
CREATE TABLE temp_results (...) ENGINE=MEMORY;
-- 中间计算速度提升10倍

典型应用:复杂报表计算的中间步骤。

67、使用表达式索引优化计算字段

场景:查询年龄范围

-- ❌ 无法使用出生日期索引
SELECT * FROM users 
WHERE EXTRACT(YEAR FROM age(birth_date)) BETWEEN 20 AND 30;
-- ✅ 创建表达式索引
CREATE INDEX idx_user_age ON users 
((EXTRACT(YEAR FROM age(birth_date))));
-- 直接使用索引查询

典型应用:用户年龄分段统计。

68、使用分区剪裁优化时间序列查询

场景:查询特定时间范围日志

-- ❌ 全分区扫描
SELECT * FROM logs 
WHERE log_time BETWEEN '2023-06-01' AND '2023-06-02';
-- ✅ 按天分区
CREATE TABLE logs (...) PARTITION BY RANGE (log_time);
-- 自动只扫描相关分区

典型应用:物联网设备数据查询。

69、使用连接复用减少连接开销

场景:微服务高频数据库访问

// ❌ 每次请求新建连接
app.get('/data', () => {
  const conn = new Connection();
  conn.query(...);
  conn.close();
});
// ✅ 连接池复用
const pool = new ConnectionPool(...);
app.get('/data', () => {
  const conn = pool.acquire();
  conn.query(...);
  pool.release(conn);
});

典型应用:云原生应用数据库访问。

70、使用数据库代理实现自动分片路由

场景:分库分表架构下的查询

-- ❌ 应用层处理分片逻辑
-- 需要计算user_id % 4确定分片
shard = user_id % 4;
conn = get_shard_connection(shard);
conn.query("SELECT ...");
-- ✅ 使用数据库代理
-- 应用直接查询代理
SELECT * FROM users WHERE user_id = 123;
-- 代理自动路由到正确分片

典型应用:超大规模系统分库分表架构。

71、冷热数据分层存储优化

场景:历史订单查询频率低

-- ❌ 所有数据存SSD,成本高昂
SELECT * FROM orders WHERE order_date > '2023-01-01'; -- 热数据
SELECT * FROM orders WHERE order_date < '2020-01-01'; -- 冷数据(占80%容量)
-- ✅ 自动分层存储
ALTER TABLE orders SET (
  storage_policy = 'HOT:30d COLD:1y ARCHIVE:5y'
);
-- 查询时自动路由到对应存储层

典型应用:电商平台订单历史查询。

72、分布式事务优化(Saga模式)

场景:跨服务订单创建

-- ❌ 分布式事务锁资源
BEGIN;
INSERT INTO orders ...; -- 服务A
UPDATE inventory ...;   -- 服务B(跨数据库)
COMMIT; -- 两阶段提交性能差
-- ✅ Saga最终一致性
1. 订单服务:INSERT INTO orders (status='pending')...
2. 库存服务:UPDATE inventory SET lock_qty = lock_qty + 1...
3. 订单服务:UPDATE orders SET status='confirmed'...
-- 失败时执行补偿操作

典型应用:微服务架构下单流程。

73、多租户索引优化

场景:SaaS系统分租户查询

-- ❌ 单索引包含所有租户
CREATE INDEX idx_tenant_data ON all_data (tenant_id, data);
-- ✅ 局部索引(PostgreSQL部分索引)
CREATE INDEX idx_tenant1_data ON all_data (data) 
WHERE tenant_id = 1; -- 每个租户独立索引

典型应用:SaaS应用多客户数据隔离。

74、HTAP混合负载隔离

场景:交易与分析同时进行

-- ❌ 分析查询阻塞交易
SELECT COUNT(*) FROM big_table; -- 全表扫描(OLAP)
INSERT INTO orders ...;         -- 被阻塞(OLTP)
-- ✅ 使用读写分离+列存副本
-- OLTP主库:行式存储处理交易
-- OLAP副本:列式存储实时同步
SET replica_query = 'columnar'; -- 分析查询自动路由到列存副本

典型应用:实时报表与交易并存系统。

75、资源组隔离关键业务

场景:保障核心交易性能

-- ❌ 报表查询耗尽资源
SELECT /*+ 复杂分析查询 */ ...; -- 占用90%CPU
-- ✅ 创建资源组
CREATE RESOURCE GROUP critical 
  CPU_RATE_LIMIT = 70; -- 核心交易组
CREATE RESOURCE GROUP report 
  CPU_RATE_LIMIT = 30; -- 报表组
ALTER USER trade_user SET RESOURCE GROUP critical;
ALTER USER report_user SET RESOURCE GROUP report;

典型应用:金融交易系统。

76、跨库查询联邦优化

场景:整合多个数据源

-- ❌ 应用层多次查询拼接
result1 = db1.query("SELECT * FROM products...")
result2 = db2.query("SELECT * FROM inventory...")
merge_results(result1, result2)
-- ✅ 使用联邦引擎
CREATE SERVER remote_db FOREIGN DATA WRAPPER mysql;
CREATE FOREIGN TABLE remote_products (...) SERVER remote_db;
SELECT local.*, remote.stock 
FROM local_products local
JOIN remote_products remote ON local.id = remote.product_id;

典型应用:数据中台跨系统查询。

77、AI预测索引

场景:预测热门商品

-- ❌ 固定索引无法适应变化
CREATE INDEX idx_popular ON products (sales_count);
-- ✅ AI自动索引管理
ALTER TABLE products 
ADD INDEX auto_idx 
USING "adaptive" 
WITH (refresh_interval = '1h'); -- 自动识别热点字段

典型应用:流量波动大的电商推荐系统。

78、向量化UDF加速计算

场景:实时风险评分计算

-- ❌ 逐行计算UDF
SELECT id, complex_risk_score(data) FROM loans; -- 单行处理
-- ✅ 向量化执行
CREATE FUNCTION vectorized_risk_score(VECTOR) 
RETURNS FLOAT AS ... LANGUAGE PL/python;
SELECT id, vectorized_risk_score(data_vector) 
FROM loans; -- 批量处理

典型应用:风控系统实时计算。

79、零拷贝数据导入

场景:每日批量数据加载

-- ❌ 传统INSERT慢
INSERT INTO target SELECT * FROM source; -- 逐行插入
-- ✅ 存储层直接挂载
ALTER TABLE target ATTACH PARTITION source 
FROM 's3://bucket/data.parquet'; -- 秒级完成

典型应用:数据仓库ETL过程。

80、区块链式数据版本

场景:审计历史追溯

-- ❌ 手动维护历史表
CREATE TABLE orders_history AS SELECT * FROM orders; -- 每日快照
-- ✅ 时态表自动版本
CREATE TABLE orders (
  id INT PRIMARY KEY,
  ... 
) WITH (SYSTEM_VERSIONING = ON); 
-- 查询历史版本
SELECT * FROM orders FOR SYSTEM_TIME AS OF '2023-01-01';

典型应用:财务系统审计追踪。

81、动态数据屏蔽与性能

场景:生产环境数据库查询需要保护用户隐私(如:PII信息),但又不希望影响分析师查询性能。

-- ❌ 应用层处理:查询完整数据后由应用程序过滤和脱敏,网络传输和数据处理开销大
SELECT user_id, name, phone_number, email FROM users WHERE region = 'North';
-- ✅ 数据库层动态数据屏蔽:在传输前完成过滤和脱敏,减少网络传输量,计算下推
CREATE VIEW vw_users_analytics AS
SELECT 
  user_id,
  name,
  -- 使用脱敏函数,仅暴露手机号后四位
  mask(phone_number, 'partial(3, "xxxx", 4)') AS phone_number,
  -- 完全屏蔽邮箱
  mask(email, 'email()') AS email
FROM users;
-- 分析师直接查询屏蔽后的视图,安全且高效
SELECT * FROM vw_users_analytics WHERE region = 'North';

典型应用:数据分析、报表系统等需要兼顾数据安全与查询性能的场景。它属于架构调整 (D) 中的安全设计,也通过计算下推实现了**查询重构 (C)**。

82、基于成本的优化器(CBO)提示

场景:极端情况下,统计信息轻微偏差或复杂连接导致优化器选择了次优的执行计划(如:错误的连接顺序或索引)。

-- ❌ 无法干预,任由优化器选择可能很慢的计划
SELECT * 
FROM large_table_a a
JOIN large_table_b b ON a.key = b.key
JOIN small_table_c c ON b.other_key = c.other_key;
-- 优化器可能错误地选择以 large_table_b 作为驱动表
-- ✅ 使用优化器提示(Hints)显式指定连接顺序或方法(语法因数据库而异)
SELECT /*+ LEADING(c b a) USE_NL(b a) */ *
FROM large_table_a a
JOIN large_table_b b ON a.key = b.key
JOIN small_table_c c ON b.other_key = c.other_key;
-- 提示优化器:从小表 c 开始,使用嵌套循环连接(NL)依次连接 b 和 a

典型应用:紧急性能问题修复、数据仓库复杂查询调优。这是对索引策略 (B) 和查询重构 (C) 的终极补充手段,属于深度干预。

83、不可变表优化

场景:日志、事件流等只追加(append-only)且永不更新的数据场景,传统表的更新、删除开销成为瓶颈。

-- ❌ 使用常规堆表,即使没有更新删除,也需要维护事务可见性信息(如:MVCC版本)
CREATE TABLE event_log (
  id BIGSERIAL PRIMARY KEY,
  event_time TIMESTAMP,
  user_id INT,
  event_data JSONB
); -- 存在行版本开销
-- ✅ 使用不可变表或追加优化表,移除不必要的更新开销
CREATE TABLE event_log (
  id BIGSERIAL PRIMARY KEY,
  event_time TIMESTAMP,
  user_id INT,
  event_data JSONB
) WITH (
  appendonly = true,    -- 只追加
  orientation = column,  -- 列式存储
  compresstype = zstd   -- 压缩
); -- 无更新/删除开销,写入速度和压缩比极高

典型应用:时序数据、日志存储、事件溯源架构。这是架构调整 (D) 中根据业务特征选择存储模型的典范,也影响了冷热分离 (D2) 策略。

83个SQL优化场景,我们就盘点到这!

是不是发现,SQL优化,远不止“加个索引”那么简单?

它更像是一个从编码习惯到架构思维的打怪升级。我们别蛮干,要巧干!先看看查询是不是没必要,再看看索引有没有用对,最后才思考是不是要动架构。这套组合拳打下来,大部分问题都能搞定。

目前,就从我们手头那个最折磨人的慢查询开始,对照着这些场景,动手试试吧!

作者丨SQL数据库

来源丨公众号:SQL语句(ID:SQLquery)

dbaplus社群欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn

© 版权声明

相关文章

1 条评论

none
暂无评论...