Как это не делает varchar2 неэффективным? - PullRequest
3 голосов
/ 11 августа 2010

Предположим, у меня есть таблица со столбцом name varchar(20), и я храню строку с именем = "abcdef".

INSERT INTO tab(id, name) values(12, 'abcdef');

Как в этом случае выполняется выделение памяти для name?

Есть два способа, которыми я могу думать:

а)

20 байтов выделено, но используется только 6. В этом случае varchar2 не имеет каких-либо существенных преимуществ перед char в плане выделения памяти.

б)

Выделено только 6 байтов. Если это так, и я добавил еще несколько строк после этого,

INSERT INTO tab(id, name) values(13, 'yyyy');
INSERT INTO tab(id, name) values(14, 'zzzz');

а потом я ОБНОВЛЯЮ,

UPDATE tab SET name = 'abcdefghijkl' WHERE id = 12;

Откуда СУБД получает дополнительные 6 байтов, необходимые? Может случиться так, что следующие 6 байтов не будут свободными (если изначально было выделено только 6 байтов, то для каких-то следующих байтов могло бы быть выделено что-то еще) еще).

Есть ли другой способ, кроме как перенести ряд на новое место? Даже сдвиг будет проблемой в случае таблиц с индексами (это может быть хорошо для таблиц с кучей).

Ответы [ 5 ]

1 голос
/ 12 августа 2010

Учитывая VARCHAR2 в названии вопроса, я предполагаю, что ваш вопрос сосредоточен на Oracle. В Oracle вы можете зарезервировать пространство для расширения строк в блоке данных с помощью предложения PCTFREE. Это может помочь смягчить последствия обновлений, делающих строки длиннее.

Однако, если у Oracle недостаточно свободного места в блоке для обратной записи строки, это называется миграцией строк; он оставляет исходный адрес только на диске (поэтому не обязательно обновлять индексы), но вместо того, чтобы хранить данные в исходном местоположении, он сохраняет указатель на новый адрес этой строки.

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

1 голос
/ 11 августа 2010

Вероятно, это сильно зависит от базы данных.

Пара моментов: MVCC Наблюдение за базами данных фактически не обновляет данные на диске или в кэше памяти. Они вставляют новую строку с обновленными данными и помечают старую строку как удаленную из определенной транзакции. Через некоторое время удаленная строка не видна ни для каких транзакций, и она возвращается.

Что касается места в хранилище, обычно оно имеет вид 1-4 bytes of header + data (+ padding)

В случае символов данные дополняются до достаточной длины. В случае varchar или текста в заголовке хранится длина следующих данных.

1 голос
/ 11 августа 2010

Редактировать Почему-то я думал, что это было помечено Microsoft SQL Server. Я думаю, что ответ все еще актуален, хотя

Вот почему официальная рекомендация равна

  • Используйте символ, если размеры записей данных столбца совпадают.
  • Используйте varchar, когда размеры записей данных столбца значительно различаются.
  • Использовать varchar (max), когда размеры записей данных столбца варьируются значительно, и размер может превышать 8 000 байт.

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

Стоит отметить, что для char значение NULL по-прежнему использует все пространство памяти. Для Management Studio есть надстройка Средство просмотра SQL , которая позволяет легко увидеть, как хранятся ваши строки.

1 голос
/ 11 августа 2010

Могут быть различия в зависимости от используемых вами rdbms, но обычно:

Выделяются только фактические данные, которые вы храните в поле varchar.Размер только максимально допустимый, но не столько, сколько выделено.

Я думаю, что это также относится к полям char в некоторых системах.Типы данных переменного размера обрабатываются достаточно эффективно, так что больше нет никакого выигрыша в распределении максимума.

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

1 голос
/ 11 августа 2010

Это определенно не выделяет больше места, чем необходимо, это лишило бы смысла использование типа переменной длины.

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

...