【发布时间】:2019-07-04 15:47:15
【问题描述】:
考虑这个 SQL 语句:
select *
from chamado.servico se
join chamado.chamado ch on ch.id_servico=se.id_servico
join chamado.statuschamado sc on sc.id_statuschamado=ch.id_statuschamado
where sc.id_statuschamado=1
;
现在考虑相应的执行计划:
现在请密切注意红框!过滤谓词 (CH.ID_STATUSCHAMADO=1)。它不在查询中,而且是最昂贵的操作。
SERVICO 表少于 200 行,STATUSCHAMADO 表少于 10 行,但CHAMADO 表多于 70000 行。
我打算只在 STATUSCHAMADO 和 SERVICO 上进行全表扫描的连接,这应该对 Oracle 施加少量开销。
我的陈述有什么问题?
更新 1
我有以下指标:
- CHAMADO.ID_CHAMADO (PK)
- CHAMADO.ID_SERVICO
- CHAMADO.ID_AREAATENDIMENTO
- SERVICO.ID_SERVICO (PK)
- AREAATENDIMENTO.ID_AREAATENDIMENTO (PK)
【问题讨论】:
-
请告诉我们您已经在这些表上创建了哪些索引。请注意,
SELECT *通常不是索引友好的东西。如果您真的不需要所有列,那么只需列出您真正需要的列。 -
此查询需要至少使用
chamado.servico(id_servico)chamado.chamado(id_servico, id_statuschamado)和chamado.statuschamado(id_statuschamado)上的索引来消除嵌套循环需要,除非 Oracle 优化器选择将嵌套循环作为(部分关闭)访问计划一个原因.. -
“过滤谓词 (CH.ID_STATUSCHAMADO=1)。它不在查询中,它是最昂贵的操作。” 很可能是一个低可能的唯一值的数量对吗?如果是这种情况,使用每个值分区可能是一个更好的选择。
-
@RaymondNijland:我按照您的建议创建了索引,总体成本确实下降到了 50%,所以这是一个改进!关于
CH.ID_STATUSCHAMADO=1,是的,该列在CHAMADO中提供了低选择性,这就是为什么我在STATUSCHAMADO中添加了一个连接,期望在那里进行全表扫描。 -
"是的,该列在 CHAMADO 中提供了低选择性,这就是为什么我向 STATUSCHAMADO 添加了一个连接,期望在那里进行全表扫描。" 也许你可以强制优化器用交付的桌子来做到这一点......
INNER JOIN (SELECT ... ) alias方法如果你在这里抓住我的观点......