PostgreSQL: різниця між текстом і варшаром (характер змінюється)


619

Яка різниця між textтипом даних та типом даних character varying( varchar)?

Відповідно до документації

Якщо зміна символів використовується без специфікатора довжини, тип приймає рядки будь-якого розміру. Останнє є розширенням PostgreSQL.

і

Крім того, PostgreSQL надає текстовий тип, який зберігає рядки будь-якої довжини. Хоча текст типу не входить у стандарт SQL, його мають і деякі інші системи управління базами даних SQL.

То яка різниця?

Відповіді:


745

Там немає ніякої різниці, під капотом все це varlena( масив змінної довжини ).

Перегляньте цю статтю від Depesz: http://www.depesz.com/index.php/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text/

Кілька важливих моментів:

Підсумовуючи все це:

  • char (n) - займає занадто багато місця при роботі зі значеннями, меншими за n(прокладки їх n), і може призвести до тонких помилок через додавання пробілів, плюс змінити обмеження проблематично
  • varchar (n) - змінити ліміт у прямому середовищі проблематично (вимагає ексклюзивного блокування під час зміни таблиці)
  • варчар - так само, як текст
  • текст - для мене переможець - понад (n) типів даних, тому що у них відсутні проблеми, а над varchar - тому що він має чітку назву

У статті робиться детальне тестування, щоб показати, що продуктивність вставлень та вибору для всіх 4 типів даних однакова. Він також детально розглядає альтернативні способи обмеження довжини при необхідності. Обмеження або домени на основі функцій забезпечують перевагу миттєвого збільшення обмеження довжини, і виходячи з того, що зменшення обмеження довжини рядка зустрічається рідко, Депес робить висновок, що один з них, як правило, є найкращим вибором для обмеження довжини.


58
@axiopisty Це чудова стаття. Ви можете просто сказати: "Чи можете ви взяти якісь уривки, якщо стаття коли-небудь знизиться?" Я спробував коротко узагальнити зміст / висновки статті. Сподіваюся, цього достатньо, щоб полегшити ваші занепокоєння.
jpmc26

34
@axiopisty, строго кажучи, початкова відповідь сказала " під кришкою все варлена ", що, безумовно, корисна інформація, яка відрізняє цю відповідь від відповіді, що стосується лише посилання.
Бруно

24
Одне, що потрібно пам’ятати з безмежною струною, - це те, що вони відкривають можливість зловживань. Якщо ви дозволяєте користувачеві мати прізвище будь-якого розміру, у вас може бути хтось зберігає ВЕЛИКИЙ обсяг інформації у вашому полі прізвища. У статті про розвиток reddit вони дають пораду "Покласти обмеження на все".
Марк Хільдрет

7
@MarkHildreth Хороший момент, хоча загалом такі обмеження виконуються далі у додатку сьогодні - так що правилами (і спробами порушень / повторних спроб) можна безперешкодно керувати користувальницьким інтерфейсом. Якщо хтось все ще хоче робити подібні речі в базі даних, він може використовувати обмеження. Див. Blog.jonanin.com/2013/11/20/postgresql-char-varchar, який містить "приклад використання TEXT та обмежень для створення полів з більшою гнучкістю, ніж VARCHAR".
Ітан

4
@Ethan blog.jonanin.com/2013/11/20/postgresql-char-varchar -> Це знищено, але знайдено тут archive.is/6xhA5 .
MrR

115

Як « типажі » в точках документації з, varchar(n), char(n), і textзберігаються всі точно так же. Єдина відмінність - додаткові цикли потрібні для перевірки довжини, якщо вона дана, і додатковий простір та час, необхідні для оббивки char(n).

Однак, коли вам потрібно зберігати лише один символ, є незначна перевага у виконанні використання спеціального типу "char"(зберігайте подвійні лапки - вони є частиною назви типу). Ви отримуєте швидший доступ до поля, і немає накладних витрат, щоб зберігати довжину.

Щойно я склав таблицю з 1 000 000 випадкових випадків, "char"вибраних з малих букв. Запит на отримання розподілу частоти ( select count(*), field ... group by field) займає близько 650 мілісекунд проти 760 за тими ж даними за допомогою textполя.


18
технічно котирування не входять до назви типу. вони потрібні для того, щоб відрізняти його від ключового слова char.
Ясен

31
Технічно ви праві @Jasen ... Що, звичайно, є найкращим видом правильного
JohannesH

тип даних "char" не char?? Це дійсно в наші дні PostgreSQL 11+? ... Так: "Тип "char"(зверніть увагу на лапки) відрізняється від char (1) тим, що він використовує лише один байт сховища. Він використовується внутрішньо в системних каталогах як спрощений тип перерахування ." , керівництво / тип даних-характер .
Пітер Краусс

63

ОНОВЛЕННЯ БЕНХАРКІВ НА 2016 рік (pg9,5 +)

І з використанням "чистого SQL" орієнтирів (без зовнішнього сценарію)

  1. використовувати будь-який string_generator з UTF8

  2. основні орієнтири:

    2.1. ВСТУПИТИ

    2.2. ВИБІРТЕ порівняння та підрахунок


CREATE FUNCTION string_generator(int DEFAULT 20,int DEFAULT 10) RETURNS text AS $f$
  SELECT array_to_string( array_agg(
    substring(md5(random()::text),1,$1)||chr( 9824 + (random()*10)::int )
  ), ' ' ) as s
  FROM generate_series(1, $2) i(x);
$f$ LANGUAGE SQL IMMUTABLE;

Підготуйте конкретний тест (приклади)

DROP TABLE IF EXISTS test;
-- CREATE TABLE test ( f varchar(500));
-- CREATE TABLE test ( f text); 
CREATE TABLE test ( f text  CHECK(char_length(f)<=500) );

Проведіть базовий тест:

INSERT INTO test  
   SELECT string_generator(20+(random()*(i%11))::int)
   FROM generate_series(1, 99000) t(i);

І інші тести,

CREATE INDEX q on test (f);

SELECT count(*) FROM (
  SELECT substring(f,1,1) || f FROM test WHERE f<'a0' ORDER BY 1 LIMIT 80000
) t;

... І використовувати EXPLAIN ANALYZE.

ОНОВЛЕНО ПРОТИ 2018 (стор. 10)

трохи редагувати, щоб додати результати 2018 року та посилити рекомендації.


Результати у 2016 та 2018 роках

Мої результати, в середньому, на багатьох машинах і в багатьох тестах: все одно
(статистично менше стандартного відхилення).

Рекомендація

  • Використовуйте textтип даних,
    уникайте старих, varchar(x)оскільки іноді це не є стандартом, наприклад, у CREATE FUNCTIONпунктах varchar(x)varchar(y) .

  • виражати обмеження (з однаковою varcharефективністю!) за допомогою CHECKпункту CREATE TABLE
    напр CHECK(char_length(x)<=10).
    Маючи незначну втрату продуктивності в INSERT / UPDATE, ви також можете контролювати діапазони та структуру рядків,
    наприкладCHECK(char_length(x)>5 AND char_length(x)<=20 AND x LIKE 'Hello%')


Тож неважливо, що я зробив усі мої колонки варчаром замість тексту? Я не уточнив довжину, хоча деякі лише 4 - 5 символів і, звичайно, не 255.
траншея

1
@trench так, це не має значення
FuriousFolder

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

@trench і читач: єдиним винятком є ​​швидший тип даних "char", якого немає char, навіть в наші дні PostgreSQL 11+. Як говорить посібник / характер типу даних, "Тип "char"(зверніть увагу на лапки) відрізняється від char (1) тим, що він використовує лише один байт сховища. Він використовується внутрішньо в системних каталогах як спрощений тип перерахування ." .
Пітер Краус

3
все ще діє з pg11 у 2019 році: текст> varchar (n)> text_check> char (n)
Олів'є Рефало

37

У посібнику PostgreSQL

Немає різниці в продуктивності між цими трьома типами, окрім збільшення місця на зберігання при використанні пустого типу та декількох додаткових циклів процесора для перевірки довжини під час зберігання в стовпчику з обмеженою довжиною. Хоча персонаж (n) має переваги у роботі в деяких інших системах баз даних, у PostgreSQL такої переваги немає; насправді персонаж (n), як правило, найповільніший з трьох через його додаткові витрати на зберігання. У більшості ситуацій замість цього слід використовувати текст чи символи, що змінюються.

Я зазвичай використовую текст

Посилання: http://www.postgresql.org/docs/current/static/datatype-character.html


23

На мою думку, varchar(n)це має свої переваги. Так, всі вони використовують один і той же базовий тип і все таке. Але, слід зазначити, що індекси в PostgreSQL мають обмеження розміру 2712 байт на рядок.

TL; DR: Якщо ви використовуєте textтип без обмежень і маєте індекси в цих стовпцях, цілком можливо, що ви досягнете цього обмеження для деяких своїх стовпців і отримаєте помилку при спробі вставки даних, але при використанні varchar(n)ви можете це запобігти.

Ще кілька деталей: Проблема тут полягає в тому, що PostgreSQL не дає жодних винятків при створенні індексів для textтипу або varchar(n)там, де nвін перевищує 2712. Однак він помилиться при спробі вставки запису зі стислим розміром більше 2712. Це означає, що ви можете легко вставити 100 000 символів рядка, який складається з повторюваних символів, тому що він буде стиснений далеко нижче 2712, але ви, можливо, не зможете вставити рядок з 4000 символів, оскільки стислий розмір перевищує 2712 байт. Використовуючи varchar(n)там, де nне занадто багато, ніж 2712, ви захищені від цих помилок.


Пізніші помилки постгресу при спробі створення індексації тексту працює лише для varchar (версія без (n)). Проте протестовано лише з вбудованими постгресами.
arntg

2
Посилаючись на: stackoverflow.com/questions/39965834/…, який має посилання на PostgreSQL Wiki: wiki.postgresql.org/wiki/… має максимальний розмір рядка як 400 Гб, тому виглядає, що заявлений обмеження в 2712 байтах для рядка невірно . Максимальний розмір для бази даних? необмежений (існує 32 бази даних ТБ) Максимальний розмір таблиці? 32 ТБ Максимальний розмір для ряду? 400 ГБ Максимальний розмір поля? 1 ГБ Максимальна кількість рядків у таблиці? необмежено
Білл Уортінгтон

@BillWorthington Номери, які ви опублікували, не враховують розміщення індексів. 2712 байт - це максимальні межі btree, це деталізація реалізації, так що ви не можете знайти їх у документах. Однак ви можете легко протестувати його самостійно або просто погуглювати його, шукаючи "розмір рядка індексу postgresql перевищує максимум 2712 для індексу", наприклад.
sotn

Я новачок у PostgeSQL, тому не є експертом. Я працюю над проектом, де хочу зберігати статті новин у колонці в таблиці. Схоже, я буду використовувати тип стовпця тексту. Загальний розмір рядків 2712 байт здається занадто низьким для бази даних, яка, мабуть, буде близькою до того ж рівня, що і Oracle. Я правильно розумію, що ви маєте на увазі індексацію великого текстового поля? Не намагаючись кинути виклик чи сперечатися з вами, просто намагаючись зрозуміти реальні межі. Якщо не задіяні індекси, то чи обмежив рядок 400 ГБ, як у вікі ?? Дякуємо за вашу швидку відповідь.
Білл Уортінгтон

1
@BillWorthington Ви повинні вивчити повний пошук тексту. Перевірте це посилання, наприклад
sotn

18

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

select ' '::char = ' '::varchar, ' '::char = ' '::text, ' '::varchar = ' '::text

повернення, true, false, trueа не так, true, true, trueяк ви могли очікувати.


Як це можливо? Якщо a = b і a = c, то b = c.
Лукас Сільва

4

Дещо OT: Якщо ви використовуєте Rails, стандартне форматування веб-сторінок може бути іншим. Для форм введення даних textполя прокручуються, але поля character varying(Рейки string) - однорядкові. Показувати перегляди потрібно стільки, скільки потрібно.


2

Хороше пояснення від http://www.sqlines.com/postgresql/datatypes/text :

Єдина відмінність TEXT від VARCHAR (n) полягає в тому, що ви можете обмежити максимальну довжину стовпця VARCHAR, наприклад, VARCHAR (255) не дозволяє вставляти рядок довжиною більше 255 символів.

І TEXT, і VARCHAR мають верхню межу в 1 Gb, і різниця в продуктивності між ними (відповідно до документації PostgreSQL) не існує.


-1

character varying(n), varchar(n)- (Обидва однакові). значення буде усічене до n символів, не викликаючи помилки.

character(n), char(n)- (Обидва однакові). фіксованої довжини і буде прокладати заготовками до кінця довжини.

text- Необмежена довжина.

Приклад:

Table test:
   a character(7)
   b varchar(7)

insert "ok    " to a
insert "ok    " to b

Отримуємо результати:

a        | (a)char_length | b     | (b)char_length
----------+----------------+-------+----------------
"ok     "| 7              | "ok"  | 2

5
Хоча MySQL буде мовчки усікати дані, коли значення перевищує розмір стовпця, PostgreSQL не буде і підвищить "занадто довге значення для символу типу, що варіює (n)" помилку.
gsiems
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.