PostgreSQL:文本和varchar之间的区别(字符不同)


618

text数据类型和character varyingvarchar)数据类型有什么区别?

根据文档

如果在不使用长度说明符的情况下使用字符变化,则该类型接受任何大小的字符串。后者是PostgreSQL扩展。

另外,PostgreSQL提供了文本类型,该文本类型存储任意长度的字符串。尽管类型文本不在SQL标准中,但其他几种SQL数据库管理系统也具有它。

那有什么区别呢?

Answers:


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)–在实时环境中更改限制是有问题的(更改表时需要排他锁)
  • varchar –就像文本一样
  • 文本–对我来说是赢家 –超过(n)个数据类型,因为它没有问题,而超过varchar –因为它具有独特的名称

本文进行了详细的测试,以显示所有4种数据类型的插入和选择性能相似。还详细介绍了在需要时限制长度的其他方法。基于函数的约束或域提供了立即增加长度约束的优势,并且在减少字符串长度约束的情况很少见的基础上,depesz得出结论,其中之一通常是长度限制的最佳选择。


58
@axiopisty这是一篇很棒的文章。您可以说:“如果文章出现问题,您可以摘录一些吗?” 我试图简要地总结文章的内容/结论。我希望这足以缓解您的担忧。
jpmc26 2014年

34
严格来说,@ axiopisty最初的答案是“ 在引擎盖下全部是varlena ”,这无疑是有用的信息,可以将此答案与仅链接的答案区分开。
2014年

24
无限的字符串要记住的一件事是,它们打开了滥用的可能性。如果允许用户使用任意大小的姓氏,则可能有人在您的“姓氏”字段中存储了大量信息。在一篇有关reddit发展的文章中,他们建议“限制一切”。
Mark Hildreth

7
@MarkHildreth好点,尽管通常这样的约束现在在应用程序中进一步得到加强,以便UI可以平滑地处理规则(以及尝试的违反/重试)。如果有人仍然想在数据库中做这种事情,他们可以使用约束。请参阅blog.jonanin.com/2013/11/20/postgresql-char-varchar,其中包括“使用TEXT和约束创建比VARCHAR更灵活的字段的示例”。
伊桑(Ethan)2015年

4
@Ethan blog.jonanin.com/2013/11/20/postgresql-char-varchar->此操作已关闭,但在此处找到archive.is/6xhA5
MrR

115

作为“ 字符类型的文档,点”出来,varchar(n)char(n),和text都存储相同的方式。唯一的区别是,如果指定了长度,则需要额外的循环来检查长度;如果需要填充,则需要额外的空间和时间char(n)

但是,当您只需要存储一个字符时,使用特殊类型在性能上有一点优势"char"(保留双引号-它们是类型名称的一部分)。您可以更快地访问该字段,并且没有开销来存储长度。

我刚刚做了一个"char"从小写字母中选择的1,000,000个随机表。获取频率分布(select count(*), field ... group by field)的查询大约需要650毫秒,而使用text字段对相同数据的查询大约需要760毫秒。


18
从技术上讲,引号不是类型名称的一部分。他们需要将其与char关键字区分开。
2015年

31
从技术上来说,您是正确的@Jasen ...当然,这是最正确的一种
JohannesH

数据类型"char" 不是 char?? 在当今的PostgreSQL 11+中有效吗?...是: “类型"char"(请注意引号)与char(1)的不同之处在于,它仅使用一个字节的存储空间。它在系统目录中内部用作简单的枚举类型。” guide / datatype-character
彼得·克劳斯

63

更新2016年基准(pg9.5 +)

并使用“纯SQL”基准(无需任何外部脚本)

  1. 将任何string_generator与UTF8一起使用

  2. 主要基准:

    2.1。插

    2.2。SELECT比较和计数


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通过eg中的with CHECK子句表示限制(具有相同的性能!)。INSERT / UPDATE的性能损失可以忽略不计,您还可以控制范围和字符串结构, 例如CREATE TABLE
    CHECK(char_length(x)<=10)

    CHECK(char_length(x)>5 AND char_length(x)<=20 AND x LIKE 'Hello%')


因此,与我将所有列都设为varchar而不是文本无关紧要?我没有具体说明,即使有些是只有4的长度- 5个字符,肯定不是255

1
@trench是的,没关系
FuriousFolder

1
很酷,为了安全起见,我对其进行了重新设置,无论如何我都将所有内容设为文字。它运行良好,而且无论如何快速添加数百万个历史记录非常容易。
trench

@trench和读者:唯一例外的是更快的数据类型"char",是不是 char,即使在当今的PostgreSQL 11+的。正如guide / datatype-character所说:“该类型"char"(请注意引号)与char(1)的不同之处在于,它仅使用一个字节的存储空间。它在系统目录中内部用作一种简单的枚举类型。”
彼得·克劳斯

3
在pg11中仍对2019年有效:text> varchar(n)> text_check> char(n)
Olivier

37

在PostgreSQL手册上

这三种类型之间没有性能差异,除了使用空白填充类型时增加的存储空间,以及在存储到受长度限制的列中时需要一些额外的CPU周期来检查长度。尽管character(n)在某些其他数据库系统中具有性能优势,但在PostgreSQL中却没有这种优势。实际上,character(n)通常是这三个中最慢的,因为它需要额外的存储成本。在大多数情况下,应改用文字或字符变化。

我通常使用文字

参考:http : //www.postgresql.org/docs/current/static/datatype-character.html


23

我认为,这varchar(n)有其自身的优势。是的,它们都使用相同的基础类型。但是,应该指出的是,PostgreSQL中的索引的大小限制为每行2712字节

TL; DR: 如果您使用没有限制的text类型并且在这些列上具有索引,则很有可能在尝试插入数据时达到某些限制并在使用时出错,但是使用可以防止这种情况。varchar(n)

更多详细信息:这里的问题是PostgreSQL在为texttype或varchar(n)where n大于2712 创建索引时没有给出任何异常。但是,当尝试插入压缩大小大于2712的记录时,它将给出错误。这意味着您可以轻松插入由重复字符组成的字符串的100.000个字符,因为它将被压缩到2712以下,但是由于压缩后的大小大于2712字节,您可能无法插入一些4000个字符的字符串。使用varchar(n)其中n太多超过2712,你就是从这些错误中的安全。


以后有关尝试为文本创建索引的postgres错误仅适用于varchar(不带(n)的版本)。不过,仅使用嵌入式postgres进行了测试。
arntg

2
引用:stackoverflow.com/questions/39965834/… 链接到PostgreSQL Wiki: wiki.postgresql.org/wiki/…的 最大行大小为400GB,由此看来,每行2712个字节的限制是错误的。数据库的最大大小?无限(存在32 TB数据库)表的最大大小?32 TB的最大最大容量?400 GB字段的最大大小?1 GB表中的最大行数?无限
Bill Worthington

@BillWorthington您发布的数字虽然没有考虑放置索引。2712字节大约是btree的最大限制,它是一个实现细节,因此您无法在文档中找到它。但是,您可以轻松地自己测试它,也可以通过搜索“ postgresql索引行大小超过索引的最大2712”来对其进行Google搜索,例如。
10:52

我是PostgeSQL的新手,所以不是专家。我正在一个项目中,我希望将新闻文章存储在表格的列中。看起来文本列类型是我将要使用的类型。对于据认为接近于Oracle级别的数据库,2712字节的总行大小听起来太低了。我是否正确理解您指的是索引大文本字段?不要试图与您挑战或争论,而只是想了解真正的限制。如果不涉及索引,那么行数限制是否会像Wiki中一样为400GB?感谢您的快速回复。
比尔·沃辛顿

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 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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.