PostgreSQL: ความแตกต่างระหว่างข้อความและ varchar (การเปลี่ยนแปลงอักขระ)


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) - เป็นปัญหาในการเปลี่ยนขีด จำกัด ในสภาพแวดล้อมแบบสด (ต้องใช้การล็อกแบบเอกสิทธิ์เฉพาะบุคคลขณะเปลี่ยนตาราง)
  • varchar - เหมือนข้อความ
  • ข้อความ - สำหรับฉันผู้ชนะ - ประเภทข้อมูลเกิน (n) เพราะมันไม่มีปัญหาและมากกว่า varchar - เพราะมีชื่อแตกต่างกัน

บทความนี้ทำการทดสอบโดยละเอียดเพื่อแสดงให้เห็นว่าประสิทธิภาพของเม็ดมีดและเลือกสำหรับทั้ง 4 ประเภทของข้อมูลนั้นคล้ายคลึงกัน นอกจากนี้ยังดูรายละเอียดเกี่ยวกับวิธีอื่นในการจำกัดความยาวเมื่อต้องการ ฟังก์ชันข้อ จำกัด หรือโดเมนที่ให้ประโยชน์ของการเพิ่มความยาวของข้อ จำกัด และบนพื้นฐานของการลดข้อจำกัดความยาวของสตริงนั้นหาได้ยาก Depesz สรุปว่าหนึ่งในนั้นมักจะเป็นตัวเลือกที่ดีที่สุดสำหรับการจำกัดความยาว


58
@axiopisty มันเป็นบทความที่ยอดเยี่ยม คุณสามารถพูดได้ว่า "คุณสามารถดึงข้อความที่ตัดตอนมาบ้างไหมในกรณีที่บทความล้มเหลว?" ฉันพยายามสรุปเนื้อหา / บทสรุปสั้น ๆ ของบทความ ฉันหวังว่านี่จะเพียงพอสำหรับการบรรเทาความกังวลของคุณ
jpmc26

34
@axiopisty พูดอย่างเคร่งครัดคำตอบเริ่มต้นพูดว่า " ภายใต้ประทุนมันคือทั้งหมดที่ varlena " ซึ่งเป็นข้อมูลที่มีประโยชน์อย่างแน่นอนซึ่งแตกต่างคำตอบนี้จากคำตอบแบบลิงก์เท่านั้น
บรูโน่

24
สิ่งหนึ่งที่ต้องคำนึงถึงด้วยสตริงที่ไร้ขีด จำกัด คือพวกเขาเปิดโอกาสในการถูกละเมิด หากคุณอนุญาตให้ผู้ใช้มีนามสกุลขนาดใดก็ได้คุณอาจมีคนที่เก็บข้อมูลจำนวนมากในฟิลด์นามสกุลของคุณ ในบทความเกี่ยวกับการพัฒนาของ Reddit พวกเขาให้คำแนะนำในการ "จำกัด ทุกสิ่ง"
Mark Hildreth

7
@MarkHildreth จุดที่ดีแม้ว่าโดยทั่วไปข้อ จำกัด เช่นนั้นจะถูกบังคับใช้เพิ่มเติมในแอปพลิเคชันในทุกวันนี้ - เพื่อให้สามารถจัดการกฎ (และความพยายามในการละเมิด / ลองใหม่) ได้อย่างราบรื่นโดย UI หากใครบางคนยังต้องการทำสิ่งนี้ในฐานข้อมูลพวกเขาสามารถใช้ข้อ จำกัด ได้ ดูblog.jonanin.com/2013/11/20/postgresql-char-varcharซึ่งรวมถึง "ตัวอย่างของการใช้ TEXT และข้อ จำกัด ในการสร้างเขตข้อมูลที่มีความยืดหยุ่นมากกว่า VARCHAR"
Ethan

4
blog.jonanin.com/2013/11/20/postgresql-char-varchar @Ethan -> นี่คือลง แต่พบได้ที่นี่archive.is/6xhA5
MrR

115

ในฐานะที่เป็น " ตัวละครประเภท " ในจุดเอกสารออกvarchar(n), char(n)และtextทั้งหมดถูกเก็บไว้ในลักษณะเดียวกัน ความแตกต่างเพียงอย่างเดียวคือรอบพิเศษที่จำเป็นในการตรวจสอบความยาวหากมีการกำหนดและต้องใช้พื้นที่และเวลาเพิ่มเติมหากจำเป็นต้องใช้ช่องว่างchar(n)ภายใน

อย่างไรก็ตามเมื่อคุณต้องการเก็บอักขระเพียงตัวเดียวจะมีข้อได้เปรียบด้านประสิทธิภาพเล็กน้อยเมื่อใช้ชนิดพิเศษ"char"(เก็บเครื่องหมายคำพูดคู่ไว้ - เป็นส่วนหนึ่งของชื่อประเภท) คุณเข้าถึงฟิลด์ได้เร็วขึ้นและไม่มีค่าใช้จ่ายในการจัดเก็บความยาว

ฉันเพิ่งสร้างตารางสุ่ม"char"เลือก1,000,000 ตัวจากตัวอักษรตัวพิมพ์เล็ก แบบสอบถามเพื่อรับการแจกแจงความถี่ ( select count(*), field ... group by field) ใช้เวลาประมาณ 650 มิลลิวินาทีเทียบกับประมาณ 760 ข้อมูลเดียวกันโดยใช้textฟิลด์


18
ในทางเทคนิคคำพูดไม่ได้เป็นส่วนหนึ่งของชื่อประเภท พวกเขาจำเป็นต้องแยกความแตกต่างจากคำหลักถ่าน
Jasen

31
ในทางเทคนิคคุณถูกต้อง @Jasen ... ซึ่งแน่นอนว่าเป็นประเภทที่ถูกต้องที่สุด
JohannesH

ประเภทข้อมูล"char" ไม่ char?? ใช้ได้กับ PostgreSQL 11+ หรือไม่ ... ใช่: "ชนิด"char"(โปรดสังเกตคำพูด) จะแตกต่างจากถ่าน (1) ในการที่จะใช้เพียงหนึ่งไบต์ของการจัดเก็บมันถูกใช้ภายในในแคตตาล็อกระบบเป็น. ประเภทการแจงนับง่าย ." , คู่มือ / ประเภทข้อมูลตัวอักษร
Peter Krauss

63

การอัพเดท BENCHMARKS สำหรับปี 2559 (pg9.5 +)

และใช้การเปรียบเทียบ "pure SQL" (ไม่มีสคริปต์ภายนอก)

  1. ใช้ string_generator ใด ๆ กับ UTF8

  2. มาตรฐานหลัก:

    2.1 INSERT

    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 และเสริมคำแนะนำ


ผลลัพธ์ในปี 2559 และ 2561

ผลลัพธ์ของฉันโดยเฉลี่ยแล้วในเครื่องหลายเครื่องและการทดสอบหลายอย่าง: เหมือนกันทั้งหมด
(ค่าเบี่ยงเบนมาตรฐานต่ำกว่าจริง)

คำแนะนำ

  • ใช้textประเภทข้อมูล,
    หลีกเลี่ยงเก่าvarchar(x)เพราะบางครั้งมันไม่ได้มาตรฐานเช่นใน CREATE FUNCTIONข้อ ≠varchar(x)varchar(y)

  • แสดงขีด จำกัด (แบบเดียวกับvarcharผลการปฏิบัติงาน) โดยมีCHECKข้อในเช่นCREATE TABLE
    ด้วยการสูญเสียประสิทธิภาพเล็กน้อยใน INSERT / UPDATE คุณสามารถควบคุมช่วงและโครงสร้างสตริง เช่นCHECK(char_length(x)<=10)

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


ดังนั้นไม่สำคัญว่าฉันสร้างคอลัมน์ varchar ทั้งหมดแทนที่จะเป็นข้อความใช่ไหม ฉันไม่ได้ระบุความยาวถึงแม้ว่าบางคนมีเพียง 4 - 5 ตัวอักษรและไม่แน่นอน 255
สลัก

1
@ น่าใช่ใช่มันไม่สำคัญ
FuriousFolder

1
เจ๋งฉันเปลี่ยนมันให้ปลอดภัยแล้วฉันก็ทำทุกอย่างเป็นข้อความต่อไป มันใช้งานได้ดีและมันง่ายมากที่จะเพิ่มบันทึกทางประวัติศาสตร์นับล้าน ๆ รายการอย่างรวดเร็ว
คูน้ำ

@trench และผู้อ่าน: ข้อยกเว้นเพียงอย่างเดียวคือประเภทข้อมูลที่เร็วกว่า"char"นั่นไม่ใช่ charแม้แต่ในปัจจุบันของ PostgreSQL 11+ ตามที่คู่มือ / datatype-characterกล่าวว่า"ประเภท"char"(หมายเหตุราคา) แตกต่างจาก char (1) โดยที่มันใช้หน่วยเก็บข้อมูลเพียงหนึ่งไบต์เท่านั้นมันถูกใช้ภายในในแคตตาล็อกระบบเป็นประเภทการแจงนับอย่างง่าย " .
Peter Krauss

3
ยังคงใช้ได้กับ pg11 ในปี 2019: ข้อความ> varchar (n)> text_check> char (n)
Olivier Refalo

37

ในคู่มือ PostgreSQL

ไม่มีความแตกต่างด้านประสิทธิภาพระหว่างสามประเภทนี้นอกเหนือจากพื้นที่เก็บข้อมูลที่เพิ่มขึ้นเมื่อใช้ประเภทที่มีเบาะรองและรอบ CPU เพิ่มเติมไม่กี่รอบเพื่อตรวจสอบความยาวเมื่อจัดเก็บในคอลัมน์ที่มีความยาว จำกัด ในขณะที่ตัวละคร (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 ตัวเนื่องจากขนาดที่บีบอัดมีขนาดใหญ่กว่า 2,712 ไบต์ การใช้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 มันเป็นรายละเอียดการใช้งานเพื่อให้คุณไม่สามารถค้นหาได้ในเอกสาร อย่างไรก็ตามคุณสามารถทดสอบได้ด้วยตนเองหรือเพียงแค่ google โดยค้นหา "ขนาดแถวดัชนี postgresql เกิน 2712 สูงสุดสำหรับดัชนี" เช่น
sotn

ฉันใหม่กับ PostgeSQL ดังนั้นจึงไม่ใช่ผู้เชี่ยวชาญ ฉันกำลังทำงานในโครงการที่ฉันต้องการจัดเก็บบทความข่าวในคอลัมน์ในตาราง ดูเหมือนว่าประเภทคอลัมน์ข้อความคือสิ่งที่ฉันจะใช้ ขนาดแถวทั้งหมด 2712 ไบต์ฟังดูต่ำเกินไปสำหรับฐานข้อมูลที่คาดว่าจะใกล้เคียงกับระดับเดียวกับ Oracle ฉันเข้าใจคุณอย่างถูกต้องหรือไม่ว่าคุณกำลังอ้างถึงการจัดทำดัชนีฟิลด์ข้อความขนาดใหญ่ ไม่พยายามท้าทายหรือโต้แย้งกับคุณเพียงพยายามเข้าใจขีด จำกัด ที่แท้จริง หากไม่มีดัชนีที่เกี่ยวข้องแล้วขีด จำกัด แถวจะเป็น 400GB เหมือนกับในวิกิหรือไม่? ขอบคุณสำหรับการตอบสนองที่รวดเร็ว
Bill Worthington

1
@BillWorthington คุณควรศึกษาเกี่ยวกับการค้นหาข้อความแบบเต็ม ตรวจสอบลิงค์นี้เช่น
sotn

18

ข้อความและ 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(ราง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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.