Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oracle SQL中的索引、解释计划和记录访问_Sql_Oracle_Database Design - Fatal编程技术网

Oracle SQL中的索引、解释计划和记录访问

Oracle SQL中的索引、解释计划和记录访问,sql,oracle,database-design,Sql,Oracle,Database Design,我一直在学习Oracle SQL中的索引,我想用一个测试表进行一个小实验,看看索引是如何工作的。正如我在前面的一篇文章中所发现的,最好的方法是使用解释计划。然而,我遇到了一些让我困惑的事情 我的示例表包含属性(EmpID、Fname、Lname、occulation等等)。我使用自己编写的java程序(随机名称、职业等)将500000条记录填充到了它中。现在,以下是一些带索引和不带索引的示例查询: 无索引: SELECT Fname FROM EMPLOYEE WHERE Occupation

我一直在学习Oracle SQL中的索引,我想用一个测试表进行一个小实验,看看索引是如何工作的。正如我在前面的一篇文章中所发现的,最好的方法是使用解释计划。然而,我遇到了一些让我困惑的事情

我的示例表包含属性(EmpID、Fname、Lname、occulation等等)。我使用自己编写的java程序(随机名称、职业等)将500000条记录填充到了它中。现在,以下是一些带索引和不带索引的示例查询:

无索引:

SELECT Fname FROM EMPLOYEE WHERE Occupation = 'DOCTOR';
SELECT Fname FROM EMPLOYEE WHERE Occupation = 'DOCTOR';
解释计划说:

OPERATION                         OPTIMIZER COST
TABLE ACCESS(FULL) TEST.EMPLOYEE  ANALYZED  1169
OPERATION                         OPTIMIZER COST
TABLE ACCESS(FULL) TEST.EMPLOYEE  ANALYZED  1169
OPERATION                              OPTIMIZER COST
INDEX(RANGE SCAN) TEST.OCCUPATION_IDX  ANALYZED  67
现在我创建索引:

CREATE INDEX occupation_idx
    ON EMPLOYEE (Occupation);
索引为“职业”\u idx:

解释计划说:

OPERATION                         OPTIMIZER COST
TABLE ACCESS(FULL) TEST.EMPLOYEE  ANALYZED  1169
OPERATION                         OPTIMIZER COST
TABLE ACCESS(FULL) TEST.EMPLOYEE  ANALYZED  1169
OPERATION                              OPTIMIZER COST
INDEX(RANGE SCAN) TEST.OCCUPATION_IDX  ANALYZED  67
所以。。。成本还是一样,1169?现在我试试这个:

索引为“职业”\u idx:

解释计划说:

OPERATION                         OPTIMIZER COST
TABLE ACCESS(FULL) TEST.EMPLOYEE  ANALYZED  1169
OPERATION                         OPTIMIZER COST
TABLE ACCESS(FULL) TEST.EMPLOYEE  ANALYZED  1169
OPERATION                              OPTIMIZER COST
INDEX(RANGE SCAN) TEST.OCCUPATION_IDX  ANALYZED  67
因此,似乎只有当该列是我从中提取值的唯一列时,才会使用索引。但是我认为索引的目的是使用索引列作为键来解锁整个记录?上面的搜索毫无意义。。。它搜索您已经知道的值。我能想到的唯一有价值的查询,只涉及一个索引列的值(而不是记录的其余部分),应该是一个聚合,比如COUNT之类的


我遗漏了什么?

即使有了您的索引,Oracle还是决定对第二个查询进行完整扫描

它为什么这样做?Oracle将创建两个计划,并为每个计划计算成本:-

1) 全扫描

2) 索引访问

Oracle选择了成本较低的计划。很明显,全扫描成本更低

如果您想查看索引计划的成本,可以使用如下提示执行解释计划以强制使用索引:

SELECT /*+ INDEX(EMPLOYEE occupation_idx) */ Fname
FROM EMPLOYEE WHERE Occupation = 'DOCTOR';
如果您在上面做一个解释计划,您将看到成本大于完整扫描成本。这就是为什么Oracle没有选择使用索引

P>一种考虑指标方案成本的简单方法是:-<
  • 索引的b级别(从上到下必须读取多少块)
  • 为在索引中匹配记录而必须随后读取的表块数。这取决于甲骨文公司对从事“医生”职业的员工数量的估计。在您的简单示例中,这将是:

    行数/不同值的数量

更复杂的考虑因素包括集群工厂和索引成本调整,这两者都反映了读取的块已经在内存中,因此不需要从磁盘读取的可能性

也许您可以使用带有索引提示的查询结果以及此查询的结果更新您的问题:-

SELECT COUNT(*), COUNT(DISTINCT( Occupation ))
FROM EMPLOYEE;

这将允许人们对索引计划的成本进行评论。

作为WAG。分析表格和索引,然后查看计划是否更改


当您仅选择职业时,可以通过索引满足整个查询。该索引实际上有一份职业的副本。当您向select添加一个附加列时,Oracle必须转到数据记录以获取它。优化器选择读取所有数据行,而不是所有索引行和数据行。更便宜。

索引是只存储以下数据的表的副本:

  • 索引字段
  • 指向原始行(
    rowid
    )的指针
假设你有一张这样的桌子:

rowid    id  name  occupation
[1]      1   John  clerk
[2]      2   Jim   manager
[3]      3   Jane  boss
occupation  rowid
boss        [3]
manager     [2]
clerk       [1]
然后,
职业
上的索引如下所示:

rowid    id  name  occupation
[1]      1   John  clerk
[2]      2   Jim   manager
[3]      3   Jane  boss
occupation  rowid
boss        [3]
manager     [2]
clerk       [1]
,记录按
职业
B树
中排序

如您所见,如果只选择索引字段,则只需要索引(第二个表)

如果您选择的不是
职业

SELECT  *
FROM    mytable
WHERE   occupation = 'clerk'
然后,引擎应该做两件事:首先在索引中查找相关记录,然后通过
rowid
在原始表中查找记录。这就像您将
rowid
上的两个表合并在一起一样

由于索引中的rowid不按顺序排列,因此对原始表的读取不是顺序的,可能会很慢。按顺序读取原始表并使用
occulation='clerk'
筛选记录可能会更快


引擎不会“解锁”记录:它只是在索引中查找rowid,如果索引本身没有足够的数据,它会通过找到的
rowid
在原始表中查找数据。

我想我看到了这里发生的事情

当索引就位后,您将执行以下操作:

SELECT Occupation FROM EMPLOYEE WHERE Occupation = 'DOCTOR';
执行计划将使用索引。这是一个很简单的问题,因为满足查询所需的所有数据都在索引中,Oracle甚至根本不需要引用表

但是,当您这样做时:

SELECT Fname FROM EMPLOYEE WHERE Occupation = 'DOCTOR';
然后,如果Oracle使用该索引,它将执行索引范围扫描,然后通过ROWID进行表访问,以查找与该职业对应的Fname。现在,根据占用了多少行,Oracle将不得不对表进行一次或多次访问,以查找Fname。例如,如果您有一个表,并且所有员工的职业都设置为“医生”,则索引没有多大用处,Oracle只需对该表进行完整的表扫描。如果有10000名员工,而且只有一名是医生,那么同样,这是一个不需要动脑筋的问题,甲骨文将使用该索引

但当你处于这两个极端之间时,你会发现一些微妙之处。在讨论是否使用索引时,人们喜欢谈论“选择性”,即索引标识了多少行,而不是表的大小。但事实并非如此。Oracle真正关心的是块选择性。也就是说,为了满足查询,它必须访问多少个块?那么,首先,距离扫描有多宽?范围越小