Ami*_*deh 5 oracle partitioning
Oracle 在 DDL 查询中支持波斯 (Jalali) 日历,我可以轻松地说:
select to_char(register_date, 'YYYY-MM-DD', 'nls_calendar=persian')
from my_table;
Run Code Online (Sandbox Code Playgroud)
我创建了一个表:
create table test_temp_times (
id number(18) not null,
xdate date not null,
str varchar2(20))
partition by range(xdate)
interval(NUMTOYMINTERVAL(1, 'MONTH'))
(partition p0 values less than (to_date('13920101', 'YYYYMMDD', 'nls_calendar=persian')))
enable row movement;
Run Code Online (Sandbox Code Playgroud)
该表正常创建,但是当我向其中添加记录时,oracle 创建新分区时,分区为:
create table TEMP_TIMES (
id NUMBER(18) not null,
xdate DATE not null,
str VARCHAR2(20)
)
partition by range (XDATE)
(
partition P0 values less than (TO_DATE(' 2013-03-21 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')),
partition SYS_P61 values less than (TO_DATE(' 2013-04-21 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')),
partition SYS_P62 values less than (TO_DATE(' 2013-05-21 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')),
partition SYS_P63 values less than (TO_DATE(' 2013-06-21 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')),
partition SYS_P64 values less than (TO_DATE(' 2013-07-21 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')));
Run Code Online (Sandbox Code Playgroud)
如您所见,数据库将 NLS_CALENDAR 更改为gregorian(与 13920101 同一天),并且每个分区都是根据gregorian日历创建的,而不是persian日历。
有什么办法可以强制 Oracle 使用波斯日历来创建新分区?
我没有看到任何方法可以在与数据库级 NLS_CALENDAR 不同的日历中定义间隔。您可以通过使用虚拟列对每个日期所属的(波斯)月份的数字表示进行分区来获得相同的效果:
create table test_temp_times (
id number(18) not null,
xdate date not null,
str varchar2(20),
ydate as (to_number(to_char(xdate, 'YYYYMM', 'nls_calendar=persian')))
)
partition by range(ydate)
interval(1)
(partition p0 values less than (139201))
enable row movement;
Run Code Online (Sandbox Code Playgroud)
如果在您的示例开始日期之后的那一年的每一天都填充了一条记录:
insert into test_temp_times (id, xdate, str)
select level, date '2013-03-20' + level, null
from dual
connect by level < 366;
Run Code Online (Sandbox Code Playgroud)
创建的分区将类似于:
select table_name, partition_name, high_value
from user_tab_partitions where table_name = 'TEST_TEMP_TIMES';
TABLE_NAME PARTITION_NAME HIGH_VALUE
------------------------------ ------------------------------ ----------
TEST_TEMP_TIMES P0 139201
TEST_TEMP_TIMES SYS_P479 139202
TEST_TEMP_TIMES SYS_P480 139203
TEST_TEMP_TIMES SYS_P481 139204
TEST_TEMP_TIMES SYS_P482 139205
TEST_TEMP_TIMES SYS_P483 139206
TEST_TEMP_TIMES SYS_P484 139207
TEST_TEMP_TIMES SYS_P485 139208
TEST_TEMP_TIMES SYS_P486 139209
TEST_TEMP_TIMES SYS_P487 139210
TEST_TEMP_TIMES SYS_P488 139211
TEST_TEMP_TIMES SYS_P489 139212
TEST_TEMP_TIMES SYS_P490 139213
13 rows selected
Run Code Online (Sandbox Code Playgroud)
您可以检查月份边界属于哪些分区:
select utp.partition_name, min(ttt.xdate), max(ttt.xdate)
from test_temp_times ttt
join user_objects uo on uo.object_id = dbms_rowid.rowid_object(ttt.rowid)
join user_tab_partitions utp on utp.table_name = uo.object_name
and utp.partition_name = uo.subobject_name
group by utp.partition_name
order by partition_name;
PARTITION_NAME MIN(TTT.XDATE) MAX(TTT.XDATE)
------------------------------ -------------- --------------
P0 2013-03-20 2013-03-20
SYS_P479 2013-03-21 2013-04-20
SYS_P480 2013-04-21 2013-05-21
SYS_P481 2013-05-22 2013-06-21
SYS_P482 2013-06-22 2013-07-22
SYS_P483 2013-07-23 2013-08-22
SYS_P484 2013-08-23 2013-09-22
SYS_P485 2013-09-23 2013-10-22
SYS_P486 2013-10-23 2013-11-21
SYS_P487 2013-11-22 2013-12-21
SYS_P488 2013-12-22 2014-01-20
SYS_P489 2014-01-21 2014-02-19
SYS_P490 2014-02-20 2014-03-19
Run Code Online (Sandbox Code Playgroud)
至少,我认为这就是你想要实现的......不幸的是我无法添加演示,因为 SQL Fiddle 没有分区选项,但这是针对 11.2.0.3 进行的测试。
当然,你必须让它使用查询的分区......如果我只是这样做:
select * from test_temp_times
where xdate = date '2013-11-01';
Run Code Online (Sandbox Code Playgroud)
它找到具有计划的行:
-----------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 47 | 164 (0)| 00:00:02 | | |
| 1 | PARTITION RANGE ALL| | 1 | 47 | 164 (0)| 00:00:02 | 1 |1048575|
|* 2 | TABLE ACCESS FULL | TEST_TEMP_TIMES | 1 | 47 | 164 (0)| 00:00:02 | 1 |1048575|
-------------------------------------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)
如果我将虚拟列显式添加到查询中:
select * from test_temp_times
where xdate = date '2013-11-01'
and ydate = to_number(to_char(date '2013-11-01', 'YYYYMM', 'nls_calendar=persian'));
Run Code Online (Sandbox Code Playgroud)
然后它知道要查询哪个分区:
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 47 | 14 (0)| 00:00:01 | | |
| 1 | PARTITION RANGE SINGLE| | 1 | 47 | 14 (0)| 00:00:01 | 9 | 9 |
|* 2 | TABLE ACCESS FULL | TEST_TEMP_TIMES | 1 | 47 | 14 (0)| 00:00:01 | 9 | 9 |
----------------------------------------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)
显然我还没有创建任何索引。如果您要查找整月的数据,则只需查询单个ydate值,而忽略xdate; 但据推测,您至少在某些时候需要混合。
| 归档时间: |
|
| 查看次数: |
3050 次 |
| 最近记录: |