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 应该是第一个访问的。然后,您需要 join
s 过滤条件和其他 tables 的相应 join
键:
wine(cid, grade, vid)
(前两个键可以任意顺序)。
其他 table 的 vineyard(vid)
和 class(cid)
的 join
键已经被索引,因为它们被声明为主键。因此,以上是您唯一需要的额外索引。
我需要使用索引优化此查询。我试图索引一些列,但它没有帮助。有没有人有想法?
我需要优化的查询:
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 应该是第一个访问的。然后,您需要 join
s 过滤条件和其他 tables 的相应 join
键:
wine(cid, grade, vid)
(前两个键可以任意顺序)。
其他 table 的 vineyard(vid)
和 class(cid)
的 join
键已经被索引,因为它们被声明为主键。因此,以上是您唯一需要的额外索引。