这是我的查询:
select count(*)
FROM TB_E2V_DOCUMENTOS_CICLO D
WHERE (D.TIPOCLIENTE = null or null is null)
AND (D.TIPODOCUMENTOCLIENTE = null or null is null)
AND (D.NUMDOCUMENTOCLIENTE = null or null is null)
AND (D.BA = null or null is null)
AND (D.FA = null or null is null)
AND (D.NOMBRECLIENTE = null or null is null)
AND (D.NUMTELEFONO = null or null is null)
AND (D.NUMSUSCRIPCION = null or null is null)
AND (D.TIPORECIBO in ('Recibo'))
AND (D.NUMRECIBO = null or null is null)
AND (TO_DATE(D.FECHAEMISION, 'yyyy/MM/dd') BETWEEN TO_DATE('2019-5-1', 'yyyy-MM-dd') AND TO_DATE('2020-2-18', 'yyyy-MM-dd'))
AND (D.MONTORECIBO = null or null is null)
AND (D.NUMPAGINAS = 0 or 0 = 0)
AND (D.NOMBREARCHIVO = null or null is null)
AND (D.NEGOCIO = null or null is null)
AND (D.NOMBREMETADATACARGA = null or null is null)
AND (D.FECHACARGA = TO_DATE(null) or TO_DATE(null) is null);
当我对Xplain进行以下操作时:
成本很高,但是此查询使用索引。查询大约持续10秒。 如何提高查询性能?
我正在使用Oracle 12c
答案 0 :(得分:0)
注意:所有“ and(= null或null为null)”谓词将始终为true; Oracle没有定义空值,因此空值不等于空值,因此,如果要检查空值,请使用“是空值”
select * from dual where null = null; -- returns no rows
select * from dual where not (null <> null); -- returns no rows
select * from dual where null is null; -- returns 1 row
select * from dual where not(null is not null); -- returns 1 row
就索引而言,您需要一个选择性索引(即返回更少的行)并且该索引存在于where子句谓词中。在这种情况下,它看起来像是TO_DATE(D.FECHAEMISION,'yyyy / MM / dd')上基于函数的索引 与D.TIPORECIBO一起准备好了。在这种情况下使用INDEX SKIP SCAN可能是因为D.TIPORECIBO不在最前面。索引跳过扫描比索引范围扫描慢,因为它需要读取更多的索引块。
答案 1 :(得分:0)
这里涉及一些因素:
首先,此查询使用的是复合索引的第二(或第三)部分,结果为SKIP SCAN
。
查看表上的所有索引,看看TIPORECIBO
上的索引类型。
这可能不是领先的专栏。您可以通过创建以TIPORECIBO
作为前导列的索引来提高性能,但这不太可能-这似乎是“类型”列,可能只有几个值,并且不是索引的理想选择
第二个问题是Oracle使用索引获取一组候选行,然后转到数据块本身以获取行以进行进一步过滤。
如果Oracle不需要获取数据块,则select count(*)
的性能会更好。这可以通过创建一个包含过滤器所需的所有数据的索引来实现。
在您的情况下,TIPORECIBO
和FECHAEMISION
上的索引意味着Oracle可以单独访问该索引,而无需访问数据块。
第三个问题是您正在将TO_DATE
应用于FECHAEMISION
列。如果这是DATE
数据类型,则不需要转换,这会给您带来麻烦。如果您确实需要转换,则可以选择在TO_DATE(D.FECHAEMISION, 'yyyy/MM/dd')
上使用基于函数的索引。
要调整此特定查询,您可以尝试基于函数的复合索引:
CREATE INDEX TB_E2V_DOCUMENTOS_CICLO_FX1 ON TB_E2V_DOCUMENTOS_CICLO(FECHAEMISION, TO_DATE(D.FECHAEMISION, 'yyyy/MM/dd'))
最后,该查询显然是从代码生成的:
当前端通过AND (D.BA = null or null is null)
时,像WHERE
这样的行似乎是排除NULL
子句部分的一种方式。如果为该参数提供了值,则可能为AND (D.BA = 'X' or 'X' is null)
。
因此,在调整当前参数集时要小心,因为生成此查询的内容的任何更改都会影响调整的有效性。
如果您有一种方法可以影响此查询的生成方式,则最好在未提供值时排除那些非事件过滤器,尽管Oracle应该能够按原样处理它们。