PostgreSQL:text和varchar之间的区别(字符变化)

Ada*_*tan 558 string postgresql varchar text types

text数据类型和character varying(varchar)数据类型之间有什么区别?

根据文件

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

此外,PostgreSQL提供了文本类型,它存储任意长度的字符串.虽然类型文本不在SQL标准中,但是其他几个SQL数据库管理系统也有它.

那有什么区别?

Fra*_*ens 677

没有区别,在引擎盖下它是全部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得出结论,其中一个通常是长度限制的最佳选择.

  • @axiopisty这是一篇很棒的文章.你可以这么说,"如果文章发生故障,你能不能摘一些摘录?" 我试图简要总结一下文章的内容/结论.我希望这足以缓解您的担忧. (54认同)
  • @axiopisty,严格来说,最初的答案是说"*引擎盖下它是所有varlena*",这肯定是有用的信息,将这个答案与仅链接答案区分开来. (32认同)
  • 用无限的字符串记住的一件事是它们打开了滥用的可能性.如果您允许用户使用任何大小的姓氏,您可能会有人在您的姓氏字段中存储大量信息.关于reddit开发的[文章](http://highscalability.com/blog/2013/8/26/reddit-lessons-learned-from-mistakes-made-scaling-to-1-billi.html),他们建议"限制一切". (22认同)
  • @JoséL.Patiño 我最近了解到,从 [v9.2](https://www.postgresql.org/docs/9.2/release-9-2.html#AEN114949:~:text=Increasing%20the%20length% 20limit%20for%20a,no%20longer%20requires%20a%20table%20rewrite) 增加 varchar 列的限制不再需要表重写,使其几乎是瞬时的。我现在更喜欢“varchar(n)”而不是“text”,因为它允许我增加长度,而无需强制重新检查或OP文章中提供的黑客解决方案(例如函数约束)。 (10认同)
  • 这条评论有这么多票数,着实令人震惊。`text` 永远不应该被认为是开箱即用的“优于 varchar 的赢家”,只是因为它允许我输入任意长度的字符串,但恰恰相反,你应该**真正**考虑什么在允许用户输入任意长度的字符串之前您想要存储的数据类型。**不**,“让前端处理它”绝对是不可接受的,也是一种非常糟糕的开发实践。如今看到很多开发人员这样做真是令人惊讶。 (6认同)
  • @MarkHildreth好点,虽然这些天通常会在应用程序中进一步强制执行约束,以便UI可以平滑地处理规则(以及尝试的违规/重试).如果某人仍想在数据库中执行此类操作,则可以使用约束.请参阅http://blog.jonanin.com/2013/11/20/postgresql-char-varchar/,其中包含"使用TEXT和约束创建比VARCHAR更灵活的字段的示例". (4认同)
  • @emeraldhieu 你可以不同意,但随后想出一个完整的答案或文章来说明为什么某些数据类型比另一种更好。就像德佩斯所做的那样。过去发明了某种数据类型,并不意味着它是一个好主意。人类在过去犯下了太多愚蠢的错误...... (4认同)
  • @Ethan blog.jonanin.com/2013/11/20/postgresql-char-varchar->此操作已关闭,但可在此处找到https://archive.is/6xhA5。 (3认同)
  • 由于它们“text”和“varchar”在postgres中的性能和实现方面非常相似 - 并且由于text不是ansi sql而“varchar”是ansi sql - 那么“varchar”即使不是获胜者,也应该是一个强大的选择。来自对 Postgress Embedded 和 H2 内存数据库的简单检查,其中只有前者允许在“文本”上添加索引。我确实看到@Ethan提到“text”比“varchar”具有更多的约束灵活性。还是我错过了其他重要的事情?所以这听起来像是每个人都必须做出的权衡。 (3认同)
  • 好点@JoséL.Patiño,但是他确实声明了以下内容:“基于函数的约束或域提供了长度约束立即增加的优势”。在我看来,他是在说:“使用‘文本’,如果需要长度限制,请使用检查约束或域。” (3认同)
  • @JoséL.Patiño“让前端处理它”绝对没有人提出这个主张,你只是编造的。这类事情应该/应该由 API 层处理(因此,是_后端_,而不是前端,它很容易被最终用户绕过)。你的评论毫无意义,而且有如此之多的赞成票确实令人震惊。 (2认同)

Geo*_*rge 107

作为" 字符类型 "的文件中指出,varchar(n),char(n),和text都存储相同的方式.唯一的区别是需要额外的周期来检查长度(如果给出一个),以及需要填充所需的额外空间和时间char(n).

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

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

  • 从技术上讲,你是正确的@Jasen ......当然,这是最好的正确 (29认同)
  • 从技术上讲,引号不是类型名称的一部分.他们需要将它与char关键字区分开来. (17认同)

Pet*_*uss 51

更新2016年基准(第9 + 5页)

并使用"纯SQL"基准测试(没有任何外部脚本)

  1. 使用UTF8的任何string_generator

  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;
Run Code Online (Sandbox Code Playgroud)

准备具体测试(例子)

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) );
Run Code Online (Sandbox Code Playgroud)

执行基本测试:

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

和其他测试,

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;
Run Code Online (Sandbox Code Playgroud)

......并使用EXPLAIN ANALYZE.

2018年再次更新(第10页)

很少编辑添加2018的结果并强化建议.


2016年和2018年的结果

我的结果,平均之后,在许多机器和许多测试中:都是相同的
(统计上较少的标准偏差).

建议

  • 使用text数据类型,
    避免旧,varchar(x)因为有时它不是标准,例如在 CREATE FUNCTION子句中 varchar(x)varchar(y).

  • varchar通过例如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%')

  • 在pg11中仍然对2019年有效:text&gt; varchar(n)&gt; text_check&gt; char(n) (3认同)
  • @trench 是的,没关系 (2认同)
  • 很酷,为了安全起见,我重新编写了它,无论如何我都将所有内容设为文本。它运行良好,无论如何快速添加数百万条历史记录非常容易。 (2认同)

小智 32

在PostgreSQL手册上

这三种类型之间没有性能差异,除了在使用空白填充类型时增加的存储空间,以及在存储到长度受限的列中时检查长度的一些额外CPU周期.虽然character(n)在其他一些数据库系统中具有性能优势,但PostgreSQL没有这样的优势; 事实上,由于额外的存储成本,字符(n)通常是三者中最慢的.在大多数情况下,应该使用文本或字符变化.

我通常使用文字

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


sot*_*otn 19

在我看来,varchar(n)它有自己的优势.是的,他们都使用相同的底层类型和所有这些.但是,应该指出的是,PostgreSQL中的索引的每行大小限制为2712字节.

TL; DR: 如果您使用没有约束的text类型并且在这些列上有索引,则很可能您的某些列达到此限制并在尝试插入数据时出现错误,但使用时,您可以阻止它.varchar(n)

一些细节:这里的问题是,创建索引时PostgreSQL没有给出任何异常text类型或varchar(n)其中n大于2712.然而,当大于2712的压缩大小的记录被试图插入它会给错误.这意味着您可以插入100.000个字符串,该字符串由重复字符轻松组成,因为它将被压缩到远低于2712但您可能无法插入一些包含4000个字符的字符串,因为压缩的大小大于2712个字节.使用varchar(n)where n不是太大于2712,你可以避免这些错误.

  • 参考:/sf/ask/2797608411/,其中有 PostgreSQL Wiki 的链接:https://wiki.postgresql。 org/wiki/FAQ#What_is_the_maximum_size_for_a_row.2C_a_table.2C_and_a_database.3F 的最大行大小为 400GB,因此看起来每行 2712 字节的限制是错误的。数据库的最大大小?无限制(存在 32 TB 数据库)表的最大大小?32 TB 一行的最大大小?400 GB 字段的最大大小?1 GB 表中的最大行数?无限 (2认同)

小智 15

text和varchar具有不同的隐式类型转换.我注意到的最大影响是处理尾随空格.例如 ...

select ' '::char = ' '::varchar, ' '::char = ' '::text, ' '::varchar = ' '::text
Run Code Online (Sandbox Code Playgroud)

返回,true, false, true而不是true, true, true你所期望的.

  • 经测试,确实如此。不可能,但却是事实。非常非常奇怪。 (3认同)
  • 这是因为“=”运算符不仅比较内容,而且还进行一些转换以找到值的通用类型。这在各种语言中都是很常见的行为,并且所使用的转换也因语言而异。例如,在 JavaScript 中,您可以看到 `[0 == '0.0', 0 == '0', '0.0' == '0']` -&gt; `[true, true, false]` (3认同)
  • 这怎么可能?如果 a = b 且 a = c,则 b = c。 (2认同)

Rol*_*and 13

区别在于传统和现代。

传统上,您需要指定每个表列的宽度。如果指定的宽度太大,则会浪费昂贵的存储空间,但如果指定的宽度太小,则某些数据将无法容纳。然后你要调整列的大小,并且必须更改很多连接的软件,修复引入的错误,这都是非常麻烦的。

现代系统允许通过动态存储分配进行无限的字符串存储,因此附带的大字符串可以很好地存储,而不会浪费小数据项的存储。

虽然许多编程语言都采用了无限大小的“字符串”数据类型,例如 C#、javascript、java 等,但像 Oracle 这样的数据库却没有。

现在 PostgreSQL 支持“文本”,很多程序员仍然习惯 VARCHAR(N),理由是:是的,文本与 VARCHAR 相同,只不过使用 VARCHAR 时可以添加限制 N,因此 VARCHAR 更灵活。

你不妨这样推理:

既然我们可以用嘴来"VARCHAR WITHOUT N"简化我们的生活,为什么我们还要费心去用嘴呢"TEXT"

在我最近几年使用 Oracle 的过程中,我很少使用 CHAR(N) 或 VARCHAR(N)。因为 Oracle 确实(没有?)没有无限的字符串类型,所以我对大多数字符串列使用 VARCHAR(2000),其中 2000 在某些时候是 VARCHAR 的最大值,并且在所有实际目的中与“无限”没有太大区别。

现在我正在使用 PostgreSQL,我认为 TEXT 是真正的进步。不再强调CHAR类型的VAR特性。不再强调让我们使用没有 N 的 VARCHAR。此外,与 VARCHAR 相比,键入 TEXT 可以节省 3 个击键次数。

年轻的同事现在长大了,甚至不知道过去没有无限的限制。就像大多数项目一样,他们不必了解汇编编程。

更新:Azure 类型字符串

显然,现代 Azure SQL 系统有一个名为 String 的通用文本类型,类似于 PostgreSQL 类型 Text,但不可配置的限制为 500 个字符。在 Azure 中,String 类型似乎比 Varchar(N) 更常用,后者的限制为 4000。这是进步吗?


Gre*_*reg 6

有点 OT:如果您使用 Rails,网页的标准格式可能会有所不同。对于数据输入表单,text框是可滚动的,但character varying(Rails string) 框是一行的。根据需要显示视图。


Chr*_*row 5

来自http://www.sqlines.com/postgresql/datatypes/text 的一个很好的解释:

TEXT 和 VARCHAR(n) 之间的唯一区别是您可以限制 VARCHAR 列的最大长度,例如,VARCHAR(255) 不允许插入长度超过 255 个字符的字符串。

TEXT 和 VARCHAR 的上限都是 1 Gb,它们之间没有性能差异(根据 PostgreSQL 文档)。