NULL-хранилище в Oracle

У меня есть таблица в Oracle 11g Standard One Edition:

таблица1

col1 col2 col3 col4 col5 col6 col7 col8       col9 col10 col11
1    NULL 2    3    4    5    NULL NULL       19   21    22
1    NULL 2    3    4    5    NULL 1 Jan 2009 19   21    22
1    NULL 2    3    4    5    NULL NULL       19   21    22
1    9    2    3    4    5    A    NULL       19   21    22
1    NULL 2    3    4    5    B    NULL       19   21    22

Таблица desc:

Name                 Null Type          
-------------------- ---- ------------- 
COL1                      NUMBER        
COL2                      NUMBER        
COL3                      NUMBER        
COL4                      NUMBER       
COL5                      NUMBER        
COL6                      NUMBER        
COL7                      VARCHAR2(255) 
COL8                      DATE          
COL9                      DATE  
COL10                     DATE        
COL11                     VARCHAR2(255) 

Мне нужно выяснить, какой процент хранения занимает таблица со значениями NULL?

Пример: потребляемая память в таблице 1 составляет 1 ГБ, а NULL внутри нее потребляет 100 МБ, поэтому NULL занимает 10% хранилища.

Кроме того, существуют ли альтернативные представления NULL в ORACLE?

Ответ 1

NULL в вашей таблице могут потреблять всего 1,75% пространства для хранения.

Но это число бессмысленно, хотя оно основано на воспроизводимом тестовом примере ниже. Более важно понять, что NULL являются крошечными (всего один байт). Настолько крошечный, что "реальный" размер должен быть неактуальным, за исключением крайних случаев. Настолько крошечный, что почти всегда пустая трата времени беспокоиться о альтернативных представлениях.


Самый лучший случай теста (использование пространства на практике)

Позвольте создать 1 ГБ данных, используя определение таблицы. Сначала создайте таблицу.

create table test1(
COL1  NUMBER,
COL2  NUMBER,
COL3  NUMBER,
COL4  NUMBER,
COL5  NUMBER,
COL6  NUMBER,
COL7  VARCHAR2(255),
COL8  DATE,
COL9  DATE,
COL10 DATE,
COL11 VARCHAR2(255)
) pctfree 0 /* Let assume no updates or deletes, and pack the data tightly */;

Теперь создайте один гигабайт данных. Каждое значение использует наибольшее возможное значение для этого типа данных.

begin
    for i in 1 .. 15 loop  --Magic number to generate exactly 1GB.
        insert into test1
        select
            .0123456789012345678901234567890123456789,
            .0123456789012345678901234567890123456789,
            .0123456789012345678901234567890123456789,
            .0123456789012345678901234567890123456789,
            .0123456789012345678901234567890123456789,
            .0123456789012345678901234567890123456789,
            lpad('A', 255, 'A'),
            sysdate,
            sysdate,
            sysdate,
            lpad('A', 255, 'A')
        from dual
        connect by level <= 95000;    --Magic number to generate exactly 1GB.
        commit;
    end loop;
end;
/

Эти запросы показывают, что он использует 1 ГБ пространства для 1,425,000 строк.

select count(*) from test1;
select bytes/1024/1024/1024 gb from user_segments where segment_name = 'TEST1';

Теперь создайте вторую таблицу с таким же количеством строк, но NULL в каждом столбце.

create table test1_null as
select col1+null c1, col2+null c2, col3+null c3, col4+null c4, col5+null c5, col6+null c6,
    cast(null as varchar2(255)) c7, col8+null c8, col9+null c9, col10+null c10,
    cast(null as varchar2(255)) c11
from test1;

Новый размер сегмента составляет всего 0,0175 ГБ, или 1,75%.

select bytes/1024/1024/1024 gb from user_segments where segment_name = 'TEST1_NULL';

Почему этот тестовый пример вводит в заблуждение

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

  • Данные переменной ширины. Большинство типов данных Oracle будут использовать только объем пространства, необходимый для хранения данных. Таким образом, процент хранения, используемого для этого байта NULL, зависит от того, что находится в других столбцах. Только несколько типов данных используют статический объем памяти независимо от данных, таких как CHAR, NCHAR, DATE, TIMESTAMP и т.д.
  • Конечные нули. Все последовательные NULL в конце строки хранятся в одном байте. Если базовое сжатие не включено, то каждый NULL снова использует байт.
  • Накладные расходы. Каждая строка имеет служебные данные, которые зависят от столбцов и конфигурации. Чем проще таблица, тем больше накладных расходов на строку использует пространство, поэтому процент, используемый NULL, будет колебаться.
  • Накладные расходы блока. Это зависит от количества строк, таких как PCTFREE, если предыдущие строки были удалены, когда последняя реорганизована таблица, размер блока и т.д.
  • Накладные расходы сегмента. Пространство выделяется как куски экстентов. Управление экстентом может использовать алгоритм по умолчанию (который, я думаю, выделяется в кусках от 1 МБ до 64 МБ), или это может быть любое пользовательское значение. Эти накладные расходы становятся менее значимыми в зависимости от объема данных. Возможно, табличное пространство установлено на огромный размер в размере, равный 10 ГБ, что, вероятно, будет тратить много места, независимо от значений столбца.
  • Другие служебные данные ввода-вывода. Пространство, вероятно, также потрачено впустую ASM, операционной системой, SAN и т.д.

Формат части строки (использование пространства в теории)

Ниже приведено изображение из главы "Структуры логических хранилищ" Руководства по концепциям:

введите описание изображения здесь

Данные столбца состоят из серии значений столбцов и значений столбцов. Если значение равно NULL, длина столбца равна 0, а значение столбца не использует пробел. Вот почему NULL всегда использует только 1 байт, для числа 0.

Большинство типов данных являются переменными, поэтому длина будет использовать не менее 1 байт, и значение будет использовать не менее 1 байт, если оно не равно NULL. Статические типы данных, такие как DATE, по-прежнему будут использовать 1 байт для длины, а затем 7 байтов для значения. Опять же, если дата не равна NULL, длина равна 0, а значение пусто.

Это изображение также может объяснить трюк хранения "trailing NULLs". Когда есть конечные нули, Oracle, вероятно, устанавливает число столбцов ниже, оставляет последнюю длину столбца равной 0 и указывает, что остальные столбцы также являются NULL.

Альтернативные представления?

Теперь я становлюсь подозрительным. Задавая вопрос об альтернативных представлениях NULL, вы узнаете о четырех видах людей:

  • Безнадежно теоретические люди, которые жалуются на нарушение реляционной модели и предлагают использовать неясные инструменты, а не те, которые работали отлично на протяжении десятилетий.
  • Архитектором данных, которые считают, что ginormous Entity-Attribute-Value table всегда является ответом. "Эй, он хорошо выглядит в моем PDF-документе, который заботится, невозможно ли запросить?"
  • Те, кто немного новичок в SQL и по праву разочарованы тем, как работают NULL.
  • Пользователям Stackoverflow, которые слишком много читают в вопросах. (Так что не стесняйтесь добавлять информацию на фоне этого вопроса, если я ухожу!)

Да, NULL немного странно. Но это будет иметь смысл в ближайшее время. Не беспокойтесь о пространстве или о том, как полностью избежать NULL. Цена, которую вы платите за NULL, ничто по сравнению с ценой, которую вы заплатите за анти-шаблоны, которые полностью избегают их.

Ответ 2

В первую очередь зависит от свойств таблицы (она разделена, индексы, тип данных, поля lob и т.д.), файловые системы и некоторые другие факторы. Раньше у меня была аналогичная задача для оракула 11. Вот шаги, которые я предпринял (не нужно было быть предельно точным из-за размера - в базе данных было более 3000 таблиц):

Мой алгоритм

  • Создайте копию таблицы без нулей (1000 записей);
  • Создать копию только с нулями (1000 записей);
  • Подсчитайте нули за столбец (это можно автоматизировать, чтобы проверить, какие столбцы имеют большее количество нулей)

    SELECT COUNT (*) FROM YourTable WHERE YourColumn IS NULL

  • Создайте копию только на основе последней меры (1000 записей);

Проанализируйте результаты.

надеюсь, что он вам поможет.

Примечание. По крайней мере, в моем случае целью было проанализировать использование и очистку базы данных.

Некоторые последующие чтения по этой теме:

Знают ли значения NULL пространство для хранения?

Как рассчитать размер строки в таблице?