昨天,有一位美女提出瞭如下需求,週末沒事,在家裏好好查了一下。
1 需求分析
有三張表,商品表(TBLITEM),庫存表(TBLSTORAGE),庫存管理表(TBLMANAGEMENT);
每一種商品對應的處理區分是0,並且庫存總量大於1000,就把庫存管理表的庫存區分更新爲1,小於1000,更新爲0。
2 數據準備
DROP TABLE TBLITEM;
DROP TABLE TBLSTORAGE;
DROP TABLE TBLMANAGEMENT;
create table TBLITEM as select d.OWNER as ITEMNO,round(dbms_random.value) as HANDLE_FLG from dba_objects d WHERE d.owner<>'sys';
create table TBLSTORAGE as select d.OWNER as ITEMNO,trunc(dbms_random.value(0,100)) as STROR_AMOUNT from dba_objects d WHERE d.owner<>'sys' ;
create table TBLMANAGEMENT as select d.OWNER as ITEMNO,round(dbms_random.value) as STORE_KIND from dba_objects d WHERE d.owner<>'sys' ;
3 SQL改善
3.1 寫法一
UPDATE TBLMANAGEMENT M
SET M.STORE_KIND=(SELECT CASE WHEN SUM(S.STROR_AMOUNT)>1000 THEN 1
ELSE 0 END
FROM TBLITEM I
INNER JOIN TBLSTORAGE S
ON I.ITEMNO=S.ITEMNO
WHERE I.HANDLE_FLG=0
AND M.ITEMNO=I.ITEMNO
AND M.ITEMNO=S.ITEMNO
GROUP BY S.ITEMNO)
WHERE EXISTS (SELECT 1
FROM TBLITEM I
INNER JOIN TBLSTORAGE S
ON I.ITEMNO=S.ITEMNO
WHERE I.HANDLE_FLG=0
AND M.ITEMNO=I.ITEMNO
AND M.ITEMNO=S.ITEMNO);
這種寫法能夠實現需求,但是作爲資深的老牌強迫症患者,一條SQL語句中重複掃描一張表是不能忍受的,所以有了下面異想天開的寫法。
3.2寫法二(錯誤)
WITH TMP AS
(SELECT S.ITEMNO, (CASE WHEN SUM(S.STROR_AMOUNT)>1000 THEN 1
ELSE 0 END) AS AMOUTFLG
FROM TBLITEM I
INNER JOIN TBLSTORAGE S
ON I.ITEMNO=S.ITEMNO
WHERE I.HANDLE_FLG=0
GROUP BY S.ITEMNO)
UPDATE TBLMANAGEMENT M
SET M.STORE_KIND=(SELECT T.AMOUTFLG
FROM TMP T
WHERE T.ITEMNO=M.ITEMNO)
WHERE EXISTS(SELECT 1
FROM TMP T
WHERE T.ITEMNO=M.ITEMNO);
這條語句直接有語法錯誤,如果是檢索處理,用with提取公共部分,還可以,但是是更新操作,無法實現。
3.3 Merge優化
MERGE INTO TBLMANAGEMENT M
USING (SELECT S.ITEMNO, (CASE WHEN SUM(S.STROR_AMOUNT)>1000 THEN 1
ELSE 0 END) AS AMOUNT_FLG
FROM TBLITEM I
INNER JOIN TBLSTORAGE S
ON I.ITEMNO=S.ITEMNO
WHERE I.HANDLE_FLG=0
GROUP BY S.ITEMNO) T
ON (M.ITEMNO=T.ITEMNO)
WHEN MATCHED THEN UPDATE SET M.STORE_KIND=T.AMOUNT_FLG;
用merge改寫,避免了表的重複的掃描,物理讀有181k降低到75多。IO減少一半。