左外部联接上的Oracle索引

左外部联接上的Oracle索引,oracle,optimization,oracle10g,oracle11g,Oracle,Optimization,Oracle10g,Oracle11g,因此,我在Oracle 11Gr2中正确/任意使用索引时遇到了一些问题,我正试图更好地理解我的解释计划如何与我的查询联系起来,以便能够正确地应用索引。运行以下查询时: SELECT JLOG1.JLOG_KEY, JLOG1.SRC_CD, JLOG1.JRNL_AMT, CASD.CONT_NO, SUM (NVL (VJLOG.TDTL_AMT, 0)) TDTL_SUM FROM

因此,我在Oracle 11Gr2中正确/任意使用索引时遇到了一些问题,我正试图更好地理解我的解释计划如何与我的查询联系起来,以便能够正确地应用索引。运行以下查询时:

 SELECT JLOG1.JLOG_KEY,
            JLOG1.SRC_CD,
            JLOG1.JRNL_AMT,
            CASD.CONT_NO,
            SUM (NVL (VJLOG.TDTL_AMT, 0)) TDTL_SUM
       FROM GL_Journal_Logs JLOG1,
            GL_JLOG_Details VJLOG,
            CASE_DATA CASD
      WHERE  VJLOG.JLOG_KEY(+) = JLOG1.JLOG_KEY
            AND CASD.CASE_KEY(+) = JLOG1.CASE_KEY
            AND JLOG1.JRNL_CD = '0'
            AND JLOG1.SRC_CD = '2'
            AND JLOG1.ACCT_IF_CD = '0'
   GROUP BY JLOG1.JLOG_KEY, JLOG1.SRC_CD,JLOG1.JRNL_AMT, CASD.CONT_NO
    HAVING JLOG1.JRNL_AMT <> SUM (NVL (VJLOG.TDTL_AMT, 0));
选择JLOG1.JLOG_键,
JLOG1.SRC_光盘,
JLOG1.JRNL_金额,
CASD.CONT_编号,
总和(NVL(VJLOG.TDTL_金额,0))TDTL_总和
从总账日志JLOG1,
GL_JLOG_详细信息VJLOG,
案例数据CASD
其中VJLOG.JLOG_键(+)=JLOG1.JLOG_键
和CASD.CASE_键(+)=JLOG1.CASE_键
和JLOG1.JRNL_CD='0'
和JLOG1.SRC_CD='2'
和JLOG1.ACCT_如果_CD='0'
按JLOG1.JLOG_键、JLOG1.SRC_CD、JLOG1.JRNL_金额、CASD.CONT_编号分组
拥有JLOG1.JRNL_金额总和(NVL(VJLOG.TDTL_金额,0));
我得到了以下解释细节:

我可以理解,我的连接“键”(JLOG_键或CASE_键)上的索引不一定适用,因为它是一个外部连接(或者应该是吗?),但是,当在JLOG1(JRNL_CD、SRC_CD、ACCT_IF_CD)上创建索引时,在技术上考虑到我的“where”子句,这些索引会生效吗


在这种情况下,我应该创建任何索引吗?还是有更好的方法

根据谓词中列的基数,可以在GL_JLOG_DETAILS表上使用适当的索引,以避免对表进行完整扫描。覆盖索引可能完全避免访问数据页:

ON GL_JOURNAL_LOGS (JRNL_CD,SRC_CD,ACCT_IF_CD,JLOG_KEY,CASE_KEY,JRNL_AMT)
(您可能希望在该索引中首先使用具有最具选择性谓词的列)

此外,您的查询还可以有效地利用索引

ON GL_JLOG_DETAILS (JLOG_KEY, TDTL_AMT) 

此外,请确保表和索引的统计信息是最新的


此外,外部联接的(+)符号可能会限制优化器。
Oracle现在支持ANSI样式的联接,这可能允许优化器在制定执行计划时有更多的自由度,例如

  FROM GL_Journal_Logs JLOG1
  LEFT
  JOIN GL_JLOG_Details VJLOG ON VJLOG.JLOG_KEY = JLOG1.JLOG_KEY
  LEFT
  JOIN CASE_DATA CASD ON CASD.CASE_KEY = JLOG1.CASE_KEY
 WHERE JLOG1.JRNL_CD = '0'
       AND JLOG1.SRC_CD = '2'
       AND JLOG1.ACCT_IF_CD = '0'

我想这只会影响
6
(相对较小)的速度;在那里,WHERE向下推,(中间)结果集是相同的。。但数据库变化无常,令人惊叹。TIAS?:)但是,通常,所有连接键都应该是索引<代码>外部与
内部
的不同之处在于,连接后的一侧(或另一侧)可能存在空填充值。索引仍然可以用于“匹配”记录(以及标识丢失的记录)。再说一次,TIA,但是散列连接意味着Oracle已经在使用索引了?非常感谢您的输入。上面提到的GL_日志索引的添加似乎有了一些改进。至于GL_LOG_详细信息,因为我使用的是TDTL_金额周围的函数,所以我应该创建基于函数的索引作为该索引的一部分,还是仅基于该值创建基于函数的索引?我了解到,只要您对其中一个值(例如NVL(val,0))使用函数,索引就不存在了。。在这种情况下,最佳做法是什么。一个简单的索引重建会做同样的事情吗,或者我应该在每次对受影响的表运行此操作之前收集表的统计数据吗?@denisb:你所读的是正确的。围绕该列的NVL函数(在查询中)禁止对该列执行“索引查找”操作。但对你来说,这并不重要。您仅在SELECT列表和HAVING子句中引用该表达式,因此这是一个没有意义的问题。您希望
JLOG_KEY
作为索引中的前导列,因为它在连接谓词中被引用。在同一指数中也包括
TDTL\U金额
,目的是使其成为“覆盖”指数。。。仅从索引即可满足查询,而无需引用任何数据页。@denisb:您可以尝试在GL_JLOG_详细信息(JLOG_键,NVL(TDTL_金额,0))上添加索引
。(但在您的查询中,它仍然只是jLogyKy中的谓词,是SGARABLE)。但是在您这样做之前,我建议您考虑重写查询,以便将NVL函数移到和函数之外。我相信在你的例子中,
NVL(SUM(TDTL\u AMT),0)
相当于
SUM(NVL(TDTL\u AMT,0))
,即使没有匹配的行,它们也返回相同的值。这将绕过需要对每个值运行
NVL
,并在总和中包含零。(总和聚合已经在检查NULL。)+1用于推荐ANSI语法,这通常更清晰。但是,ANSI联接对优化器没有帮助,因为Oracle仍然会将所有查询转换为旧语法:
  FROM GL_Journal_Logs JLOG1
  LEFT
  JOIN GL_JLOG_Details VJLOG ON VJLOG.JLOG_KEY = JLOG1.JLOG_KEY
  LEFT
  JOIN CASE_DATA CASD ON CASD.CASE_KEY = JLOG1.CASE_KEY
 WHERE JLOG1.JRNL_CD = '0'
       AND JLOG1.SRC_CD = '2'
       AND JLOG1.ACCT_IF_CD = '0'