1. 问题背景与SQL性能瓶颈分析
最近在数据库巡检过程中,我发现一个SQL语句长期占据TOP SQL CPU和TOP SQL LOGICAL READ排行榜首位。通过sql10.sql脚本收集性能数据后,确认这是一个典型的标量子查询性能问题。由于该SQL是核心业务的关键查询,执行频率极高,导致逻辑读飙升,CPU使用率也随之攀升。
让我们先看看这个"问题SQL"的真面目:
sql复制SELECT CUSTOMER_NAME 客户姓名,
DEPT_CODE 部门编码,
WORKSTATION_NO 工位号,
ORDER_SERIAL 订单流水号,
ORDER_ID 订单ID,
ORDER_NO 订单号,
PRODUCT_NAME 产品名称,
PRODUCT_NAME 商品名称,
PRODUCT_CODE 商品编码,
PRODUCT_SPEC 规格,
UNIT_NAME 单位,
ORDER_DATE 下单时间,
a.QUANTITY 数量,
(SELECT count(*)
FROM ORDER_EXECUTION@DB_LINK c
WHERE c.ORDER_NO=A.ORDER_NO
AND c.DELETE_FLAG='0') 完成数,
a.QUANTITY -
(SELECT count(*)
FROM ORDER_EXECUTION@DB_LINK c
WHERE c.ORDER_NO=A.ORDER_NO
AND c.DELETE_FLAG='0') 剩余数
FROM ORDER_DETAIL A
WHERE A.ORDER_NO NOT IN
(SELECT B.ORDER_NO
FROM
(SELECT count(*) 完成数,
c.ORDER_NO
FROM ORDER_EXECUTION@DB_LINK c
WHERE c.DELETE_FLAG='0'
GROUP BY c.ORDER_NO) B
WHERE b.完成数=A.QUANTITY
AND B.ORDER_NO=a.ORDER_NO);
1.1 业务需求解析
这个查询涉及两个主要表:
- 主表ORDER_DETAIL:存储订单基本信息
- 关联表ORDER_EXECUTION@DB_LINK:通过数据库链接访问的订单执行记录表
业务需求包括:
- 显示订单基本信息(客户、部门、工位、商品等)
- 统计每个订单的完成数量和剩余数量
- 只显示未完全执行的订单(完成数 < 订单数量)
1.2 性能问题诊断
这个SQL存在三个严重问题:
-
标量子查询的逐行执行:主查询返回的每一行都会触发子查询执行。假设主查询返回1000行,子查询将执行2000次(完成数和剩余数各计算一次)
-
重复计算:完成数被计算两次,违反了DRY原则
-
复杂的NOT IN子查询:
