找到有效的oracle数据库条件查询方法

时间:2017-05-26 06:45:47

标签: oracle optimization

我有两张桌子,名为“订单”和“假期”

“订单”表格

orderId | orderDate
1个2017年2月3日
2个2017年2月3日
3个2017年2月3日
4个2017年2月3日
5个2017年4月3日
6个2017年4月3日
7个2017年4月3日
8个2017年4月3日



“假期”表

holiId | holiDate
1个2017年12月3日
2个2017年2月6日
3个2017年6月9日
4 2017年2月3日


然后,我有这个查询

SELECT orderId, orderDate, 
CASE WEHN hd.holiDate IS NOT NULL THEN 'HOLIDAY'
ELSE to_char(or.Day, 'DD-MON-YYYY') AS 'WEEKDAY'
FROM Orders or
LEFT JOIN Holiday hd
ON or.orderDate = hd.holiDate



这给了我一些结果如下所示的结果(

orderId | orderDate | WEEKDAY
1个2017年2月3日HOLIDAY
2个2017年2月3日HOLIDAY
3个2017年2月3日HOLIDAY
4个2017年2月3日HOLIDAY
5 2017年4月3日星期六
6 2017年4月3日SATURDAY
7 2017年4月3日星期六
8 2017年4月3日星期六


基本上,我正在做的是我通过“left join on”子句将“Orders”表的每一行与“Holiday”表进行比较。
然后我将每一行标记为'HOLIDAY'(如果有的话)比赛。它按预期工作,但我想知道我是否可以改进此查询。在实际情况中,我会有很多行具有相同的orderDate值。

当数据库将“Orders”的第一行与“Holiday”表进行比较时,它会发现该当前行与“Holiday”表中的一行匹配。因此,数据库会将其标记为“HOLIDAY”。

然后,它将移动到下一行,然后对“假日”表执行相同的比较操作。
这是我的想法“有效的方式”可以进来。

现在我已经知道02-03-2017是第一排比较中的'HOLIDAY'。因此,我首先将当前行的orderDate与之前的行比较,然后如果它们匹配,则只需使用前一行的WEEKDAY列的值。如果它们不匹配,只需对“假日”表进行比较操作。

有没有办法做到这一点?

1 个答案:

答案 0 :(得分:0)

如果是Oracle之外的任何其他数据库,那么您的分析是正确的。幸运的是,在Oracle中,您可以使用Hash join来为您节省时间。

当你说它是一个大表问题时,你的情况是什么是大的定义,我们谈论的是多少行/块数据和多少列/行(投影/选择)。

在任何情况下检查下面的代码有3000万行,数据列被索引只是为了确保它不进行散列连接,而是进行排序合并或嵌套循环连接。

你的假期表真的不大,因为除非计算周末有假期,否则你一年中将有20到30个假期,即使那时它还不到100行。因此,散列连接将首先在holidate列上创建HASH,然后使用这些散列它将在一次扫描整个订单表。这里的关键词是ONE go,换句话说,它不会进行比较,因为你每次都在逐行思考。因此,它会非常快,具体取决于会话的PGA内存大小。让我们看看它对你所展示的两列包含的3000万行订单表的速度有多快。

 alter session set nls_date_format='DD-MON-RRRR';
drop table orders;
drop table holiday;
create table orders (orderid number, orderdate date);
create table holiday(holiid number, holidate date);

insert into orders 
select level, '03-FEB-2017' from dual connect by level <= 20000000;


insert into holiday values (1,'03-dec-2017');
insert into holiday values (2,'06-feb-2017');
insert into holiday values (3,'09-jun-2017');
insert into holiday values (4,'03-feb-2017');
commit;
select count(*) from orders;
select count(*) from holiday;

alter table orders add constraint pk_orders primary key(orderid);
alter table holiday add constraint pk_holiday primary key (holiid);

create index idx_orders on orders(orderdate);
create index idx_holiid on holiday(holidate);

begin
for i in 20000001..30000000
loop
insert into orders select i,'04-MAR-2017' from dual;
end loop;
commit;
end;

SET TIMING ON;
SELECT orderId, orderDate, 
CASE WHEN hd.holiDate IS NOT NULL THEN 'HOLIDAY'
ELSE to_char("or".orderdate, 'DAY') END AS WEEKDAY
FROM Orders "or"
LEFT JOIN Holiday hd
ON "or".orderDate = hd.holiDate;

This last query elapsed time was >>Query Run In:Query Result 2

Elapsed: 00:00:00.363

让我们看一下解决方案,enter image description here

顺便说一句,不要使用&#34;或&#34;作为一个表别名它是一个保留字,如果你将使用它,你将不得不使用双引号,这是一个不好的做法。如果你不想在PL / SQL广告SQL引擎之间进行2百万个上下文切换,也不要像我一样使用开始和结束块进行快速和脏插入而是使用forall。