【发布时间】:2019-12-15 09:34:40
【问题描述】:
我在 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 子句包含一个选择(通常只有几条记录)时,我能否以某种方式让引擎选择索引计划?
【问题讨论】:
-
问题是Firebird的优化器不区分相关子查询和非相关子查询,所以更新表驱动查询,每行执行子查询。使用
merge可能会更快,我会看看我是否可以在有时间的时候写一个答案,或者找到一个替代选项(合并可能有点冗长)。 -
@MarkRotteveel 您的意思是优化器将“in”转换为“exists”?或者我无法想象如何为要更新的表的“每一行”重新执行子查询。 FB3 的高级计划选项可能会以某种方式告诉优化查询在执行之前“看起来像”什么......我知道,它是 BLR,然后不再是 SQL,但仍然。
-
@Arioch'The 不,据我了解,它将评估表中每一行的条件,并且作为评估的一部分,它将为每一行执行子查询。该行为等同于存在,但它不会将其“转换”为存在。
-
@MarkRotteveel 如果为真,如果“in”查询的结果没有被缓存,但是在每一行上,整个集合都被重新评估为一个整体(而不是检查那一行- 有效地转换为“存在”) - 那么这是最低效的方法,选择两种方法中最糟糕的一面。
标签: sql query-optimization firebird sql-execution-plan firebird-3.0