为什么使用索引,但sql仍然很慢
有一个表为什么使用索引,但sql仍然很慢,sql,oracle11g,Sql,Oracle11g,有一个表ORG\u HLD\u INFO和它的索引:“ORG\u HLD\u INFO”(“HLD\u UNI\u code”、“ISVALID”、“ORG\u UNI\u code”)。现在执行下面的查询速度很慢,需要3.26秒(并且获取的所有行都是466行) 为什么这么慢?它应该使用索引,以及索引中select的所有字段,因此无需查询表行 p、 美国。 该表的总计数为:109102083 下面是解释计划 您在评论中说,您的in子句可能有大约100个值 在这种情况下,索引通常是无用的 让我们看
ORG\u HLD\u INFO
和它的索引:“ORG\u HLD\u INFO”(“HLD\u UNI\u code”、“ISVALID”、“ORG\u UNI\u code”)
。现在执行下面的查询速度很慢,需要3.26秒(并且获取的所有行都是466行)
为什么这么慢?它应该使用索引,以及索引中select的所有字段,因此无需查询表行
p、 美国。
该表的总计数为:109102083
下面是解释计划
您在评论中说,您的
in
子句可能有大约100个值
在这种情况下,索引通常是无用的
让我们看一下您的查询的简化版本
select HLD_UNI_CODE ,ORG_UNI_CODE
from ORG_HLD_INFO
where ISVALID=1 and HLD_UNI_CODE in (3, 4, 5)
这相当于
select HLD_UNI_CODE ,ORG_UNI_CODE
from ORG_HLD_INFO
where ISVALID=1 and
(HLD_UNI_CODE = 3 OR HLD_UNI_CODE = 4 OR HLD_UNI_CODE = 5)
select HLD_UNI_CODE ,ORG_UNI_CODE
from ORG_HLD_INFO
where ISVALID=1 and HLD_UNI_CODE = 3
UNION ALL
select HLD_UNI_CODE ,ORG_UNI_CODE
from ORG_HLD_INFO
where ISVALID=1 and HLD_UNI_CODE = 4
UNION ALL
select HLD_UNI_CODE ,ORG_UNI_CODE
from ORG_HLD_INFO
where ISVALID=1 and HLD_UNI_CODE = 5
这相当于
select HLD_UNI_CODE ,ORG_UNI_CODE
from ORG_HLD_INFO
where ISVALID=1 and
(HLD_UNI_CODE = 3 OR HLD_UNI_CODE = 4 OR HLD_UNI_CODE = 5)
select HLD_UNI_CODE ,ORG_UNI_CODE
from ORG_HLD_INFO
where ISVALID=1 and HLD_UNI_CODE = 3
UNION ALL
select HLD_UNI_CODE ,ORG_UNI_CODE
from ORG_HLD_INFO
where ISVALID=1 and HLD_UNI_CODE = 4
UNION ALL
select HLD_UNI_CODE ,ORG_UNI_CODE
from ORG_HLD_INFO
where ISVALID=1 and HLD_UNI_CODE = 5
这里我们可以使用UNION ALL
,因为我们在所选列中包括HLD\u UNI\u code
。如果不是,我们可能需要使用UNION
无论如何,关键是每个单独的简单查询
select HLD_UNI_CODE ,ORG_UNI_CODE
from ORG_HLD_INFO
where ISVALID=1 and HLD_UNI_CODE = 5
可以使用索引。使用,从某种意义上说,引擎将在索引中查找以仅查找所需的行,而不是扫描所有行
在某些数据库中,优化器可能足够聪明,可以将/中的或
查询重写为更简单索引搜索的联合(如果
中的中只有很少的值)。我不知道Oracle的优化器是否能够完成这种转换
但是,当您有数百个这样简单的查询时,执行所有这些查找并将它们放在一起的成本很快就会变得太高,因此优化器选择扫描整个表;扫描表(或索引)仍然意味着读取所有109102083行,并对每一行应用过滤器
您可以在plan范围扫描中看到,而不是seek,这实际上意味着读取所有行。您可以看到谓词(filter)带有一堆或s
您可以尝试将查询重写为一百个联合,并检查它是否运行得更快,但查询可能会变得太复杂而无法解析。因此,即使您尝试手动执行此转换,也可能不可行,除非您找到一些技巧,例如在循环中运行数百个简单查询并将中间结果转储到临时表中。在(30004536568,…)
子句中的中有多少值?如果它不止几个,那么索引就毫无用处。这是一个综合索引吗?@VladimirBaranov谢谢!通常在100左右,但是为什么在这种情况下索引是无用的,如何改进它呢?您可以提供执行的SQL监视器报告吗。在你知道发生了什么之前,一切都只是猜测…@BobC添加了解释planThanks!全局分区索引在这种情况下有用吗?@朱国伟,我没有分区索引的经验,但我怀疑它们是否有用。如果可以将IN
子句中的值列表放入表中,则可以将查询重写为“强制”优化器执行搜索。我尝试使用的关键思想是所谓的横向连接。我对Oracle了解不多,但它应该支持它。不过,我不知道Oracle的确切语法。你最好再问一个问题。不过,不能保证它会比全扫描快。