使用索引从表的最后一行获取一个值

问题描述 投票:0回答:1

我有两个表,通过以下示例进行说明。

CREATE TABLE t1
(
   name      VARCHAR2(50 CHAR),
   status    VARCHAR2(8 CHAR),
   CONSTRAINT t1_pk PRIMARY KEY(name)
);

CREATE TABLE t2
(
   id             NUMBER NOT NULL,
   name           VARCHAR2(50 CHAR),
   finished_at    DATE,
   status         VARCHAR2(8 CHAR),
   CONSTRAINT t2_pk PRIMARY KEY(id)
);

CREATE INDEX ix_t2_last
   ON t2(name, finished_at);

现在我想从表

T1
中获取值,以及表 'T2' 中
status
列的值,以获取
finished_at
中具有最高值的记录的给定“名称”。

下面的select语句就是为了说明这个问题。

SELECT name,
       status,
       (  SELECT t2.status
            FROM t2
           WHERE t2.name = t1.name
        ORDER BY t2.finished_at
           FETCH FIRST ROW ONLY)
  FROM t1
 WHERE t1.name = :name;

实际问题如下: 有没有一种方法可以以这样的方式制定语句:

T2
上的索引不仅用于与
name
的范围扫描,而且还使用
finished_at
列也被索引的事实?

我得到的最佳执行计划是:

-----------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name       | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |  OMem |  1Mem |  O/1/M   |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |            |      1 |        |       |     4 (100)|          |      1 |00:00:00.01 |       2 |       |       |          |
|*  1 |  VIEW                         |            |      1 |      1 |    31 |     3   (0)| 00:00:01 |      1 |00:00:00.01 |     107 |       |       |          |
|*  2 |   WINDOW BUFFER PUSHED RANK   |            |      1 |      1 |    20 |     3   (0)| 00:00:01 |      1 |00:00:00.01 |     107 |  2048 |  2048 |     1/0/0|
|   3 |    TABLE ACCESS BY INDEX ROWID| T2         |      1 |      1 |    20 |     3   (0)| 00:00:01 |   9999 |00:00:00.01 |     107 |       |       |          |
|*  4 |     INDEX RANGE SCAN          | IX_T2_LAST |      1 |        |       |     2   (0)| 00:00:01 |   9999 |00:00:00.01 |      67 |       |       |          |
|   5 |  TABLE ACCESS BY INDEX ROWID  | T1         |      1 |      1 |    10 |     1   (0)| 00:00:01 |      1 |00:00:00.01 |       2 |       |       |          |
|*  6 |   INDEX UNIQUE SCAN           | T1_PK      |      1 |      1 |       |     0   (0)|          |      1 |00:00:00.01 |       1 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
 
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
 
   1 - SEL$1 / from$_subquery$_002@SEL$3
   2 - SEL$1
   3 - SEL$1 / T2@SEL$1
   4 - SEL$1 / T2@SEL$1
   5 - SEL$2 / T1@SEL$2
   6 - SEL$2 / T1@SEL$2
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - filter("from$_subquery$_002"."rowlimit_$$_rownumber"<=1)
   2 - filter(ROW_NUMBER() OVER ( ORDER BY "T2"."FINISHED_AT")<=1)
   4 - access("T2"."NAME"=:B1)
   6 - access("T1"."NAME"=:NAME)

当然,如果需要,我可以创建不同的索引。 ;-)

由于

name
中给定的
T2
有很多行,范围扫描将导致获取太多缓冲区。

sql oracle
1个回答
1
投票

您必须创建一个包含所需所有列的多列(串联)索引,从名称(等式谓词)开始,然后是日期(不等式谓词),最后是您选择的列:

create index myindex on t2(name,finished_at,status)

最后一列(状态)的存在不是为了方便查找,而是为了将表的一部分放入索引中,这样如果 Oracle 需要的所有内容都在索引中,则 Oracle 不需要访问表来获取列。显然,您不想忘乎所以地添加几十列,但是对于一两列,如果您的查询将以高频率运行并且需要额外的速度,那么这是一种有用的技术。

© www.soinside.com 2019 - 2024. All rights reserved.