[英]Query optimization with in (select …) clause
我在Windows上使用Firebird WI-V3.0.4.33054。
我在優化此查詢時遇到問題,該查詢使用帶有select的in子句:
update CADPC p set p.STA = 'L'
where p.COD in (select distinct CODPC from CADPCI_Rec where IDNfr = 27)
and not exists (select * from CADPCI where CODPC = p.COD)
此查詢的計划是(並且明顯的問題是P NATURAL
部分):
PLAN SORT (CADPCI_REC INDEX (PK_CADPCI_REC))
PLAN (CADPCI INDEX (FK_CADPCI_CODPC))
PLAN (P NATURAL)
Select Expression
-> Filter
-> Unique Sort (record length: 36, key length: 8)
-> Filter
-> Table "CADPCI_REC" Access By ID
-> Bitmap
-> Index "PK_CADPCI_REC" Range Scan (partial match: 1/3)
Select Expression
-> Filter
-> Table "CADPCI" Access By ID
-> Bitmap
-> Index "FK_CADPCI_CODPC" Range Scan (full match)
Select Expression
-> Filter
-> Table "CADPC" as "P" Full Scan
另一方面,如果我手動運行select distinct
,則復制結果並粘貼到查詢中,如下所示:
update CADPC p set p.STA = 'L'
where p.COD in (5699, 5877, 5985)
and not exists (select * from CADPCI where CODPC = p.COD)
現在,優化器為P表選擇合理的計划,查詢運行得非常快:
PLAN (CADPCI INDEX (FK_CADPCI_CODPC))
PLAN (P INDEX (PK_CADPC, PK_CADPC, PK_CADPC))
Select Expression
-> Filter
-> Table "CADPCI" Access By ID
-> Bitmap
-> Index "FK_CADPCI_CODPC" Range Scan (full match)
Select Expression
-> Filter
-> Table "CADPC" as "P" Access By ID
-> Bitmap Or
-> Bitmap Or
-> Bitmap
-> Index "PK_CADPC" Unique Scan
-> Bitmap
-> Index "PK_CADPC" Unique Scan
-> Bitmap
-> Index "PK_CADPC" Unique Scan
我也試過在兩種情況下都存在,但結果是一樣的:每個行重新評估子查詢。
update CADPC p set p.STA = 'L'
where exists (select * from CADPCI_Rec where IDNfr = 27 and CODPC = p.COD)
and not exists (select * from CADPCI where CODPC = p.COD)
計划:
PLAN (CADPCI_REC INDEX (PK_CADPCI_REC))
PLAN (CADPCI INDEX (FK_CADPCI_CODPC))
PLAN (P NATURAL)
Select Expression
-> Filter
-> Table "CADPCI_REC" Access By ID
-> Bitmap
-> Index "PK_CADPCI_REC" Range Scan (partial match: 1/3)
Select Expression
-> Filter
-> Table "CADPCI" Access By ID
-> Bitmap
-> Index "FK_CADPCI_CODPC" Range Scan (full match)
Select Expression
-> Filter
-> Table "CADPC" as "P" Full Scan
所以,問題是:當in子句包含一個select(通常只有幾個記錄)時,我能以某種方式讓引擎選擇索引計划嗎?
嘗試使用exists
for both:
update CADPC p
set p.STA = 'L'
where exists (select 1 from CADPCI_Rec where r.IDNfr = 27 and p.COD = r.CODPC) and
not exists (select 1 from CADPCI c2 where c2.CODPC = p.COD);
特別是,您需要CADPCI_Rec(CODPC, IDNfr)
的索引。
你可以試試EXECUTE BLOCK
和“反轉控制”
基本上發布匿名ad hoc存儲過程
EXECUTE BLOCK AS
declare id INTEGER;
BEGIN
for select distinct t1.CODPC from CADPCI_Rec t1
left join CADPCI t2 on where t2.CODPC = t1.CODPC
where t2.CODPC is NULL and t1.IDNfr = 27
into :id
do
update CADPC p set p.STA = 'L' where p.COD = :ID and p.STA <> 'L';
END
您也可以使用全球臨時表(GTT)
然后在實際刪除之前創建ID列表。
數據庫准備(創建無體表):
CREATE GLOBAL TEMPORARY TABLE CADPC_mark_IDs
( ID integer )
ON COMMIT DELETE ROWS
然后命令就像
insert into CADPC_mark_IDs(ID)
select distinct t1.CODPC from CADPCI_Rec t1
left join CADPCI t2 on where t2.CODPC = t1.CODPC
where t2.CODPC is NULL and t1.IDNfr = 27
然后
update CADPC p set p.STA = 'L'
where p.COD in (select * from CADPC_mark_IDs) and p.STA <> 'L'
然后
commit; -- clear the in-memory table for next uses
像Mark建議的那樣,在你將“不存在的地方”轉換成“左連接”(已經在上面完成,希望是正確的)后,將使用MERGE
。
一切順利
merge into CADPC p
using (
select distinct t1.CODPC as id from CADPCI_Rec t1
left join CADPCI t2 on where t2.CODPC = t1.CODPC
where t2.CODPC is NULL and t1.IDNfr = 27
) t
on (t.id = p.COD) and (p.STA <> 'L')
when matched then update set p.STA = 'L'
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.