PostgreSQL: разница между текстом и varchar (различается символ)


620

В чем разница между textтипом данных и character varying( varchar) типами данных?

Согласно документации

Если изменение символов используется без спецификатора длины, тип принимает строки любого размера. Последнее является расширением PostgreSQL.

а также

Кроме того, PostgreSQL предоставляет тип текста, в котором хранятся строки любой длины. Хотя текст типа не соответствует стандарту SQL, он есть и в некоторых других системах управления базами данных SQL.

Так в чем же разница?

Ответы:


746

Разницы нет, под капотом все varlena( массив переменной длины ).

Проверьте эту статью от Depesz: http://www.depesz.com/index.php/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text/

Несколько основных моментов:

Подводя итог всего этого:

  • char (n) - занимает слишком много места при работе со значениями короче n(дополняет их n) и может привести к незначительным ошибкам из-за добавления конечных пробелов, плюс изменение предела проблематично
  • varchar (n) - изменить лимит в реальной среде проблематично (требуется исключительная блокировка при изменении таблицы)
  • varchar - как текст
  • текстовые - для меня победитель - над (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"(сохраняйте двойные кавычки - они являются частью имени типа). Вы получаете более быстрый доступ к полю, и нет затрат на хранение длины.

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


18
технически кавычки не являются частью имени типа. они нужны, чтобы отличать его от ключевого слова char.
Ясен

31
Технически, вы правы @Jasen ... Что, конечно, является лучшим видом правильности
JohannesH

Тип данных "char" не char?? Это действительно в наши дни PostgreSQL 11+? ... Да: «Тип "char"(обратите внимание на кавычки) отличается от char (1) тем, что он использует только один байт памяти. Он внутренне используется в системных каталогах как упрощенный тип перечисления» . , руководство / тип данных-характер .
Питер Краусс

64

ОБНОВЛЕНИЕ ЭТАЛОНОВ НА 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 (pg10)

немного изменить, чтобы добавить результаты 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%')


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

1
@trench да, это не имеет значения
FuriousFolder

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

@trench и reader: единственное исключение - более быстрый тип данных "char", которого нет char, даже в настоящее время в PostgreSQL 11+. Как говорит символ guide / datatype : «Тип "char"(обратите внимание на кавычки) отличается от char (1) тем, что он использует только один байт памяти. Он используется внутри системных каталогов как упрощенный тип перечисления» . ,
Питер Краусс

3
все еще действует с pg11 в 2019 году: text> 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, вы защищены от этих ошибок.


Позже ошибки postgres при попытке создать индексацию для текста работают только для varchar (версия без (n)). Только проверено со встроенными postgres.
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

text и varchar имеют разные неявные преобразования типов. Самое большое влияние, которое я заметил, это обработка конечных пробелов. Например ...

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(Rails string) - однострочные. Шоу просмотров столько, сколько нужно.


2

Хорошее объяснение от http://www.sqlines.com/postgresql/datatypes/text :

Единственная разница между TEXT и VARCHAR (n) состоит в том, что вы можете ограничить максимальную длину столбца VARCHAR, например, VARCHAR (255) не позволяет вставлять строку длиной более 255 символов.

И TEXT, и VARCHAR имеют верхний предел в 1 Гб, и между ними нет разницы в производительности (согласно документации 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.