oracle 当SQL索引不能解决性能问题时该怎么办?

izkcnapc  于 2023-01-25  发布在  Oracle
关注(0)|答案(1)|浏览(120)

此查询ONE

SELECT * FROM TEST_RANDOM WHERE EMPNO >= '236400' AND EMPNO <= '456000';

正在以成本1927运行。
这个查询TWO

SELECT * FROM TEST_RANDOM WHERE EMPNO = '236400';

正在以1924的成本运行。
这个表TEST_RANDOM有1.000.000行,我创建这个表是为了:

Create table test_normal (empno varchar2(10), ename varchar2(30), sal number(10), faixa varchar2(10));

Begin 
    For i in 1..1000000 
    Loop 
        Insert into test_normal values(
            to_char(i), dbms_random.string('U',30), 
            dbms_random.value(1000,7000), 'ND'
        ); 
        If mod(i, **10000)** = 0 then 
            Commit; 
        End if; 
    End loop; 
End; 

Create table test_random 
as
select /*+ append */ * from test_normal order by dbms_random.random;

我在字段EMPNO中创建了一个B树索引,因此:

CREATE INDEX IDX_RANDOM_1 ON TEST_RANDOM (EMPNO);

在此之后,查询TWO得到改进,并且成本变为4。
但是查询ONE没有改进,因为Oracle数据库忽略了它,出于某种原因,Oracle数据库理解此查询不值得使用带索引的计划执行...
我的问题是:我们可以做些什么来提高这个查询ONE的性能呢?因为索引的解决方案没有解决,而且它的成本仍然很高...

qncylg1j

qncylg1j1#

对于此查询,Oracle不使用索引,因为优化器正确地估计了行数,并正确地决定了全表扫描会更快或更有效。
B树索引通常只在可用于返回一小部分行时才有用,而您的第一个查询返回了大约25%的行。很难说理想的行百分比是多少,但25%几乎总是太大了。在我的系统上,当查询返回1723行时,执行计划将从全表扫描更改为索引范围扫描-但这个数字可能会有所不同。
全表扫描在检索大部分行时优于索引的原因有以下几个:
1.**单块与多块:**在Oracle中,与几乎所有计算机系统一样,一次检索多个数据块(顺序访问)比一次检索一个随机数据块(随机访问)要快得多。
1.**聚簇因子:**Oracle将所有行存储在块中,块通常为8 KB大小,类似于页。如果索引的效率非常低,例如索引是基于随机排序的数据构建的,并且两次顺序读取很少从同一个块中读取,则从索引中阅读25%的行可能仍然需要读取100%的表块。
1.**算法复杂性:**全表扫描将数据作为简单的堆读取,即O(N)。单个索引访问要快得多,为O(LOG(N))。但随着索引访问次数的增加,这种好处逐渐消失,直到最终使用的索引为O(N * LOG(N))
可以执行以下操作来提高不使用索引时的性能:
1.**分区:**分区是从表中检索大部分数据的理想解决方案(但必须获得许可)。使用分区时,Oracle会将逻辑表拆分为多个物理表,查询只能从所需的分区中读取。这可以带来多块读取的好处,但仍会限制扫描的数据量。
1.**并行性:**让Oracle工作得更辛苦,而不是更聪明。但是对于这么小的表来说,并行性可能不值得这么麻烦。
1.**实体化视图:**创建只存储所需内容的表。
1.**对数据进行排序:**通过按相关列对表数据进行排序(而不是随机排序)来改进索引聚簇因子。在您的情况下,请将order by dbms_random.random替换为order by empno。根据您的版本和平台,可以使用实体化区域Map来保持表的排序。
1.**压缩:**收缩表以加快读取整个表的速度。
对于可能的小性能问题,这是相当多的信息。在您进入这个兔子洞之前,可能值得问一下,您是否真的有一个重要的性能问题(通过时钟或资源消耗来衡量),或者您只是通过查看有点无意义的成本度量来钓性能问题?

相关问题