为啥使用索引但sql仍然很慢

Posted

技术标签:

【中文标题】为啥使用索引但sql仍然很慢【英文标题】:Why used index but the sql is still slow为什么使用索引但sql仍然很慢 【发布时间】:2019-08-16 04:08:35 【问题描述】:

有一个表ORG_HLD_INFO,并且有一个索引:"ORG_HLD_INFO" ("HLD_UNI_CODE", "ISVALID", "ORG_UNI_CODE")。现在执行下面的查询很慢,需要 3.26 秒(并且获取的所有行都是 466)

select HLD_UNI_CODE ,ORG_UNI_CODE
from ORG_HLD_INFO
where ISVALID=1 and HLD_UNI_CODE in (30004536568,...) 

为什么这么慢?它应该使用索引,以及索引中选择的所有字段,因此无需查询表行。

附言 该表的总数为:109102083 以下是解释计划

【问题讨论】:

in (30004536568,...) 子句中有多少个值?如果它超过几个,那么索引几乎没用。 这是一个复合索引吗? @VladimirBaranov 谢谢!通常在 100 左右,但为什么在这种情况下索引是无用的,如何改进它? 您能否提供执行的 SQL 监视器报告。在你知道发生了什么之前,一切都只是猜测...... @BobC 已添加解释计划 【参考方案1】:

您在 cmets 中说您的 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

这里我们可以使用UNION ALL,因为我们在选定的列中包含HLD_UNI_CODE。如果不是,我们可能需要使用UNION

无论如何,关键是每个单独的简单查询都像

select HLD_UNI_CODE ,ORG_UNI_CODE
from ORG_HLD_INFO
where ISVALID=1 and HLD_UNI_CODE = 5

可以使用索引。从某种意义上说,引擎将在索引中查找以仅查找所需的行而不是扫描所有行。

在某些数据库中,优化器可能足够聪明,可以将IN/OR 查询重写为更简单的索引查找的UNION(如果IN 中的值很少)。完全不知道Oracle的优化器能不能做这种转换。

但是,当您有数百个这样的简单查询时,执行所有这些查找然后将它们放在一起很快就会变得过于昂贵,因此优化器选择扫描整个表;并且扫描表(或索引)仍然意味着读取所有 109102083 行并将过滤器应用于每一行。

在计划RANGE SCAN中可以看到,不是seek,本质上就是读取所有行。你可以看到 Predicate(过滤器)和一堆ORs。

您可以尝试将查询重写为数百个联合并检查它是否运行得更快,但查询可能变得过于复杂而无法解析。因此,即使您尝试手动进行此转换,也可能不可行,除非您找到一些技巧,例如在循环中运行数百个简单查询并将中间结果转储到临时表中。

【讨论】:

谢谢!全局分区索引在这种情况下有帮助吗? @zhguuowei,我没有分区索引的经验,但我怀疑他们能提供帮助。如果您可以将IN 子句中的值列表放入表中,则可以将查询重写为“强制”优化器进行数百次搜索。我尝试使用的关键思想是所谓的横向连接。我对Oracle了解不多,但它应该支持它。不过,我不知道 Oracle 的确切语法。你最好再问一个问题。但是,不能保证它会比全扫描更快。

以上是关于为啥使用索引但sql仍然很慢的主要内容,如果未能解决你的问题,请参考以下文章

求助,sql语句无法用到索引,执行很慢

SQL查询很慢。没有索引如何改进?

为啥我的 Postgres SQL 查询不使用索引

MySQL:为啥在使用索引时仍然“使用文件排序”?

mysql全文索引 很慢,速度不如like的百分之一

mysql全文索引 很慢,速度不如like的百分之一