Oracle 选择索引优化

Oracle Selecting Index Optimisation

我需要使用索引优化此查询。我试图索引一些列,但它没有帮助。有没有人有想法?

我需要优化的查询:

Select vintage, wine_no, wname, pctalc, grade, price, wine.vid, vname, wine.cid, cname
from vineyard, class, wine
where wine.vid = vineyard.vid
and wine.cid = class.cid
and wine.cid = 'SHIRAZ' and grade = 'A';

我尝试创建了以下索引: '''在 wine(vid) 上创建索引 wine_vid_idx; 在 wine(cid) 上创建索引 wine_cid_idx; 在葡萄酒(等级)上创建索引 wine_grade_idx;```

我对原始查询的执行计划是:

----------------------------------------------------------------------------------------------
| Id  | Operation                     | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |              |    42 |  9114 |    10   (0)| 00:00:01 |
|*  1 |  HASH JOIN                    |              |    42 |  9114 |    10   (0)| 00:00:01 |
|   2 |   NESTED LOOPS                |              |    42 |  6930 |     2   (0)| 00:00:01 |
|   3 |    TABLE ACCESS BY INDEX ROWID| CLASS    |     1 |    50 |     1   (0)| 00:00:01 |
|*  4 |     INDEX UNIQUE SCAN         | SYS_C0027457 |     1 |       |     1   (0)| 00:00:01 |
|*  5 |    TABLE ACCESS CLUSTER       | WINE    |    42 |  4830 |     1   (0)| 00:00:01 |

PLAN_TABLE_OUTPUT                                                                                                                                                                                                                                                                                           
---------------------------------------------------------------------------------------------
|   6 |   TABLE ACCESS FULL           | VINEYARD |   160 |  8320 |     8   (0)| 00:00:01 |

索引是优化查询的常用有效措施,但是,您需要执行进一步的步骤。基于文本的搜索一般来说往往较慢,因此强烈建议修改您的 class table,这样它将具有数字 primary key 并避免在您的文件中存储 SHIRAZ 等文本wine table,而是 class table 的数字 foreign key 并将文本 SHIRAZ 恰好存储一次,用于其 class 记录,该记录将从wine table 通过数值。此外,您应该对 grade 执行类似的操作。如果您还没有 grade table,请创建一个,其中包含数字 primary key 和一个用于存储值的字段,例如 A.

最后,您的查询正在计算笛卡尔乘法,正如我们从集合论中了解到的那样,它会匹配问题拓扑中的每个坐标。此外,正如我们从关系代数中了解到的那样,您的 where 子句将 运行 用于三维(葡萄园、class、葡萄酒)问题中的所有点 - space。据我所知,如果您将查询重构为使用联接,它应该会变得更快,因为对联接进行了一些优化以避免计算拓扑中的所有点。

让我们重构您当前的查询:

Select vintage, wine_no, wname, pctalc, grade, price, wine.vid, vname, wine.cid, cname
from wine
join class
on wine.cid = class.cid and wine.cid = 'SHIRAZ' and wine.grade = 'A'
join vineyard
on wine.vid = vineyard.vid;

在我建议的结构更改之后,让我们重构此查询以与您的架构兼容:

Select vintage, wine_no, wname, pctalc, grade, price, wine.vid, vname, wine.cid, cname
from wine
join class
on wine.class_id = class.id and class.cid = 'SHIRAZ'
join grade
on wine.grade_id = grade.id and grade.value = 'A'
join vineyard
on wine.vid = vineyard.vid;

此外,由于假设只有几个等级和葡萄园是安全的,我们可以更改在查询中引入 table 的顺序:

Select vintage, wine_no, wname, pctalc, grade, price, wine.vid, vname, wine.cid, cname
from grade
join wine
on wine.grade_id = grade.id and grade.value = 'A'
join class
on wine.class_id = class.id and class.cid = 'SHIRAZ'
join vineyard
on wine.vid = vineyard.vid;

如果这还不够,还有进一步的步骤,如果需要进一步的步骤,请告诉我。

首先:您使用的是旧的连接语法(实际上是 1980 年代的)。这就是我们今天编写查询的方式:

Select
   w.vintage, w.wine_no, w.wname, w.pctalc, w.grade, w.price, w.vid, v.vname, w.cid, c.cname
from wine w
join vineyard v on v.vid = w.vid
join class c on c.cid = w.cid
where w.cid = 'SHIRAZ' 
and w.grade = 'A';

这里只要看一下 WHERE 子句就足以看出您正在寻找与 class 和等级相匹配的葡萄酒。所以,在两列上有一个索引。顺序可能很重要,因此提供两个索引。将此与葡萄园ID一起扩展,以便快速到达葡萄园table。

至于class和葡萄园,你应该已经在他们的ID上有了索引。您可能希望为每个选择的 table 添加一列,以便 DBMS 可以直接从索引中获取值。

create index idx01 on wine ( cid, grade, vid );
create index idx02 on wine ( grade, cid, vid );
create index idx03 on class ( cid, cname );
create index idx04 on vineyard ( vid, vname );

使用执行计划检测未使用的索引(查询将仅使用 idx01 或 idx02 或什至 none,而不是两者)并删除它们。

这是您的查询:

select w.vintage, w.wine_no, w.wname, w.pctalc, w.grade,
       w.price, w.vid, v.vname, w.cid, c.cname
from wine w join
     vineyard v
     on v.vid = w.vid join
     class c
     on c.cid = w.cid
where w.cid = 'SHIRAZ' and
      w.grade = 'A';

所有join都是inner join,所有过滤都在一个table上,条件为相等条件。因此,table 应该是第一个访问的。然后,您需要 joins 过滤条件和其他 tables 的相应 join 键:

  • wine(cid, grade, vid)(前两个键可以任意顺序)。

其他 table 的 vineyard(vid)class(cid)join 键已经被索引,因为它们被声明为主键。因此,以上是您唯一需要的额外索引。