Oracle - подход ежедневного разбиения хорош для таблицы с миллионами строк - PullRequest
1 голос
/ 16 июня 2020

Я работаю над существующей таблицей, содержащей миллионы строк данных с точки зрения истории розничных транзакций. схема выглядит так:

create table History(
hid number(19,0),
type varchar2(255 char),
lastupdated timestamp (6) not null enable,
name varchar2(255 char),
primary key (hid))
partition by range (lastupdated) interval (numtodsinterval(1,'day'))
(partition retailhistory values less than (to_timestamp('12/01/2020','DD/MM/YYYY')));

Приведенная выше таблица разбита на разделы на основе интервалов между днями, поэтому в год будет 365 разделов, состоящих из миллионов строк. Мы планируем создать задание очистки, но до тех пор можно будет иметь такое количество разделов в таблице и приведет ли это к снижению производительности по сравнению с таблицей без разделов?

Любая помощь будет принята с благодарностью. Спасибо. :)

1 Ответ

1 голос
/ 18 июня 2020

В зависимости от вашего определения «миллионов», ежедневное разбиение на разделы может быть слишком детальным и может вызвать проблемы с производительностью при чтении данных.

Каждый раздел физически хранится как таблица и имеет разные накладные расходы - наиболее важно накладные расходы для выделения пространства сегмента. Oracle почти никогда не выделяет точно , сколько места необходимо, всегда есть немного лишнего. Если вы создаете большое количество крошечных разделов, эта «небольшая дополнительная» может быть больше, чем фактические данные.

В моем тестовом примере, приведенном ниже, предполагается, что 5 миллионов строк в год и относительно небольшое значение в каждом из столбцы, ежедневное разбиение использует в десять раз больше пространства сегментов, чем ежемесячное. Это означает, что ежедневное разбиение будет оптимальным для выбора данных за один день, но будет ужасным для выбора данных за несколько дней. А поскольку полное сканирование таблицы / раздела использует многоблочное чтение и в любом случае считывает мегабайты данных за раз, чтение данных за целый месяц в любом случае может быть не намного медленнее, чем чтение данных за день.

Пример схемы

Создайте три таблицы для ежедневного, ежемесячного и без разбиения. Загрузите 5 миллионов строк равномерно в каждый из 365 дней, а затем проверьте размеры сегментов.

  • Ежедневное разбиение использует 2920 мегабайт для 365 сегментов.
  • Ежемесячное разбиение использует 288 мегабайт для 13 сегментов.
  • Без разбиения на 1 сегмент используется 280 мегабайт.

Код:

----------------------------------------
--DAY
----------------------------------------

create table History_day(
hid number(19,0),
type varchar2(255 char),
lastupdated timestamp (6) not null enable,
name varchar2(255 char),
primary key (hid))
partition by range (lastupdated) interval (numtodsinterval(1,'day'))
(partition retailhistory values less than (to_timestamp('12/01/2020','DD/MM/YYYY')));

create sequence history_day_seq;

begin
    for i in 1 .. 365 loop
        for j in 1 .. 13698 loop
            insert into history_day values(history_day_seq.nextval, 'some type value', date '2020-12-01' + i, 'some name value');
        end loop;
    end loop;
    commit;
end;
/

select sum(bytes)/1024/1024 mb, count(*) partition_count from dba_segments where segment_name = 'HISTORY_DAY';


----------------------------------------
--MONTH: 288 megabytes for 13 partitions.
----------------------------------------

create table History_month(
hid number(19,0),
type varchar2(255 char),
lastupdated timestamp (6) not null enable,
name varchar2(255 char),
primary key (hid))
partition by range (lastupdated) interval (numtoyminterval(1,'month'))
(partition retailhistory values less than (to_timestamp('12/01/2020','DD/MM/YYYY')));

create sequence history_month_seq;

begin
    for i in 1 .. 365 loop
        for j in 1 .. 13698 loop
            insert into history_month values(history_month_seq.nextval, 'some type value', date '2020-12-01' + i, 'some name value');
        end loop;
    end loop;
    commit;
end;
/

select sum(bytes)/1024/1024 mb, count(*) partition_count from dba_segments where segment_name = 'HISTORY_MONTH';


----------------------------------------
--NO PARTITIONS
----------------------------------------

create table History(
hid number(19,0),
type varchar2(255 char),
lastupdated timestamp (6) not null enable,
name varchar2(255 char),
primary key (hid));

create sequence history_seq;

begin
    for i in 1 .. 365 loop
        for j in 1 .. 13698 loop
            insert into history values(history_seq.nextval, 'some type value', date '2020-12-01' + i, 'some name value');
        end loop;
    end loop;
    commit;
end;
/

select sum(bytes)/1024/1024 mb, count(*) partition_count from dba_segments where segment_name = 'HISTORY';

Применимы ли эти результаты к вам?

Есть большая вероятность, что ваши результаты будут разными в вашей системе, в зависимости от ваших данных и того, как ваша система распределяет сегменты. Важно то, что вы должны сами провести такой тест. И имейте в виду, что разделы предназначены для «больших» объемов данных, но слово «большой» явно субъективно.

Ежедневное разбиение на разделы идеально подходит для многих больших таблиц, но я чувствую, что ваша таблица будет лучше работать с разбиением по месяцам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...