PostgreSQL: Sự khác biệt giữa văn bản và varchar (thay đổi ký tự)


619

Sự khác biệt giữa textkiểu dữ liệu và kiểu dữ liệu character varying( varchar) là gì?

Theo tài liệu

Nếu thay đổi ký tự được sử dụng mà không có bộ xác định độ dài, loại chấp nhận các chuỗi có kích thước bất kỳ. Cái sau là một phần mở rộng PostgreSQL.

Ngoài ra, PostgreSQL cung cấp loại văn bản, lưu trữ các chuỗi có độ dài bất kỳ. Mặc dù văn bản loại không có trong tiêu chuẩn SQL, một số hệ thống quản lý cơ sở dữ liệu SQL khác cũng có nó.

Vậy sự khác biệt là gì?

Câu trả lời:


745

Không có sự khác biệt, dưới mui xe là tất cả varlena( mảng có chiều dài thay đổi ).

Kiểm tra bài viết này từ Depesz: http://www.depesz.com/index.php/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text/

Một vài điểm nổi bật:

Tổng hợp tất cả:

  • char (n) - chiếm quá nhiều không gian khi xử lý các giá trị ngắn hơn n(đệm chúng n) và có thể dẫn đến các lỗi tinh vi do thêm dấu cách, cộng với việc thay đổi giới hạn là vấn đề
  • varchar (n) - thật khó để thay đổi giới hạn trong môi trường sống (yêu cầu khóa độc quyền trong khi thay đổi bảng)
  • varchar - giống như văn bản
  • văn bản - đối với tôi là người chiến thắng - hơn (n) loại dữ liệu vì nó thiếu các vấn đề của họ và trên varchar - vì nó có tên riêng biệt

Bài viết thực hiện kiểm tra chi tiết để chỉ ra rằng hiệu suất của việc chèn và chọn cho cả 4 loại dữ liệu là tương tự nhau. Nó cũng có một cái nhìn chi tiết về các cách thay thế về việc hạn chế độ dài khi cần thiết. Các ràng buộc hoặc miền dựa trên chức năng cung cấp lợi thế tăng tức thời của ràng buộc độ dài và trên cơ sở giảm ràng buộc độ dài chuỗi là hiếm, depesz kết luận rằng một trong số chúng thường là lựa chọn tốt nhất cho giới hạn độ dài.


58
@axiopisty Đó là một bài viết tuyệt vời. Bạn chỉ có thể nói, "Bạn có thể lấy một số trích đoạn trong trường hợp bài báo bị hỏng không?" Tôi đã cố gắng tóm tắt ngắn gọn nội dung / kết luận của bài viết. Tôi hy vọng điều này là đủ để giảm bớt mối quan tâm của bạn.
jpmc26

34
@axiopisty, nói đúng ra, câu trả lời ban đầu là " dưới tất cả là varlena ", đây là thông tin hữu ích giúp phân biệt câu trả lời này với câu trả lời chỉ liên kết.
Bruno

24
Một điều cần lưu ý với một chuỗi vô hạn là chúng mở ra khả năng lạm dụng. Nếu bạn cho phép người dùng có họ của bất kỳ kích thước nào, bạn có thể có ai đó lưu trữ lượng thông tin LỚN trong trường họ của bạn. Trong một bài viết về sự phát triển của reddit, họ đưa ra lời khuyên là "Đặt giới hạn cho mọi thứ".
Đánh dấu Hildreth

7
@MarkHildreth Điểm tốt, mặc dù nhìn chung các ràng buộc như thế được thi hành thêm trong một ứng dụng vào những ngày này để các quy tắc (và cố gắng vi phạm / thử lại) có thể được xử lý trơn tru bởi UI. Nếu ai đó vẫn muốn thực hiện loại điều này trong cơ sở dữ liệu, họ có thể sử dụng các ràng buộc. Xem blog.jonanin.com/2013/11/20/postgresql-char-varchar bao gồm "một ví dụ về việc sử dụng văn bản và các ràng buộc để tạo các trường có tính linh hoạt cao hơn VARCHAR".
Ethan

4
@Ethan blog.jonanin.com/2013/11/20/postgresql-char-varchar -> Đây là xuống, nhưng được tìm thấy ở đây archive.is/6xhA5 .
MrR

115

Là " loại nhân vật " trong điểm tài liệu ra, varchar(n), char(n), và textđều được lưu trữ theo cùng một cách. Sự khác biệt duy nhất là các chu kỳ bổ sung là cần thiết để kiểm tra độ dài, nếu được đưa ra, và không gian và thời gian bổ sung cần thiết nếu cần đệm char(n).

Tuy nhiên, khi bạn chỉ cần lưu trữ một ký tự, có một lợi thế hiệu suất nhỏ khi sử dụng loại đặc biệt "char"(giữ nguyên dấu ngoặc kép - chúng là một phần của tên loại). Bạn có thể truy cập nhanh hơn vào trường và không có chi phí để lưu trữ độ dài.

Tôi chỉ tạo một bảng 1.000.000 ngẫu nhiên "char"được chọn từ bảng chữ cái viết thường. Một truy vấn để có được phân phối tần số ( select count(*), field ... group by field) mất khoảng 650 mili giây, so với khoảng 760 trên cùng một dữ liệu sử dụng một texttrường.


18
về mặt kỹ thuật, các trích dẫn không phải là một phần của tên loại. họ cần thiết để phân biệt nó với từ khóa char.
Jasen

31
Về mặt kỹ thuật bạn là chính xác @Jasen ... Trong đó, tất nhiên, là loại tốt nhất của đúng
JohannesH

kiểu dữ liệu "char" không char?? Nó có hợp lệ trong ngày nay của PostgreQuery 11+ không? ... Có: "Loại "char"(lưu ý các trích dẫn) khác với char (1) ở chỗ nó chỉ sử dụng một byte lưu trữ. Nó được sử dụng nội bộ trong các danh mục hệ thống như một kiểu liệt kê đơn giản ." , hướng dẫn / kiểu dữ liệu-ký tự .
Peter Krauss

63

CẬP NHẬT LỢI ÍCH NĂM 2016 (pg9.5 +)

Và sử dụng điểm chuẩn "SQL thuần túy" (không có bất kỳ tập lệnh bên ngoài nào)

  1. sử dụng bất kỳ chuỗi_generator nào với UTF8

  2. điểm chuẩn chính:

    2.1. CHÈN

    2.2. CHỌN so sánh và đếm


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;

Chuẩn bị kiểm tra cụ thể (ví dụ)

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) );

Thực hiện một bài kiểm tra cơ bản:

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

Và các xét nghiệm khác,

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;

... Và sử dụng EXPLAIN ANALYZE.

CẬP NHẬT LẠI NĂM 2018 (trg10)

chỉnh sửa nhỏ để thêm kết quả của năm 2018 và củng cố các khuyến nghị.


Kết quả năm 2016 và 2018

Kết quả của tôi, sau trung bình, trong nhiều máy và nhiều thử nghiệm: tất cả đều giống nhau
(độ lệch chuẩn tham chiếu ít hơn về mặt thống kê).

sự giới thiệu

  • Sử dụng textkiểu dữ liệu,
    tránh cũ varchar(x)bởi vì đôi khi nó không phải là một tiêu chuẩn, ví dụ như trong CREATE FUNCTIONđiều khoản varchar(x)varchar(y) .

  • thể hiện giới hạn (có cùng varcharhiệu suất!) bằng CHECKmệnh đề trong CREATE TABLE
    ví dụ CHECK(char_length(x)<=10).
    Với hiệu suất giảm không đáng kể trong CHERTN / CẬP NHẬT, bạn cũng có thể kiểm soát phạm vi và cấu trúc chuỗi,
    vdCHECK(char_length(x)>5 AND char_length(x)<=20 AND x LIKE 'Hello%')


Vì vậy, nó không quan trọng hơn việc tôi thực hiện tất cả các cột varchar thay vì văn bản? Tôi đã không chỉ định độ dài mặc dù một số chỉ có 4 - 5 ký tự và chắc chắn không phải là 255.
rãnh

1
@tbler có, không thành vấn đề
FuriousFolder

1
Thật tuyệt, tôi đã làm cho nó an toàn và dù sao tôi cũng đã làm mọi thứ. Nó hoạt động tốt và thật dễ dàng để thêm hàng triệu hồ sơ lịch sử một cách nhanh chóng.
rãnh

@tbler và reader: ngoại lệ duy nhất là kiểu dữ liệu nhanh hơn "char", điều đó không phải char, ngay cả trong ngày nay của PostgreQuery 11+. Như hướng dẫn / datatype-character nói "Loại "char"(lưu ý các trích dẫn) khác với char (1) ở chỗ nó chỉ sử dụng một byte lưu trữ. Nó được sử dụng trong các danh mục hệ thống như một kiểu liệt kê đơn giản ." .
Peter Krauss

3
vẫn còn hiệu lực với pg11 vào năm 2019: text> varchar (n)> text_check> char (n)
Olivier Refalo

37

Trên hướng dẫn sử dụng PostgreSQL

Không có sự khác biệt về hiệu năng giữa ba loại này, ngoài không gian lưu trữ tăng lên khi sử dụng loại đệm trống và một vài chu kỳ CPU bổ sung để kiểm tra độ dài khi lưu trữ vào cột bị giới hạn độ dài. Mặc dù ký tự (n) có lợi thế về hiệu năng trong một số hệ thống cơ sở dữ liệu khác, nhưng PostgreQuery không có lợi thế như vậy; trong thực tế, ký tự (n) thường là chậm nhất trong ba vì chi phí lưu trữ bổ sung của nó. Trong hầu hết các tình huống, văn bản hoặc ký tự khác nhau nên được sử dụng thay thế.

Tôi thường sử dụng văn bản

Tài liệu tham khảo: http://www.postgresql.org/docs/civerse/static/datatype-character.html


23

Theo tôi, varchar(n)có lợi thế riêng của nó. Vâng, tất cả đều sử dụng cùng một loại cơ bản và tất cả những thứ đó. Nhưng, cần chỉ ra rằng các chỉ mục trong PostgreSQL có giới hạn kích thước là 2712 byte mỗi hàng.

TL; DR: Nếu bạn sử dụng textloại không có ràng buộc và có chỉ mục trên các cột này, rất có thể bạn đã đạt giới hạn này đối với một số cột của mình và gặp lỗi khi bạn cố gắng chèn dữ liệu nhưng với việc sử dụng varchar(n), bạn có thể ngăn chặn nó.

Một số chi tiết khác: Vấn đề ở đây là PostgreSQL không đưa ra bất kỳ trường hợp ngoại lệ nào khi tạo chỉ mục cho textloại hoặc varchar(n)ở nơi nlớn hơn 2712. Tuy nhiên, nó sẽ báo lỗi khi bản ghi có kích thước nén lớn hơn 2712 được cố gắng chèn. Điều đó có nghĩa là bạn có thể chèn 100.000 ký tự chuỗi được tạo bởi các ký tự lặp đi lặp lại một cách dễ dàng vì nó sẽ bị nén xuống dưới 2712 nhưng bạn không thể chèn một số chuỗi có 4000 ký tự vì kích thước nén lớn hơn 2712 byte. Sử dụng varchar(n)ở nơi nkhông quá lớn hơn 2712, bạn an toàn trước những lỗi này.


Các lỗi postgres sau này khi cố gắng tạo lập chỉ mục cho văn bản chỉ hoạt động cho varchar (phiên bản không có (n)). Chỉ được thử nghiệm với postgres nhúng mặc dù.
arntg

2
Tham chiếu đến: stackoverflow.com/questions/39965834/ , có liên kết đến PostgreQuery Wiki: wiki.postgresql.org/wiki/, có kích thước hàng tối đa là 400GB, từ đó có vẻ như giới hạn 2712 byte đã nêu là sai . Kích thước tối đa cho một cơ sở dữ liệu? không giới hạn (cơ sở dữ liệu 32 TB tồn tại) Kích thước tối đa cho một bảng? 32 TB Kích thước tối đa cho một hàng? 400 GB Kích thước tối đa cho một lĩnh vực? 1 GB Số lượng hàng tối đa trong một bảng? không giới hạn
Bill Worthington

@BillWorthington Các số bạn đã đăng không tính đến việc đặt các chỉ mục mặc dù. 2712 byte là về giới hạn tối đa của btree, đó là một chi tiết triển khai để bạn không thể tìm thấy nó trên các tài liệu. Tuy nhiên, bạn có thể dễ dàng tự kiểm tra hoặc chỉ cần google nó bằng cách tìm kiếm "kích thước hàng chỉ mục postgresql vượt quá tối đa 2712 cho chỉ mục", vd.
sotn

Tôi chưa quen với PostgeSQL, vì vậy tôi không phải là chuyên gia. Tôi đang làm việc trong một dự án mà tôi muốn lưu trữ các bài báo trong một cột trong bảng. Có vẻ như kiểu cột văn bản là những gì tôi sẽ sử dụng. Tổng kích thước hàng 2712 byte nghe có vẻ quá thấp đối với cơ sở dữ liệu được cho là gần với mức tương tự như Oracle. Tôi có hiểu chính xác bạn rằng bạn đang đề cập đến việc lập chỉ mục một trường văn bản lớn không? Không cố gắng để thách thức hoặc tranh luận với bạn, chỉ cố gắng để hiểu các giới hạn thực sự. Nếu không có chỉ mục nào liên quan thì giới hạn hàng sẽ là 400GB như trong wiki ?? Cảm ơn phản hồi nhanh chóng của bạn.
Bill Worthington

1
@BillWorthington Bạn nên nghiên cứu về Tìm kiếm toàn văn. Kiểm tra liên kết này ví dụ
sotn

18

văn bản và varchar có chuyển đổi loại ngầm định khác nhau. Tác động lớn nhất mà tôi nhận thấy là xử lý các dấu cách. Ví dụ ...

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

trả lại true, false, truevà không true, true, truenhư bạn mong đợi


Sao có thể như thế được? Nếu a = b và a = c thì b = c.
Lucas Silva

4

Một chút OT: Nếu bạn đang sử dụng Rails, định dạng chuẩn của các trang web có thể khác nhau. Đối với các biểu mẫu nhập dữ liệu, các texthộp có thể cuộn được, nhưng các hộp character varying(Rails string) là một dòng. Hiển thị lượt xem miễn là cần thiết.


2

Một lời giải thích tốt từ http://www.sqlines.com/postgresql/datatypes/text :

Sự khác biệt duy nhất giữa TEXT và VARCHAR (n) là bạn có thể giới hạn độ dài tối đa của cột VARCHAR, ví dụ, VARCHAR (255) không cho phép chèn một chuỗi dài hơn 255 ký tự.

Cả TEXT và VARCHAR đều có giới hạn trên ở mức 1 Gb và không có sự khác biệt về hiệu năng giữa chúng (theo tài liệu của PostgreQuery).


-1

character varying(n), varchar(n)- (Cả hai giống nhau). giá trị sẽ được cắt ngắn thành n ký tự mà không gây ra lỗi.

character(n), char(n)- (Cả hai giống nhau). chiều dài cố định và sẽ đệm với khoảng trống cho đến hết chiều dài.

text- Không giới hạn chiều dài.

Thí dụ:

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

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

Chúng tôi nhận được kết quả:

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

5
Mặc dù MySQL sẽ âm thầm cắt dữ liệu khi giá trị vượt quá kích thước cột, PostgreSQL sẽ không và sẽ đưa ra một "giá trị quá dài cho lỗi thay đổi ký tự loại (n)".
gsiems
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.