Sql 多连接的慢速查询

Sql 多连接的慢速查询,sql,oracle,oracle10g,Sql,Oracle,Oracle10g,我有下面的查询,我正在尝试优化,如果我从下面的查询中删除缺少的图片中的select DISTINCEDENT_id中的连接条件I.ident_id,查询将在3秒钟内运行,但执行此查询需要3分钟 SELECT IDENT_ID FROM tbl_IDENT I JOIN tbl_TA AN ON (AN.IDENT_ID = I.IDENT_ID and AN.anchor_point = I.c_id) JOIN tbl_AB A ON (A

我有下面的查询,我正在尝试优化,如果我从下面的查询中删除缺少的图片中的select DISTINCEDENT_id中的连接条件I.ident_id,查询将在3秒钟内运行,但执行此查询需要3分钟

SELECT IDENT_ID
   FROM tbl_IDENT I
            JOIN tbl_TA AN ON (AN.IDENT_ID = I.IDENT_ID and AN.anchor_point = I.c_id)
            JOIN tbl_AB A ON (A.A_ID = I.A_ID)
            JOIN tbl_FULL_ARCHIVE FT ON (FT.ARCHIVE_ID = I.ARCHIVE_ID)
            WHERE (I.DATA_STATUS = 'ACTIVE' or I.DATA_STATUS = 'INACTIVE')
            AND 
            (
             I.FD = 'Y'
                OR


 I.ident_id in (select distinct(ident_id) from MISSING_Images miss where substr(miss.NAME, 0, INSTR(miss.NAME, '.',-1,1)) in (SELECT substr(IMG_NAME, 0, INSTR(IMG_NAME, '.',-1,1)) FROM IMAGES ))
)

从丢失的图像中选择Distincedent_id miss return 2000记录,主tbl_id有超过100000条记录。我已经在I.ident_id上创建了索引


任何关于如何改进它的提示。我正在使用oracle 10g。

首先,尝试使用联合

SELECT IDENT_ID
FROM tbl_IDENT I
    JOIN tbl_TA AN ON AN.IDENT_ID = I.IDENT_ID AND AN.anchor_point = I.c_id
    JOIN tbl_AB A ON A.A_ID = I.A_ID
    JOIN tbl_FULL_ARCHIVE FT ON FT.ARCHIVE_ID = I.ARCHIVE_ID
WHERE 
    (I.DATA_STATUS = 'ACTIVE' OR I.DATA_STATUS = 'INACTIVE')
AND I.FD = 'Y'
UNION
SELECT IDENT_ID
FROM tbl_IDENT I
    JOIN tbl_TA AN ON AN.IDENT_ID = I.IDENT_ID AND AN.anchor_point = I.c_id
    JOIN tbl_AB A ON A.A_ID = I.A_ID
    JOIN tbl_FULL_ARCHIVE FT ON FT.ARCHIVE_ID = I.ARCHIVE_ID
    JOIN MISSING_Images miss ON I.ident_id = miss.ident_id
WHERE 
    I.DATA_STATUS = 'ACTIVE' 
OR I.DATA_STATUS = 'INACTIVE'
;

当然可以提供更多的改进,但为此我需要一个查询的解释计划…

首先尝试一个联合

SELECT IDENT_ID
FROM tbl_IDENT I
    JOIN tbl_TA AN ON AN.IDENT_ID = I.IDENT_ID AND AN.anchor_point = I.c_id
    JOIN tbl_AB A ON A.A_ID = I.A_ID
    JOIN tbl_FULL_ARCHIVE FT ON FT.ARCHIVE_ID = I.ARCHIVE_ID
WHERE 
    (I.DATA_STATUS = 'ACTIVE' OR I.DATA_STATUS = 'INACTIVE')
AND I.FD = 'Y'
UNION
SELECT IDENT_ID
FROM tbl_IDENT I
    JOIN tbl_TA AN ON AN.IDENT_ID = I.IDENT_ID AND AN.anchor_point = I.c_id
    JOIN tbl_AB A ON A.A_ID = I.A_ID
    JOIN tbl_FULL_ARCHIVE FT ON FT.ARCHIVE_ID = I.ARCHIVE_ID
    JOIN MISSING_Images miss ON I.ident_id = miss.ident_id
WHERE 
    I.DATA_STATUS = 'ACTIVE' 
OR I.DATA_STATUS = 'INACTIVE'
;

当然可以提供更多的改进,但为此我需要一个查询的解释计划…

您可以尝试替换

I.ident_id in (select distinct(ident_id) from MISSING_Images miss)

并在缺少的图像上创建索引。ident\u id

编辑:最直接的解决方案是:

EXISTS (select 1 from MISSING_Images miss 
        where miss.ident_id = I.ident_id
          and exists (select 1 from images img 
                      where substr(img.IMG_NAME, 0, INSTR(img.IMG_NAME, '.',-1,1))
                            = substr(miss,NAME, 0, INSTR(IMG_NAME, '.',-1,1))
                     )
        )
并创建基于索引的索引:

create index indx_name1 on images(substr(IMG_NAME, 0, INSTR(IMG_NAME, '.',-1,1))); 
create index indx_name2 on MISSING_Images(substr(miss.NAME, 0, INSTR(miss.NAME, '.',-1,1))); 
请注意,此类索引可能会对不存在的对象上的插入/更新操作产生不良影响,并需要一些额外的空间。除此之外,它们不能很好地处理null

其他选择:

EXISTS (select 1 from MISSING_Images miss join images img 
                        on substr(img.IMG_NAME, 0, INSTR(img.IMG_NAME, '.',-1,1))
                            = substr(miss,NAME, 0, INSTR(IMG_NAME, '.',-1,1))
        where miss.ident_id = I.ident_id
       )


EXISTS (select 1 from (select miss.ident_id MISSING_Images miss join images img 
                        on substr(img.IMG_NAME, 0, INSTR(img.IMG_NAME, '.',-1,1))
                            = substr(miss,NAME, 0, INSTR(IMG_NAME, '.',-1,1))
                       ) sub        
        where sub.ident_id = I.ident_id
       )

你可以试着替换

I.ident_id in (select distinct(ident_id) from MISSING_Images miss)

并在缺少的图像上创建索引。ident\u id

编辑:最直接的解决方案是:

EXISTS (select 1 from MISSING_Images miss 
        where miss.ident_id = I.ident_id
          and exists (select 1 from images img 
                      where substr(img.IMG_NAME, 0, INSTR(img.IMG_NAME, '.',-1,1))
                            = substr(miss,NAME, 0, INSTR(IMG_NAME, '.',-1,1))
                     )
        )
并创建基于索引的索引:

create index indx_name1 on images(substr(IMG_NAME, 0, INSTR(IMG_NAME, '.',-1,1))); 
create index indx_name2 on MISSING_Images(substr(miss.NAME, 0, INSTR(miss.NAME, '.',-1,1))); 
请注意,此类索引可能会对不存在的对象上的插入/更新操作产生不良影响,并需要一些额外的空间。除此之外,它们不能很好地处理null

其他选择:

EXISTS (select 1 from MISSING_Images miss join images img 
                        on substr(img.IMG_NAME, 0, INSTR(img.IMG_NAME, '.',-1,1))
                            = substr(miss,NAME, 0, INSTR(IMG_NAME, '.',-1,1))
        where miss.ident_id = I.ident_id
       )


EXISTS (select 1 from (select miss.ident_id MISSING_Images miss join images img 
                        on substr(img.IMG_NAME, 0, INSTR(img.IMG_NAME, '.',-1,1))
                            = substr(miss,NAME, 0, INSTR(IMG_NAME, '.',-1,1))
                       ) sub        
        where sub.ident_id = I.ident_id
       )
在缺少的\u Imagesident\u id上创建索引

我还建议您将where条款写为:

        WHERE I.DATA_STATUS IN ('ACTIVE', 'INACTIVE') AND
              (I.FD = 'Y' OR
               I.ident_id in (select ident_id from MISSING_Images miss)
              )
在in子查询中不需要distinct。此外,in更易于读写和维护,然后是一个单独比较的列表。索引应考虑性能。

针对缺少的\u Imagesident\u id创建索引

我还建议您将where条款写为:

        WHERE I.DATA_STATUS IN ('ACTIVE', 'INACTIVE') AND
              (I.FD = 'Y' OR
               I.ident_id in (select ident_id from MISSING_Images miss)
              )

在in子查询中不需要distinct。此外,in更易于读写和维护,然后是一个单独比较的列表。索引应该考虑性能。

您甚至可以在连接条件中组合where筛选器 如下

SELECT IDENT_ID
   FROM tbl_IDENT I
            JOIN tbl_TA AN ON (AN.IDENT_ID = I.IDENT_ID and AN.anchor_point = I.c_id)
            and I.DATA_STATUS IN ('ACTIVE', 'INACTIVE') AND
            I.FD = 'Y'
                OR
             I.ident_id in (select distinct(ident_id) from MISSING_Images miss)
            JOIN tbl_AB A ON (A.A_ID = I.A_ID)
            JOIN tbl_FULL_ARCHIVE FT ON (FT.ARCHIVE_ID = I.ARCHIVE_ID);

甚至可以使用exists子句,正如@Multisync所说的,这可能会导致更好的性能。

您甚至可以在连接条件中组合where过滤器 如下

SELECT IDENT_ID
   FROM tbl_IDENT I
            JOIN tbl_TA AN ON (AN.IDENT_ID = I.IDENT_ID and AN.anchor_point = I.c_id)
            and I.DATA_STATUS IN ('ACTIVE', 'INACTIVE') AND
            I.FD = 'Y'
                OR
             I.ident_id in (select distinct(ident_id) from MISSING_Images miss)
            JOIN tbl_AB A ON (A.A_ID = I.A_ID)
            JOIN tbl_FULL_ARCHIVE FT ON (FT.ARCHIVE_ID = I.ARCHIVE_ID);

甚至您也可以使用exists子句,正如@Multisync所说的,这可能会导致更好的性能。

我在DB2上看到一些基准测试,其中exists的性能优于in,因此我对Oracle上的情况也不会感到惊讶。也就是说,如果你没有关于MISSING_Images.ident_id的索引,那么创建该索引将有更大的改进。嗨,Mike,使用MISSING_Images.ident_id索引时,情况有所改善,但我更新了问题,因为我忘记在MISSING_Images中添加where子句,该子句使用substr,这似乎是一个实际问题。@atif您有多少图像?是否有可能将外键存储在MISSING_IMAGES中的图像上,而不是解析和比较名称?外键不可能,因为用户将它们上载到IMAGES表中,我们将它们重新处理到jpgs MISSING_IMAGES中,因此两个表中的扩展不同,这就是为什么我们通过名称检查它,而不使用图像扩展。大约有10000张图片。@atif我已经更新了我的答案。基于函数的索引是最明显的解决方案,但不一定是最好的。Insert/update可能有点慢,但它通常在实时系统中有很多Insert更新。我在DB2上见过一些基准测试,其中EXISTS的性能比in好,所以我对Oracle上的情况也不会感到惊讶。也就是说,如果你没有关于MISSING_Images.ident_id的索引,那么创建该索引将有更大的改进。嗨,Mike,使用MISSING_Images.ident_id索引时,情况有所改善,但我更新了问题,因为我忘记在MISSING_Images中添加where子句,该子句使用substr,这似乎是一个实际问题。@atif您有多少图像?是否有可能将外键存储在MISSING_IMAGES中的图像上,而不是解析和比较名称?外键不可能,因为用户将它们上载到IMAGES表中,我们将它们重新处理到jpgs MISSING_IMAGES中,因此两个表中的扩展不同,这就是为什么我们通过名称检查它,而不使用图像扩展。大约有10000张图片。@atif我已经更新了我的答案。基于函数的索引是最明显的解决方案,但不一定是最好的。插入/更新可能会稍微慢一点,但在具有大量插入更新的实时系统中通常是有意义的。