ดัชนีประสิทธิภาพสำหรับ CHAR กับ VARCHAR (Postgres)


16

ในคำตอบนี้ ( /programming/517579/strings-as-primary-keys-in-sql-database ) คำพูดเดียวจับตาฉัน:

โปรดทราบว่ามักจะมีความแตกต่างระหว่าง CHAR และ VARCHAR บ่อยมากเมื่อทำการเปรียบเทียบดัชนี

สิ่งนี้ใช้ได้ / ยังใช้กับ Postgres หรือไม่?

ฉันพบหน้าเว็บใน Oracle ที่อ้างว่าCHARเป็นนามแฝงไม่มากก็น้อยVARCHARดังนั้นประสิทธิภาพของดัชนีก็เหมือนกัน แต่ฉันไม่พบอะไรที่ชัดเจนสำหรับ Postgres

คำตอบ:


24

CHARและVARCHARมีการใช้งานเหมือนกันทุกประการใน Postgres (และ Oracle) ไม่มีความแตกต่างของความเร็วเมื่อใช้ชนิดข้อมูลเหล่านั้น

อย่างไรก็ตามมีความแตกต่างอย่างหนึ่งที่สามารถสร้างความแตกต่างในประสิทธิภาพการทำงาน: charคอลัมน์จะมีการเสริมความยาวตามที่กำหนดไว้เสมอ ดังนั้นถ้าคุณกำหนดคอลัมน์เป็นchar(100)และหนึ่งvarchar(100)เพียง แต่เก็บ 10 อักขระในแต่ละchar(100)คอลัมน์คอลัมน์ใช้ 100 อักขระสำหรับแต่ละค่า (10 อักขระที่คุณเก็บไว้บวก 90 ช่องว่าง) ในขณะที่varcharคอลัมน์เก็บ 10 อักขระเท่านั้น

การเปรียบเทียบ 100 ตัวอักษรกับ 100 ตัวอักษรจะช้ากว่าการเปรียบเทียบ 10 ตัวอักษรกับ 10 ตัวอักษรถึงแม้ว่าฉันสงสัยว่าคุณสามารถวัดความแตกต่างนี้ได้ในแบบสอบถาม SQL

ถ้าคุณประกาศทั้งสองมีความยาว 10 ตัวอักษรและมักจะเก็บตรง 10 ตัวอักษรในพวกเขานั้นมีความแตกต่างอย่างใด ๆ (นี้เป็นจริงสำหรับ Oracle และ Postgres) ไม่มี

ดังนั้นความแตกต่างเพียงอย่างเดียวคือการขยายที่ทำกับcharชนิดข้อมูล


โปรดทราบว่ามักจะมีความแตกต่างระหว่าง CHAR และ VARCHAR บ่อยมากเมื่อทำการเปรียบเทียบดัชนี

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


จากมุมมองของฉันcharประเภทข้อมูลไม่ได้ใช้จริงคำใด ๆ เพียงใช้varchar(หรือtextใน Postgres) และลืมสิ่งนั้นcharไว้


2
การเปรียบเทียบ 100 ตัวอักษรกับ 100 ตัวอักษรจะช้ากว่าการเปรียบเทียบ 10 ตัวอักษรกับ 10 ตัวอักษรถึงแม้ว่าฉันสงสัยว่าคุณสามารถวัดความแตกต่างนี้ได้ในแบบสอบถาม SQL - ขึ้นอยู่กับสิ่งที่แบบสอบถามทำนอกเหนือจากการเรียงลำดับความแตกต่างอาจมีขนาดใหญ่ นั่นเป็นเหตุผลที่ Postgres 9.5 มีคุณสมบัติ "ตัวย่อคีย์" ใหม่: pgeoghegan.blogspot.de/2015/01/…
chirlu

6

ฉันเห็นด้วยกับทุกอย่างที่พูดโดย a_horse_with_no_name และโดยทั่วไปฉันเห็นด้วยกับคำแนะนำความคิดเห็นของ Erwin:

ไม่ถ่านเป็นรอง (และล้าสมัย) ข้อความและ varchar ดำเนินการ (เกือบ) เหมือนกัน

เมตาดาต้า

ด้วยข้อยกเว้นเล็กน้อยหนึ่งครั้งเดียวที่ฉันใช้char()คือเมื่อฉันต้องการให้ meta-data บอกว่าต้องมีตัวอักษร x แม้ว่าฉันจะรู้ว่าchar()จะบ่นถ้าอินพุตเกินขีด จำกัด ฉันมักจะป้องกันไม่ให้มีผู้บุกรุกต่ำกว่าCHECKข้อ จำกัด ตัวอย่างเช่น,

CREATE TABLE foo (
  x char(10) CHECK ( length(x) = 10 )
);
INSERT INTO foo VALUES (repeat('x', 9));

ฉันทำสิ่งนี้ด้วยเหตุผลบางประการ

  1. char(x)บางครั้งอนุมานด้วย schema-loader ว่าเป็นคอลัมน์ความกว้างคงที่ สิ่งนี้อาจสร้างความแตกต่างในภาษาที่เหมาะสำหรับสตริงที่มีความกว้างคงที่
  2. มันสร้างการประชุมที่เหมาะสมและบังคับใช้อย่างง่ายดาย ฉันสามารถเขียน schema-loader ในภาษาเพื่อสร้างรหัสจากการประชุมนี้

ต้องการตัวอย่างที่ฉันสามารถทำได้

  1. อักษรสองตัวอักษรย่อของรัฐ ENUMแต่เพราะรายการนี้สามารถแจกแจงฉันจะมักจะทำมันด้วย
  2. หมายเลขประจำตัวยานพาหนะ
  3. หมายเลขรุ่น (ขนาดคงที่)

เกี่ยวกับข้อผิดพลาด

สังเกตว่าบางคนอาจรู้สึกไม่สบายใจกับความไม่ลงรอยกันของข้อความแสดงข้อผิดพลาดทั้งสองด้านของขีด จำกัด แต่มันก็ไม่ได้รบกวนฉัน

test=# INSERT INTO foo VALUES (repeat('x', 9));
ERROR:  new row for relation "foo" violates check constraint "foo_x_check"
DETAIL:  Failing row contains (xxxxxxxxx ).
test=# INSERT INTO foo VALUES (repeat('x', 11));
ERROR:  value too long for type character(10)

ตัดกันด้วย varchar

ยิ่งกว่านั้นฉันคิดว่าคำแนะนำข้างต้นนั้นเข้ากันได้ดีกับรูปแบบการใช้งานเกือบทุกtextครั้ง คุณถามvarchar(n)ด้วย ฉันไม่เคยใช้มัน varchar(n)อย่างน้อยผมก็จำไม่ได้ว่าครั้งสุดท้ายที่ผมใช้

  • หากข้อมูลจำเพาะมีสนามคงมีความกว้างที่ผมเชื่อว่าผมใช้char(n),
  • มิฉะนั้นฉันใช้textซึ่งมีประสิทธิภาพvarchar(ไม่ จำกัด )

หากฉันพบข้อมูลจำเพาะที่มีข้อความตัวอักษรยาวหลายตัวแปรที่มีความหมายและฉันเชื่อว่ามีความยาวสูงสุดคงที่ฉันก็จะใช้varchar(n)เช่นกัน อย่างไรก็ตามฉันไม่สามารถคิดอะไรที่เหมาะกับเกณฑ์นั้น

หมายเหตุเพิ่มเติม

คำถาม & คำตอบที่เกี่ยวข้อง:


1

PostgreSQL

sales_reporting_db=# create table x (y char(2));
CREATE TABLE
sales_reporting_db=# insert into x values ('Y');
INSERT 0 1
sales_reporting_db=# select '*' || y || '*' from x;
 ?column? 
----------
 *Y*

คำพยากรณ์

SQL> create table x ( y char(2));

Table created.

SQL> insert into x values ('Y');

1 row created.

SQL> select '*' || y || '*' from x;

'*'|
----
*Y *

Postgresql ไม่ได้มีช่องว่าง


นั่นเป็นเพียงภาพลวงตาทางแสงใน Postgres ลองSELECT pg_column_size(y) FROM x;
dezso

-2

ฉันพบว่ามีประโยชน์ที่สุดและคำอธิบาย 3 บรรทัดอย่างรวดเร็ว:

จากCHAR (n) Vs VARCHAR (N) Vs ข้อความใน Postgres

  • หากคุณต้องการเก็บข้อความที่มีความยาวไม่รู้จักใช้TEXTประเภทข้อมูล
  • หากคุณต้องการที่จะเก็บข้อความบางส่วนมีความยาวไม่รู้จัก VARCHAR(n)แต่คุณรู้ว่าความยาวสูงสุดที่ใช้
  • CHAR(N)หากคุณต้องการที่จะเก็บข้อความบางอย่างกับรู้จักกันในระยะเวลาที่แน่นอนการใช้งาน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.