Создание таблицы разделов диапазона с большим количеством разделов

мне нужно создать таблицу с разделением по диапазону с двумя сотнями разделов. например:

CREATE TABLE emp (
     empno NUMBER(4), 
     ename VARCHAR2(30), 
     sal   NUMBER
) 
PARTITION BY RANGE(empno) (
partition e1 values less than (1000)     , 
partition e2 values less than (2000)     , 
...
partition e200 values less than (MAXVALUE) 

);

Есть ли способ указать интервал диапазона без написания двухсот строк только для указания диапазона?


person subodh1989    schedule 31.10.2012    source источник
comment
Какую версию Oracle вы используете? Если 11g, то вам действительно следует использовать интервальное разбиение, которое сделает всю работу за вас. Просто будьте осторожны, чтобы иметь ограничения на ваши данные, чтобы ошибочное большое значение не заставляло Oracle создавать ненужные разделы.   -  person Colin 't Hart    schedule 31.10.2012


Ответы (2)


CREATE TABLE emp (
     empno NUMBER(4), 
     ename VARCHAR2(30), 
     sal   NUMBER
) 
PARTITION BY RANGE(empno) (
partition e1 values less than (1000));

begin
  for k in 2..200 
  loop
     execute immediate 
       'alter table emp add partition e'||k||' values less than  ('||k*1000||')';
  end loop
end;

ОБНОВЛЕНИЕ: в версии 11g существует функция указания интервала для разделов диапазона, и разделы будут создаваться при вставке в таблицу.

Но мне это не нравится, и я не рекомендую это по двум причинам:

1 Вы всегда должны сохранять первый раздел, потому что это ссылка. Если вы попытаетесь бросить его, вы получите SQL Error: ORA-14758: Last partition in the range section cannot be dropped;

2 У вас нет контроля над именами разделов (AFAIK), и интервалом (это уродливо). Если вы по ошибке вставите значение в будущем, некоторые разделы будут пропущены, и вы получите толстые разделы: (немного изучил, и толстого раздела нет. Добавлено в пример.)

 Create table Z_TB_PART_TEST(
    id number
  )
  partition by range(id)
  interval(1000)
 (
    PARTITION PART_01 VALUES LESS THAN (1000)
 );  

 INSERT INTO Z_TB_PART_TEST values (1500);
 INSERT INTO Z_TB_PART_TEST VALUES (10000);
 INSERT INTO Z_TB_PART_TEST VALUES (5000);


  SELECT partition_name , high_value
  FROM USER_TAB_PARTITIONS
  WHERE table_name = 'Z_TB_PART_TEST';

  PART_01   1000
  SYS_P141  2000
  SYS_P142  11000
  SYS_P143  6000

ОБНОВЛЕНИЕ 2: Николай Краснов указал в комментарии обходной путь для первого пункта:

А как насчет ORA-14758? Этого можно легко избежать: мы временно преобразуем нашу таблицу интервального разбиения в таблицу разбиения по диапазонам (alter table tb_table_test set interval()), удаляем раздел и затем переключаемся обратно на таблицу разбиения по интервалам (alter table tb_part_test set interval(1000)).

Работает, я проверял. Однако следует отметить, что все разделы будут заморожены, они будут разделами диапазона. Если у вас были промежутки, останутся (в промежутках не будет добавлен раздел). Таким образом, эталонный раздел будет последним перед изменением на interval. Вот что говорит ошибка: Last partition in the range section cannot be dropped.

Таким образом, у вас будет раздел диапазонного разбиения и раздел интервального разбиения со всеми его преимуществами.

person Florin Ghita    schedule 31.10.2012
comment
В качестве быстрой заметки. Чтобы сохранить тип разбиения, мы можем обрезать раздел, от которого хотим избавиться, а затем объединить его со следующим. В зависимости от размера разделов может быть много повторов. - person Nick Krasnov; 01.11.2012

Вы не сказали, какую версию Oracle вы используете, но если окажется, что ваша версия Oracle 11g, тогда есть предложение INTERVAL оператора CREATE TABLE, которое позволит вам установить интервальное разбиение таблицы. Вот пример:

SQL> Create table TB_PART_TEST(
  2    id number
  3  )
  4  partition by range(id)
  5  interval(1000)
  6  (
  7    partition Part_01 values less than (1000)
  8  );  

 table created

 SQL> select partition_name
   2       , high_value
   3    from user_tab_partitions
   4   where table_name = 'TB_PART_TEST';



PARTITION_NAME  HIGH_VALUE
 ------------------------------
  PART_01           1000 


  SQL> insert into TB_PART_TEST(id)
    2    values(1500); 

  1 row created

  SQL> commit;

  commit complete

  SQL> select partition_name
   2       , high_value
   3    from user_tab_partitions
   4   where table_name = 'TB_PART_TEST';

  PARTITION_NAME  HIGH_VALUE
 ------------------------------
  PART_01           1000 
  SYS_P63           2000
person Nick Krasnov    schedule 31.10.2012
comment
Я хотел ответить тем же! Если вы используете 11g, это определенно путь. Также ознакомьтесь с превосходным обзором Тима Холла по секционированию, в котором содержится информация об интервальном секционировании: oracle-base.com/articles/11g/ - person Colin 't Hart; 31.10.2012
comment
я использую oracle 10g... у меня есть этот метод 11g, но я не могу использовать его на производственной машине.. - person subodh1989; 31.10.2012
comment
Я знаю об этой функции, но она мне не нравится (или недостаточно протестирована). По двум причинам. Я обновлю свой ответ через несколько минут. - person Florin Ghita; 01.11.2012
comment
Я немного изучил и больше не ненавижу этот тип разбиения, потому что обнаружил, что он создает разделы между промежутками. Теперь это приемлемый тип разбиения. :) - person Florin Ghita; 01.11.2012
comment
@FlorinGhita Да, Флорин, одним из недостатков является автоматическое присвоение имен разделам. А как насчет ORA-14758? Этого можно легко избежать: мы временно преобразуем нашу таблицу интервального разбиения в таблицу разбиения по диапазонам (alter table tb_table_test set interval()), удаляем раздел и затем переключаемся обратно на таблицу разбиения по интервалам (alter table tb_part_test set interval(1000). - person Nick Krasnov; 01.11.2012