- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我能够使用连接消除来处理一对一关系等简单情况,但不适用于稍微复杂一些的情况。最终我想尝试 anchor 建模,但首先我需要找到解决这个问题的方法。我使用的是 Oracle 12c 企业版 12.1.0.2.0 版。
我的测试用例的 DDL:
drop view product_5nf;
drop table product_color cascade constraints;
drop table product_price cascade constraints;
drop table product cascade constraints;
create table product(
product_id number not null
,constraint product_pk primary key(product_id)
);
create table product_color(
product_id number not null references product
,color varchar2(10) not null
,constraint product_color_pk primary key(product_id)
);
create table product_price(
product_id number not null references product
,from_date date not null
,price number not null
,constraint product_price_pk primary key(product_id, from_date)
);
一些示例数据:
insert into product values(1);
insert into product values(2);
insert into product values(3);
insert into product values(4);
insert into product_color values(1, 'Red');
insert into product_color values(2, 'Green');
insert into product_price values(1, date '2016-01-01', 10);
insert into product_price values(1, date '2016-02-01', 8);
insert into product_price values(1, date '2016-05-01', 5);
insert into product_price values(2, date '2016-02-01', 5);
insert into product_price values(4, date '2016-01-01', 10);
commit;
第一个 View 无法编译 - 它因 ORA-01799 而失败:列不能外连接到子查询。不幸的是,当我查看 anchor 建模的在线示例时,这就是大多数历史化 View 的定义方式......
create view product_5nf as
select p.product_id
,pc.color
,pp.price
from product p
left join product_color pc on(
pc.product_id = p.product_id
)
left join product_price pp on(
pp.product_id = p.product_id
and pp.from_date = (select max(pp2.from_date)
from product_price pp2
where pp2.product_id = pp.product_id)
);
下面是我修复它的尝试。当通过简单选择 product_id
使用此 View 时,Oracle 设法消除了 product_color 但没有 product_price。
create view product_5nf as
select product_id
,pc.color
,pp.price
from product p
left join product_color pc using(product_id)
left join (select pp1.product_id, pp1.price
from product_price pp1
where pp1.from_date = (select max(pp2.from_date)
from product_price pp2
where pp2.product_id = pp1.product_id)
)pp using(product_id);
select product_id
from product_5nf;
----------------------------------------------------------
| Id | Operation | Name | Rows |
----------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 |
|* 1 | HASH JOIN OUTER | | 4 |
| 2 | INDEX FAST FULL SCAN| PRODUCT_PK | 4 |
| 3 | VIEW | | 3 |
| 4 | NESTED LOOPS | | 3 |
| 5 | VIEW | VW_SQ_1 | 5 |
| 6 | HASH GROUP BY | | 5 |
| 7 | INDEX FULL SCAN | PRODUCT_PRICE_PK | 5 |
|* 8 | INDEX UNIQUE SCAN | PRODUCT_PRICE_PK | 1 |
----------------------------------------------------------
我找到的唯一解决方案是改用标量子查询,如下所示:
create or replace view product_5nf as
select p.product_id
,pc.color
,(select pp.price
from product_price pp
where pp.product_id = p.product_id
and pp.from_date = (select max(from_date)
from product_price pp2
where pp2.product_id = pp.product_id)) as price
from product p
left join product_color pc on(
pc.product_id = p.product_id
)
select product_id
from product_5nf;
---------------------------------------------------
| Id | Operation | Name | Rows |
---------------------------------------------------
| 0 | SELECT STATEMENT | | 4 |
| 1 | INDEX FAST FULL SCAN| PRODUCT_PK | 4 |
---------------------------------------------------
现在 Oracle 成功地删除了 product_price 表。但是,标量子查询的实现方式与联接不同,它们的执行方式根本不允许我在现实世界场景中获得任何可接受的性能。
长话短说我如何重写 View product_5nf
以便 Oracle 成功消除两个相关表?
最佳答案
我认为你这里有两个问题。
首先,加入消除仅适用于某些特定情况(PK-PK、PK-FK 等)。您可以 LEFT JOIN
到任何行集,这不是一个普遍的事情,它将为每个连接键值返回一行,并让 Oracle 消除连接。
其次,即使 Oracle 足够先进,可以在任何 LEFT JOIN
上进行连接消除,它知道每个连接键值只会获得一行,Oracle 尚不支持 上的连接消除>LEFT JOINS
基于复合键(Oracle 支持文档 887553.1 说这将在 R12.2 中出现)。
您可以考虑的一种解决方法是具体化一个 View ,其中包含每个 product_id
的最后一行。然后 LEFT JOIN
到物化 View 。像这样:
create table product(
product_id number not null
,constraint product_pk primary key(product_id)
);
create table product_color(
product_id number not null references product
,color varchar2(10) not null
,constraint product_color_pk primary key(product_id)
);
create table product_price(
product_id number not null references product
,from_date date not null
,price number not null
,constraint product_price_pk primary key (product_id, from_date )
);
-- Add a VIRTUAL column to PRODUCT_PRICE so that we can get all the data for
-- the latest row by taking the MAX() of this column.
alter table product_price add ( sortable_row varchar2(80) generated always as ( lpad(product_id,10,'0') || to_char(from_date,'YYYYMMDDHH24MISS') || lpad(price,10,'0')) virtual not null );
-- Create a MV snapshot so we can materialize a view having only the latest
-- row for each product_id and can refresh that MV fast on commit.
create materialized view log on product_price with sequence, primary key, rowid ( price ) including new values;
-- Create the MV
create materialized view product_price_latest refresh fast on commit enable query rewrite as
SELECT product_id, max( lpad(product_id,10,'0') || to_char(from_date,'YYYYMMDDHH24MISS') || lpad(price,10,'0')) sortable_row
FROM product_price
GROUP BY product_id;
-- Create a primary key on the MV, so we can do join elimination
alter table product_price_latest add constraint ppl_pk primary key ( product_id );
-- Insert the OP's test data
insert into product values(1);
insert into product values(2);
insert into product values(3);
insert into product values(4);
insert into product_color values(1, 'Red');
insert into product_color values(2, 'Green');
insert into product_price ( product_id, from_date, price ) values(1, date '2016-01-01', 10 );
insert into product_price ( product_id, from_date, price) values(1, date '2016-02-01', 8);
insert into product_price ( product_id, from_date, price) values(1, date '2016-05-01', 5);
insert into product_price ( product_id, from_date, price) values(2, date '2016-02-01', 5);
insert into product_price ( product_id, from_date, price) values(4, date '2016-01-01', 10);
commit;
-- Create the 5NF view using the materialized view
create or replace view product_5nf as
select p.product_id
,pc.color
,to_date(substr(ppl.sortable_row,11,14),'YYYYMMDDHH24MISS') from_date
,to_number(substr(ppl.sortable_row,25)) price
from product p
left join product_color pc on pc.product_id = p.product_id
left join product_price_latest ppl on ppl.product_id = p.product_id
;
-- The plan for this should not include any of the unnecessary tables.
select product_id from product_5nf;
-- Check the plan
SELECT *
FROM TABLE (DBMS_XPLAN.display_cursor (null, null,
'ALLSTATS LAST'));
------------------------------------------------
| Id | Operation | Name | E-Rows |
------------------------------------------------
| 0 | SELECT STATEMENT | | |
| 1 | INDEX FULL SCAN | PRODUCT_PK | 1 |
------------------------------------------------
关于sql - 加入消除在带有子查询的 Oracle 中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40490220/
我编写了一些运行速度很慢的 VBA 代码。我的代码中有一系列不同的循环。我知道循环并不总是处理数据的最有效方式,所以我认为它们是问题所在。我需要有关如何更改或消除循环的想法,以便加快代码的运行时间。
我目前有一个网址:http://testsite.local/search/?q=findme一旦有人查询,我的搜索页面。我使用 mod_rewrite 重写了一些页面,想知道是否可以将其变成一个不错
有人可以帮助我执行一个查询,其中查询的重复元素被删除 Select * from table where APPNAME = 'Ap1' or APPNAME= 'Ap2' 使用 DISTINCT 的
我正在尝试在 ubuntu 上使用以下命令在一个文件夹中查找文件并通过 FFmpeg 提供并输出到另一个文件夹。问题是当它处理输出路径和文件名时,它添加了一个 .像这样的路径:/conversions
这个问题在这里已经有了答案: How can I remove all duplicates so that NONE are left in a data frame? (3 个答案) 关闭 1
我想证明以下定理: Theorem Frobenius (A: Set) (q: Prop) (p: A -> Prop) : (q \/ forall x : A, p x) -> (foral
我有一个 PHP 脚本,它只需要一些数据,将其分隔为制表符分隔格式,将其保存为 .xls 文件,然后为用户提供下载链接。 大多数情况下运行良好,但有些人正在获取导出的 .xls 文件的缓存版本。 我想
我有一个看起来有点像这个可重现代码的数据框,我想删除每列的异常值(在我们的例子中,数据点低于或高于平均值 2.5 个标准偏差)而不删除整个主题/行。 Subj mn + sd * 2.5) | (x
我正在尝试编写一个实现 fmap 的演示。在 Haskell 中与 continuation ,我的代码如下所示: #include #include template using Callba
在此 HighCharts例如,如何消除 xaxis 开始位置与 Jan 的刻度位置之间的差距。 http://jsfiddle.net/gh/get/jquery/1.7.2/highslide-s
重现步骤: 将TPanel添加到新的VCL表单并设置Align = alClient。 将 TSpeedButton 添加到面板,并将一些 bmp 图像分配给 Glyph 属性。 (可选,但更清晰:F
我得到一个 JavaScript 数组,其中包含一定数量(未指定)的各种元素(字符串、数字、 bool 值)。我需要消除字符串和 bool 值。我应该如何处理它?我应该使用typeof吗? 最佳答案
我正在寻找一个公式,可以消除字符串中空格后的空格和无用字符。 我的第一 react 是执行以下操作:=LEFT(A1,FIND("",A1)) 它适用于所有有空格的情况 但是如果单元格中没有空格,我的
我有以下问题:我正在尝试编写一个 Javascript 游戏,并且 Angular 色由箭头键控制。 问题是,当一个人按住按键时,在触发第一个按键和重复的按键之间存在短暂的延迟。 另外,当按下“向右箭
让我们考虑一个集合的集合,以及需要在管道内对内部集合的每个元素执行的操作。 为了简单起见,让它成为一个数组数组,操作简单的打印到屏幕上。为了表达我的问题,让我们还有一个元素不是集合的数组: $Arra
跟进this question关于包含源文件。我包括一个 Chapel 模块,其中包含一个名为 classes.chpl 的文件。 ,但我当前的项目也有一个 classes.chpl 。正确的消歧模式
我想知道如何在英特尔语法中的某些指令中区分标签名称和寄存器名称。例如,call rdx通常意味着间接跳转,但是如果我们在同一个汇编文件中有一个标签rdx怎么办?我相信它可以被解释为直接跳转到 rdx
据我了解,Chrome 会异步运行整个程序,这会导致我的扩展程序在单击后大约 2 秒后打开。有没有办法强制扩展程序显示带有“正在加载”消息的 html 页面,然后完成加载 javascript 并用内
我正在将 CSV 加载到 sqlite 数据库,如下所示: sqlite3 /path/to/output.db /dev/null 或者,您可以自己生成 SQL 命令,以便可以使用 INSERT 或
我的 .cabal 文件的许多节中经常有类似的属性。例如 Library x ... ghc-options: -O2 -Wall -fno-warn-missing-s
我是一名优秀的程序员,十分优秀!