【问题标题】:Can i have a composite index on when using a left join使用左连接时我可以有一个复合索引吗
【发布时间】:2020-09-03 03:18:41
【问题描述】:

我的目标是在student 表上使用复合索引。 Student 表将内连接到xyz 表。我在学生表上创建了我的索引,如下所示:

 CREATE INDEX email_phonenumber_student_idx
  ON student(phonenumber, email);

当我运行查询时

SELECT Phonenumber, email from student 
left join enrolment on enrolment.studentnumber = student.studentnumber 
where months_between(SYSDATE, dateofbirth)/12 >= 18 and 
enrolment.studentnumber is null and 
student.phonenumber = '07123456788' and student.email = 'Chris@Lailasman.com’;

它按预期工作,但没有使用索引,因为当我'EXPLAIN PLAN FOR' 查询时,我只能将主键视为索引。我是否在错误的表上创建了索引?出现的问题是我想使用复合键,但是连接表不包含任何用于复合索引的列。

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1388008413

---------------------------------------------------------------------------------------------
| Id  | Operation                    | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |              |     1 |    63 |     0   (0)| 00:00:01 |
|   1 |  NESTED LOOPS ANTI           |              |     1 |    63 |     0   (0)| 00:00:01 |
|*  2 |   TABLE ACCESS BY INDEX ROWID| STUDENT      |     1 |    50 |     0   (0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | SYS_C0022463 |     1 |       |     0   (0)| 00:00:01 |
|*  4 |   INDEX RANGE SCAN           | SYS_C0022468 |     1 |    13 |     0   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("STUDENT"."EMAIL"='Chris@Lailasman.com' AND
              MONTHS_BETWEEN(SYSDATE@!,INTERNAL_FUNCTION("STUDENT"."DATEOFBIRTH"))/12>=18)
   3 - access("STUDENT"."PHONENUMBER"='07123456788')
   4 - access("ENROLMENT"."STUDENTNUMBER"="STUDENT"."STUDENTNUMBER")

【问题讨论】:

  • and xyz.studentnumber is null; 在您的查询中,但您的解释计划没有显示过滤器,我在这里遗漏了什么吗?
  • 我用它来识别左表中不在右表中的行。
  • 解释计划没有显示它,所以不确定它是否是同一个查询。无论如何,我已经回答了你的问题。您的查询与索引无关。
  • 现在我 100% 确定您在此发布的内容不是。相比之下,您更新的解释计划和查询完全不同。能否请您发布一个 Oracle 会话的输出。
  • 嗨,我用精确查询更新了问题,我截断了表格并添加了 1 行精确匹配以保持简单,因为我只想看到索引正常工作。

标签: sql oracle indexing sqlplus


【解决方案1】:

您的估计行数为“8”。索引对于这样的小表没有用处。 Oracle 知道这一点,所以它只使用更简单的扫描技术。

使用索引会产生开销——例如,通常需要读取索引和原始数据页。随着数据变大,它们很有用。

【讨论】:

  • 那么索引会起作用,只是表还不够大,Oracle无法使用它吗?对吗?
  • 好吧,这不是本例的原因。 OP 要求进行普通选择,Oracle 会按预期进行全表扫描。当您要求 Oracle 选择所有行时,没有理由进行索引扫描。
【解决方案2】:

它按预期工作。 Oracle 完全按照您的要求做了。

CREATE INDEX email_phonenumber_student_idx
  ON student(phonenumber, email);

您在phonenumber, email 上有一个复合索引,而您没有使用查询的过滤谓词 中的任何列:

where months_between(SYSDATE, dateofbirth)/12 >= 18 
and  xyz.studentnumber is null;

所以 Oracle 没有理由对 phonenumber, email 进行索引扫描。您只是选择复合键的那些列,而不是过滤它们:

SELECT Phonenumber, email 
from student left join Xyz

索引将在您PROJECT这些列时使用,而不仅仅是SELECT。正如预期的那样,STUDENT 表适用于FULL TABLE SCAN,因为它是一个普通的选择,并且不对索引列使用任何过滤器。如果您想查看索引扫描的发生情况,请添加以下过滤器:

AND phonenumber = <value>
AND email = <value>

【讨论】:

  • 我添加了电话号码过滤器,但是索引仍然没有被使用?
  • @Annon 看看我上面所说的并完全按照所说的去做。您有包含 2 列的复合索引,那么过滤器中只有一列将如何使用复合索引?我认为您需要阅读文档并了解优化器和索引的工作原理。 在过滤器中使用与您在索引中使用的完全相同的列。 Oracle 优化器将执行索引扫描。这样做并告诉我,如果对您有帮助,也将其标记为已回答
  • 问题仍然存在,我相信我已经添加了你告诉我的内容,但是索引仍然没有被使用。我查看了文档,但找不到错误的原因。我已经用使用的新查询更新了问题,
  • 您并没有讲述整个故事,因为您所说的是不可能的。您发布的查询和解释计划完全不匹配,您的索引也没有参与。我再说一遍,在提出更多问题之前,您必须阅读有关索引的更多信息。相信我,一旦您了解了基础知识,它也会帮助您提出问题。
猜你喜欢
  • 1970-01-01
  • 2021-11-06
  • 2011-11-28
  • 2012-08-05
  • 2013-03-03
  • 1970-01-01
  • 1970-01-01
  • 2011-07-12
相关资源
最近更新 更多