Що таке накладні витрати для varchar (n)?


15

Я хотів запитати значення цього фрагмента у doc Postgres щодо varchar(n)типу:

Вимога зберігання для короткого рядка (до 126 байт) становить 1 байт плюс фактичний рядок, який включає пробіл у випадку символів. Більш довгі рядки мають 4 байти накладних, а не 1.

Припустимо, що у мене є varchar(255)поле. А тепер наступні твердження:

  • Якщо це поле містить рядок у 10 байт, то накладні дані - 1 байт. Так рядок буде використовувати 11 байт.
  • Якщо поле містить рядок, використовуючи 140 байт, то накладні витрати - 4 байти. Так рядок буде використовувати 144 байти.

Чи справді ці твердження вище? Тут хто - то розуміє док точно так же , як і я , але тут хто - то стверджує , накладні витрати завжди 4 байта тут ?

Відповіді:


19

Не дивно, що керівництво правильно. Але в цьому є більше.

Для одного розмір на диску (у будь-якій таблиці , навіть коли він фактично не зберігається на диску) може відрізнятися від розміру в пам'яті . На диску накладні витрати на короткі varcharзначення до 126 байт зменшуються до 1 байта, як зазначено в посібнику. Але накладні витрати в пам’яті завжди становлять 4 байти (після вилучення окремих значень).

Те ж саме відноситься і до text, varchar, varchar(n)абоchar(n) - за винятком того, що char(n)воно доповнюється пробілами до nсимволів і зазвичай не хочуть , щоб використовувати його. Його ефективний розмір все ще може змінюватись у багатобайтових кодуваннях, оскільки nпозначає максимум символів, а не байтів:

рядки довжиною до nсимволів (не байтів).

Всі вони використовують varlenaвнутрішньо.
"char"(з подвійними лапками) - інша істота і завжди займає один байт.
Нетипізовані рядкові літерали ( 'foo') мають один байт накладних витрат. Не плутати з набраними значеннями!

Тест с pg_column_size().

CREATE TEMP TABLE t (id int, v_small varchar, v_big varchar);
INSERT INTO t VALUES (1, 'foo', '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890');

SELECT pg_column_size(id)        AS id
     , pg_column_size(v_small)   AS v_small
     , pg_column_size(v_big)     AS v_big
     , pg_column_size(t)         AS t
FROM   t
UNION ALL  -- 2nd row measuring values in RAM
SELECT pg_column_size(1)
     , pg_column_size('foo'::varchar)
     , pg_column_size('12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890'::varchar)
     , pg_column_size(ROW(1, 'foo'::varchar, '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890'::varchar));

 id | v_small | v_big |  t
----+---------+-------+-----
  4 |       4 |   144 | 176
  4 |       7 |   144 | 176

Як ви можете бачити:

  • 3-байтовий рядок 'foo' займає 4 байти на диску і 7 байт в оперативній пам’яті (так 1 байт проти 4 байтів накладних витрат).
  • 140-байтовий рядок "123 ..." займає 144 байти як на диску, так і в оперативній пам'яті (так завжди 4 байти накладних витрат).
  • Зберігання integerне має накладних витрат (але воно має вимоги вирівнювання, які можуть накладати прокладки).
  • Рядок має додатковий наклад у 24 байти для заголовка кортежу (плюс додаткові 4 байти на кортеж для вказівника елемента в заголовку сторінки).
  • І останнє, але не менш важливо: накладні витрати на малий varcharдосі становлять лише 1 байт, поки він не був витягнутий з рядка - як видно з розміру рядка. (Тому іноді трохи швидше вибирати цілі рядки.)

Пов'язані:


1
Це 1 байт накладних витрат все ще 1 байт в індексі?
двтан

1
@dtgq: Індекс зберігає дані так само, як таблицю, так що так.
Ервін Брандстеттер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.