当我想在oracle中搜索最小和最大结果时,哪种方法更好?
Which method is better when I want to search the min and max result in oracle?
我有一个叫学生的table,我想得到最高分和最低分,所以我用第一种方式写sql:
select max(score),min(score) from student;
第二种方式:
select max(score) from student;
select min(score) from student;
我在网上搜索,他们说第二种方式更好,因为oracle不能扫描相同的索引time.But第二种方式不能确保相同的数据源,因为它做了两次searching.How 修复它?
将第二种方法的两个查询合并为一个查询:
select
(select max(score) from student),
(select min(score) from student)
from dual;
该解决方案使用两次快速索引扫描。它应该 运行 比选项 1 或 2 更快,并且也将是一致的。
为什么最简单的解决方案不起作用?
看起来 Oracle 应该 有办法运行 最佳地做到这一点:
select max(score),min(score) from student;
我以前见过这个查询,看到人们讨论过它,Oracle 甚至有特殊的访问路径来获取最大值和最小值:INDEX FULL SCAN (MIN/MAX)
。但它似乎无法同时执行最小值和最大值,我不确定为什么。
很难证明 Oracle 不能 做某事。也许稍后会有人进来证明我错了。我的答案基于 Richard Foote 的 this article,他可能是世界顶级的 Oracle 索引专家。我在下面包含了一些简单的测试。示例模式看起来像是 Oracle 在一次查询中自动使用 INDEX FULL SCAN (MIN/MAX)
两次的理想情况,但事实并非如此。我的结果是使用最新版本 12.2 生成的。
示例架构
--Create STUDENT table with 1.6 million rows, an index on score, and fresh statistics.
--drop table student;
create table student(name varchar2(100), score number not null);
insert into student select lpad('A', 20, 'A'), level from dual connect by level <= 100000;
insert into student select * from student;
insert into student select * from student;
insert into student select * from student;
insert into student select * from student;
begin
dbms_stats.gather_table_stats(user, 'STUDENT');
end;
/
create index student_idx on student(score);
选项 1:具有最小值和最大值的最简单查询 - 不起作用
最简单的查询使用 INDEX FAST FULL SCAN
。这可能比完整 table 扫描更好,但对于大型索引来说仍然很昂贵。
explain plan for select max(score),min(score) from student;
select * from table(dbms_xplan.display);
Plan hash value: 4052181173
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5 | 972 (2)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 5 | | |
| 2 | INDEX FAST FULL SCAN| STUDENT_IDX | 1600K| 7812K| 972 (2)| 00:00:01 |
-------------------------------------------------------------------------------------
选项 2 - 一次查询中只有 MIN 或 MAX
运行一次一个导致最优计划,成本超低3。它有INDEX FULL SCAN (MIN/MAX)
操作。这可能是它得到的最快速度,尽管它只是 returns 一半的答案。使用 MIN
而不是 MAX
returns 相同的计划。
--MIN works the same way
explain plan for select max(score) from student;
select * from table(dbms_xplan.display);
Plan hash value: 3501948619
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 5 | | |
| 2 | INDEX FULL SCAN (MIN/MAX)| STUDENT_IDX | 1 | 5 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------------------
选项 3 - 将 MIN 和 MAX 与子查询组合
将两者与子查询结合起来需要更多的代码,但结果会比选项 1 中的简单查询快得多。成本看起来比选项 2 的成本高两倍,但是当你考虑到数据库的额外往返,选项 3 将是最快的。
还有其他方法可以在一个查询中执行此操作,例如使用 UNION ALL
.
explain plan for
select
(select max(score) from student),
(select min(score) from student)
from dual;
select * from table(dbms_xplan.display);
Plan hash value: 661746414
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 8 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 5 | | |
| 2 | INDEX FULL SCAN (MIN/MAX)| STUDENT_IDX | 1 | 5 | 3 (0)| 00:00:01 |
| 3 | SORT AGGREGATE | | 1 | 5 | | |
| 4 | INDEX FULL SCAN (MIN/MAX)| STUDENT_IDX | 1 | 5 | 3 (0)| 00:00:01 |
| 5 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------------
select ma,mi from
(select max(score) ma from student) a,
(select min(score) mi from student) b
我有一个叫学生的table,我想得到最高分和最低分,所以我用第一种方式写sql:
select max(score),min(score) from student;
第二种方式:
select max(score) from student;
select min(score) from student;
我在网上搜索,他们说第二种方式更好,因为oracle不能扫描相同的索引time.But第二种方式不能确保相同的数据源,因为它做了两次searching.How 修复它?
将第二种方法的两个查询合并为一个查询:
select
(select max(score) from student),
(select min(score) from student)
from dual;
该解决方案使用两次快速索引扫描。它应该 运行 比选项 1 或 2 更快,并且也将是一致的。
为什么最简单的解决方案不起作用?
看起来 Oracle 应该 有办法运行 最佳地做到这一点:
select max(score),min(score) from student;
我以前见过这个查询,看到人们讨论过它,Oracle 甚至有特殊的访问路径来获取最大值和最小值:INDEX FULL SCAN (MIN/MAX)
。但它似乎无法同时执行最小值和最大值,我不确定为什么。
很难证明 Oracle 不能 做某事。也许稍后会有人进来证明我错了。我的答案基于 Richard Foote 的 this article,他可能是世界顶级的 Oracle 索引专家。我在下面包含了一些简单的测试。示例模式看起来像是 Oracle 在一次查询中自动使用 INDEX FULL SCAN (MIN/MAX)
两次的理想情况,但事实并非如此。我的结果是使用最新版本 12.2 生成的。
示例架构
--Create STUDENT table with 1.6 million rows, an index on score, and fresh statistics.
--drop table student;
create table student(name varchar2(100), score number not null);
insert into student select lpad('A', 20, 'A'), level from dual connect by level <= 100000;
insert into student select * from student;
insert into student select * from student;
insert into student select * from student;
insert into student select * from student;
begin
dbms_stats.gather_table_stats(user, 'STUDENT');
end;
/
create index student_idx on student(score);
选项 1:具有最小值和最大值的最简单查询 - 不起作用
最简单的查询使用 INDEX FAST FULL SCAN
。这可能比完整 table 扫描更好,但对于大型索引来说仍然很昂贵。
explain plan for select max(score),min(score) from student;
select * from table(dbms_xplan.display);
Plan hash value: 4052181173
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5 | 972 (2)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 5 | | |
| 2 | INDEX FAST FULL SCAN| STUDENT_IDX | 1600K| 7812K| 972 (2)| 00:00:01 |
-------------------------------------------------------------------------------------
选项 2 - 一次查询中只有 MIN 或 MAX
运行一次一个导致最优计划,成本超低3。它有INDEX FULL SCAN (MIN/MAX)
操作。这可能是它得到的最快速度,尽管它只是 returns 一半的答案。使用 MIN
而不是 MAX
returns 相同的计划。
--MIN works the same way
explain plan for select max(score) from student;
select * from table(dbms_xplan.display);
Plan hash value: 3501948619
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 5 | | |
| 2 | INDEX FULL SCAN (MIN/MAX)| STUDENT_IDX | 1 | 5 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------------------
选项 3 - 将 MIN 和 MAX 与子查询组合
将两者与子查询结合起来需要更多的代码,但结果会比选项 1 中的简单查询快得多。成本看起来比选项 2 的成本高两倍,但是当你考虑到数据库的额外往返,选项 3 将是最快的。
还有其他方法可以在一个查询中执行此操作,例如使用 UNION ALL
.
explain plan for
select
(select max(score) from student),
(select min(score) from student)
from dual;
select * from table(dbms_xplan.display);
Plan hash value: 661746414
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 8 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 5 | | |
| 2 | INDEX FULL SCAN (MIN/MAX)| STUDENT_IDX | 1 | 5 | 3 (0)| 00:00:01 |
| 3 | SORT AGGREGATE | | 1 | 5 | | |
| 4 | INDEX FULL SCAN (MIN/MAX)| STUDENT_IDX | 1 | 5 | 3 (0)| 00:00:01 |
| 5 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 |
------------------------------------------------------------------------------------------
select ma,mi from
(select max(score) ma from student) a,
(select min(score) mi from student) b