由于类型转换而未使用索引?

par*_*rkr 3 database oracle indexing performance

由于特定表上的全表扫描,我的进程表现不佳.我已经计算了统计数据,重建了现有的索引,并尝试为此表添加新索引,但这还没有解决问题.

隐式类型转换可以停止使用索引吗?其他原因呢?全表扫描的成本比索引查找大1000左右.

编辑:

SQL语句:

select unique_key 
from src_table 
where natural_key1 = :1 
and natural_key2 = :2 
and natural_key3 = :3;
Run Code Online (Sandbox Code Playgroud)
  • natural_key1的基数很高,但有一种类型转换.
  • 自然键的其他部分是低基数,并且未启用位图索引.
  • 表大小约为1,000,000条记录.

Java代码(不易修改):

ps.setLong(1, oid);
Run Code Online (Sandbox Code Playgroud)

这与列数据类型:varchar2冲突

Vin*_*rat 12

隐式转换可以防止使用由优化的指标.考虑:

SQL> CREATE TABLE a (ID VARCHAR2(10) PRIMARY KEY);

Table created

SQL> insert into a select rownum from dual connect by rownum <= 1e6;

1000000 rows inserted
Run Code Online (Sandbox Code Playgroud)

这是一个简单的表,但数据类型不是'正确',即如果你这样查询它将完全扫描:

SQL> select * from a where id = 100;

ID
----------
100
Run Code Online (Sandbox Code Playgroud)

这个查询实际上相当于:

select * from a where to_number(id) = 100;
Run Code Online (Sandbox Code Playgroud)

它因为我们索引id而不能使用索引to_number(id).如果我们想要使用索引,我们必须明确:

select * from a where id = '100';
Run Code Online (Sandbox Code Playgroud)

回复pakr的评论: 关于隐式转换有很多规则.一个好的起点是 文档.除其他外,我们了解到:

在SELECT FROM操作期间,Oracle将列中的数据转换为目标变量的类型.

这意味着当在"WHERE column=variable"子句期间发生隐式转换时,Oracle将转换列的数据类型而不转换变量,从而阻止使用索引.这就是您应该始终使用正确类型的数据类型或显式转换变量的原因.

来自Oracle doc:

Oracle建议您指定显式转换,而不是依赖隐式或自动转换,原因如下:

  • 使用显式数据类型转换函数时,SQL语句更容易理解.
  • 隐式数据类型转换可能会对性能产生负面影响,尤其是当列值的数据类型转换为常量的数据类型而不是相反时.
  • 隐式转换取决于它发生的上下文,并且在每种情况下可能无法以相同的方式工作.例如,从datetime值到VARCHAR2值的隐式转换可能会返回意外的年份,具体取决于NLS_DATE_FORMAT参数的值.
  • 隐式转换的算法可能会在软件版本和Oracle产品之间发生变化.显式转换的行为更具可预测性.


Qua*_*noi 8

让你条件sargable,即将字段本身与恒定条件进行比较.

这是不好的:

SELECT  *
FROM    mytable
WHERE   TRUNC(date) = TO_DATE('2009.07.21')
Run Code Online (Sandbox Code Playgroud)

,因为它无法使用索引.Oracle无法反转TRUNC()函数来获取范围界限.

这很好:

SELECT  *
FROM    mytable
WHERE   date >= TO_DATE('2009.07.21')
        AND date < TO_DATE('2009.07.22')
Run Code Online (Sandbox Code Playgroud)

要摆脱隐式转换,请使用显式转换:

这是不好的:

SELECT  *
FROM    mytable
WHERE   guid = '794AB5396AE5473DA75A9BF8C4AA1F74'

-- This uses implicit conversion. In fact this is RAWTOHEX(guid) = '794AB5396AE5473DA75A9BF8C4AA1F74'
Run Code Online (Sandbox Code Playgroud)

这很好:

SELECT  *
FROM    mytable
WHERE   guid = HEXTORAW('794AB5396AE5473DA75A9BF8C4AA1F74')
Run Code Online (Sandbox Code Playgroud)

更新:

这个查询:

SELECT  unique_key
FROM    src_table
WHERE   natural_key1 = :1
        AND natural_key2 = :2
        AND natural_key3 = :3
Run Code Online (Sandbox Code Playgroud)

在很大程度上取决于你的领域的类型.

将变量显式转换为字段类型,就像从字符串中转换一样.