如果指定没有时间组件的日期值,则为默认值 时间是午夜。如果您指定的日期值没有日期,那么 默认日期是当月的第一天。
Oracle DATE列始终包含日期和时间的字段。如果 您的查询使用没有时间部分的日期格式,那么您必须 确保DATE列中的时间字段设置为午夜。
解决方案是在日期数据类型的列上设置约束,并在表中插入或更新行时创建一个触发器(带TRUNC()
)。
如果我使用此解决方案,我是否有保证,Oracle确实会为没有时间的日期存储更少的字节数?
使用此标准日期时间类型Oracle会产生歧义。创建日期类型(仅包含日期)非常困难?这是我的观点(我来自MSSQL)。
答案 0 :(得分:7)
不,你没有任何保证......无论发生什么事情,甲骨文都会存储午夜的事实。您无法存储没有时间的日期。
如果您创建下表:
create table a ( dt date);
insert into a values(sysdate);
insert into a values(trunc(sysdate));
然后运行此查询:
select dt, dump(dt) from a
返回的值是:
+-----------------------------+------------------------------------+ | DT | DUMP(DT) | +-----------------------------+------------------------------------+ | June, 12 2013 18:03:15+0000 | Typ=12 Len=7: 120,113,6,12,19,4,16 | | June, 12 2013 00:00:00+0000 | Typ=12 Len=7: 120,113,6,12,1,1,1 | +-----------------------------+------------------------------------+
DUMP()
返回数据类型,字节长度和数据的内部表示。
换句话说,带有时间的日期和截断的日期都有7个字节。它们的长度相同。
稍微偏离一点,我会建议不要破坏可能有用的数据,因为你担心空间。
答案 1 :(得分:1)
如果使用table compression,只存储日期可以节省空间。
这是一个示例,显示只存储日期可以减少段大小:
create table a (dt date) compress;
create table b (dt date) compress;
--Insert 20 million rows, with time
begin
for i in 1 .. 20 loop
insert /*+ append */ into a
select sysdate + numToDSInterval(level, 'second')
from dual connect by level <= 1000000;
commit;
end loop;
end;
/
--Insert 20 million rows, date only
begin
for i in 1 .. 20 loop
insert /*+ append */ into b
select trunc(sysdate + numToDSInterval(level, 'second'))
from dual connect by level <= 1000000;
commit;
end loop;
end;
/
select segment_name, bytes/1024/1024 MB
from dba_segments
where segment_name in ('A', 'B')
order by segment_name;
SEGMENT_NAME MB
------------ --
A 256
B 224
Oracle基本表压缩仅压缩整个值,如果有较少的不同值,则压缩可以更好地工作。但永远不要完全相信任何压缩演示 - 您需要在自己的数据上尝试它才能确定。这可能是最好的情况,压缩可能根本无法帮助您的数据。
表压缩有许多缺点 - 它需要企业版,DML较慢,不能向表中添加列等。
此外,正如Ben建议的那样,您应该使用检查约束而不是触发器来强制执行仅限日期的规则。它将更简单,更快速,并且不会阻止直接路径写入,这是使用基本表压缩所必需的。