EDB分区表的又一个“坑”

下周有一个应用上线,其中涉及一个夜维删除逻辑的应用,大体功能是按照时间删除一张表的历史数据,这张表的主键是另外一张时间分区表的外键,使用的是EDB(9.2)数据库,这次测试就意外发现了一个说是隐藏,也不算隐藏,至少和Oracle分区表有很大不同的地方,或者可以称他为KENG,“坑”。

P.S. 这里不是贬低EDB,毕竟能做到和Oracle最相近并不容易。但就分区这个功能,已经不是第一次碰见“坑”了,可能对EDB来说不公平,也许这个功能就是这么设计的,但至少从Oracle使用习惯上来看,确实需要额外注意。
上次碰见的问题可以参考:http://blog.csdn.net/bisal/article/details/50089359

在这还要感谢wc和lx同学的帮助,一块排查。

实验过程:
目标:T1表是主表,T2表是子表,T2表的t1_id字段作为外键关联T1表的主键id字段。要验证的就是是否可以在主子表有关联数据的情况下,直接删除T1表的数据。

1.按照正常理解,这种操作是不行的,EDB普通表是支持的,实验如下。
(1) 创建T1和T2表

create table t1 (
id number primary key);

create table t2 (
id number primary key,
t1_id number,
constraint fk_t2 foreign key(t1_id) references t1(id));

(2) 插入测试数据

insert into t1 values(1);
insert into t2 values(1, 1);
commit;

此时T1和T2存在关联数据。

(3) 此时直接删除T1表记录,会报错:

[SQL]delete from t1;

[Err] ERROR:  update or delete on table "t1" violates foreign key constraint "fk_t2" on table "t2"
DETAIL:  Key (id)=(1) is still referenced from table "t2".

因为存在外键关联,不能先删除主表记录。关系型数据库都会有这样的要求。
同样,直接drop表T1也是禁止的,

[SQL]drop table t1;

[Err] ERROR:  cannot drop table t1 because other objects depend on it
DETAIL:  constraint fk_t2 on table t2 depends on table t1
HINT:  Use DROP ... CASCADE to drop the dependent objects too.

2.接下来就要说我碰见的问题了。
(1) 创建主表T1和子表T2,唯一不同的是T2是分区表。

create table t1 (
id number primary key);

create table t2 (
id number primary key,
t1_id number,
t2_date date,
constraint fk_t2 foreign key(t1_id) references t1(id))
partition by range (t2_date)
(
  partition part_01 values less than ('2016-01-02'),
  partition part_02 values less than ('2016-01-03'),
  partition part_03 values less than ('2016-01-04'),
  partition part_04 values less than ('2016-01-05')
);

(2) 插入测试数据

insert into t1 values(1);
insert into t1 values(2);
commit;

insert into t2 values(1, 1, to_date('2016-01-01','yyyy-mm-dd'));
insert into t2 values(2, 1, to_date('2016-01-02','yyyy-mm-dd'));
commit;

同样,表T1和T2存在关联数据。

(3) 此时删除T1表记录,

[SQL]delete from t1;

时间: 0.004s

受影响的行: 0

竟然能删除。。。第一次碰见还是比较的毁三观。。。为什么?

原因知道后其实很简单,但确实要是开始不了解EDB分区和Oracle分区的一些不同之处,很难绕出来。

之所以有主外键,就是为了让数据库能控制这种关联关系,这里能直接删除主表记录,并不是违反了主外键的逻辑原理,而是其实这块是不受主外键的约束,从建表后的DDL语句可以看出端倪。

这是子表定义,可以看见他有Foreign Key的定义:

CREATE TABLE "t2" (
"id" numeric NOT NULL,
"t1_id" numeric,
"t2_date" timestamp(6),
CONSTRAINT "t2_pkey" PRIMARY KEY ("id"),
CONSTRAINT "fk_t2" FOREIGN KEY ("t1_id") REFERENCES "btracer"."t1" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION
)
WITH (OIDS=FALSE)

但我们看其中一个分区表T2_PART_01的定义,却没有Foreign Key的定义,因此可以直接删除主表T1的记录是正常的,因为T2_PART_01根本没有和主表T1的主外键关联关系。

CREATE TABLE "btracer"."t2_part_01" (
"id" numeric NOT NULL,
"t1_id" numeric,
"t2_date" timestamp(6),
CONSTRAINT "t2_part_01_pkey" PRIMARY KEY ("id"),
CONSTRAINT "t2_part_01_partition" CHECK (t2_date < '02-JAN-16 00:00:00'::timestamp without time zone)
)
INHERITS ("btracer"."t2")
WITH (OIDS=FALSE)
;

其实开始使用EDB分区的时候,手工创建新分区的时候,都会为每个分区创建一个本地/局部索引,换句话说,本地/局部索引是需要手工创建的,而在Oracle中,这种索引是Oralce会自动创建。

create table t2 (
id number primary key,
t1_id number,
t2_date DATE)
partition by range (t2_date)
(
  partition part_01 values less than (to_date('2016-01-02','yyyy-mm-dd')),
  partition part_02 values less than (to_date('2016-01-03','yyyy-mm-dd')),
  partition part_03 values less than (to_date('2016-01-04','yyyy-mm-dd')),
  partition part_04 values less than (to_date('2016-01-05','yyyy-mm-dd'))
);

CREATE INDEX idx_t2 ON t2(t1_id) LOCAL;

INSERT INTO t2 VALUES(1, 1, to_date('2016-01-01','yyyy-mm-dd'));
INSERT INTO t2 VALUES(2, 1, to_date('2016-01-02','yyyy-mm-dd'));
INSERT INTO t2 VALUES(3, 1, to_date('2016-01-03','yyyy-mm-dd'));
INSERT INTO t2 VALUES(4, 1, to_date('2016-01-04','yyyy-mm-dd'));
COMMIT;

SELECT index_name,partition_name
from user_ind_partitions WHERE INDEX_name = 'IDX_T2';

以此类推,约束也是需要为每个分区手工创建,不是一劳永逸的事情。

接下来,我们为每个分区表新建外键约束:

alter table t2_part_01 add constraint fk_t2_part_01 foreign key(t1_id) references t1(id);

alter table t2_part_02 add constraint fk_t2_part_02 foreign key(t1_id) references t1(id);

alter table t2_part_03 add constraint fk_t2_part_03 foreign key(t1_id) references t1(id);

alter table t2_part_04 add constraint fk_t2_part_04 foreign key(t1_id) references t1(id);

再次删除T1表,

[SQL]delete from t1;

[Err] ERROR:  update or delete on table "t1" violates foreign key constraint "fk_t2_part_01" on table "t2_part_01"
DETAIL:  Key (id)=(1) is still referenced from table "t2_part_01".

此时返回的报错,就是主外键约束的问题了。

总结

1.从EDB分区表这个问题上,至少可以看出Oracle和EDB两种不同数据库在处理分区表上的区别,每个人都有他自己的看法,怎么设计可能都有他考虑的角度,可以说无所谓对错,只是在易用性和接受性方面会有不同。

2.要学会触类旁通,说起来容易做起来难,如果知道EDB分区索引需要手工建立,能不能想到外键约束亦是如此?这就是能不能理解数据库原理精髓的能力,至少我还欠缺着。

3.都说实践是检验真理的唯一标准,在Oracle的世界里,实践就是实验,纸上谈兵不能解决问题,实验过程中可能又会因为一个问题碰到另一个问题,也许这就是eygle一直所说的”由点及面“的学习方法,虽然有时会很痛苦,但会受益,至少不跟别人比,跟自己比是有提高的,也许这就够了,人的一生比来比去也就是一生,况且神人就是那么几位,大多数还是平凡之人,费了劲了还不及神人的一点功力,这里不是说就轻易放弃了,反正追不上,而是说要有豁达的胸怀,能为自己设立一个目标、一个榜样,即使现实中根本无法超越甚至赶上,但至少一直会提醒自己,他那么厉害,我差这么远,没有理由不努力,给自己暗示,就是让自己持续提高的动力,大家共勉。

时间: 2024-10-24 21:03:16

EDB分区表的又一个“坑”的相关文章

MySQL JDBC的queryTimeout的一个坑

遇到一个MySQL JDBC执行execute方法时指定queryTimeout的坑,比较恶心,算是它的BUG,也可以不算,^_^,为啥这么说?看一下下面的解释: 现象: 用同一个Connection执行大批量SQL的时候,导致了OOM现象. 细节现象描述: 1.SQL是从某个存储设备上拿到的,不会直接占用大量的内存,每次只会取最多1千条数据过去,也会判定容量不超过多少M. 2.每一批SQL执行会单独创建Statement对象,执行一批SQL后,会将这个Statement关闭掉. 3.SQL语句

罗永浩:每一个情怀都是一个坑

摘要: 今天下午两点半,罗永浩在北京发布了可能是最后一期一个理想主义者的创业故事的主题演讲,反思了自己进入手机市场之后的的创业经历.在发布会上,罗永浩把锤子科技两年来遇到 今天下午两点半,罗永浩在北京发布了可能是最后一期"一个理想主义者的创业故事"的主题演讲,反思了自己进入手机市场之后的的创业经历.在发布会上,罗永浩把"锤子科技"两年来遇到的为题归因于两点:供应链生产和与媒体关系. 每一个情怀都是一个坑 罗永浩回顾过去半年锤子手机Smartisan T1生产中遇到的

Javascript之旅——第八站:说说instanceof踩了一个坑

原文:Javascript之旅--第八站:说说instanceof踩了一个坑 前些天写js遇到了一个instanceof的坑,我们的页面中有一个iframe,我在index页面中计算得到了一个array,然后需要传递到Flight页面 这个嵌套的iframe中的一个函数(SearchFlight)中,作为防御性编程,我需要在SearchFlight函数中进行参数检测,也就是判断过来的参数一 定是Array类型.   一:抛出问题 举个例子,下面有两个页面. Index.html页面 1 <!DO

罗永浩疑似最后一场主题演讲:每一个情怀都是一个坑

罗永浩把"锤子科技"两年来遇到的问题归因于两点:供应链生产和与媒体关系.目前锤子手机的销量累计为 122063 部. 近日罗永浩在北京发布了可能是最后一场"一个理想主义者的创业故事"的主题演讲,反思了自己进入手机市场之后的的创业经历.在发布会上,罗永浩把"锤子科技"两年来遇到的问题归因于两点:供应链生产和与媒体关系. 每一个情怀都是一个坑 罗永浩回顾过去半年锤子手机 Smartisan T1 生产中遇到的问题,承认问题首先出在自己身上: 锤子手机

iOS 7 跳过的一个坑又掉里了 - 图片渲染模式

iOS 7 跳过的一个坑又掉里了 - 图片渲染模式 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. 导航栏按钮以及标签栏按钮的图片,在 iOS 7 中均会默认以蓝色渲染高亮,以灰色渲染正常状态颜

对象题目的一个坑 理解Javascript对象_javascript技巧

这一篇的例子,主要是来引起对Javascript对象的理解及注意的.其实是一种面试时的一个坑,实际项目中也是很少用得到,但是为了提高警惕性,我们来看这个例子: 代码名称 var first = {}; var second = {k:"second"}; var third = {k:"third"}; first[second] = 100; first[third] = 200; console.log(first[second])//这里会输出什么内容呢? 如

老罗最后的演讲:每一个情怀都是一个坑

今天下午两点半,罗永浩在北京发布了可能是最后一期"一个理想主义者的创业故事"的主题演讲,反思了自己进入手机市场之后的的创业经历.在发布会上,罗永浩把"锤子科技"两年来遇到的为题归因于两点:供应链生产和与媒体关系. 每一个情怀都是一个坑 罗永浩回顾过去半年锤子手机 T1 生产中遇到的问题,承认问题首先出在自己身上: 锤子手机的很多细节,还有一些小的元器件制造,之前钱晨博士都警告过我要考虑可行性和风险.能制造出来和能量产是两个概念.但是我那时候不以为然. 罗永浩当时在微

最近用Timer踩了一个坑,分享一下避免别人继续踩

最近做一个小项目,项目中有一个定时服务,需要向对方定时发送数据,时间间隔是1.5s,然后就想到了用C#的Timer类,我们知道Timer 确实非常好用,因为里面有非常人性化的start和stop功能,在Timer里面还有一个Interval,就是用来设置时间间隔,然后时间间隔到了就会触 发Elapsed事件,我们只需要把callback函数注册到这个事件就可以了,如果Interval到了就会触发Elapsed,貌似一切看起来很顺其自然,但是 有一点一定要注意,callback函数本身执行也是需要

StringUtils.isNumeric(String str) 的一个坑(转)

  在项目中遇到一处bug,调试的结果竟然是StringUtils.isNumeric(String str) 在捣鬼(采用的是org.apache.commons.lang.StringUtils),下面的代码是判断一个参数非空,且为整数: if(StringUtils.isNumeric(str) && StringUtils.isNotBlank(str)){ // do sth } 在简单不过的代码,却隐藏着bug ! 因为如果 str = "-1"; Stri