ค่าใช้จ่ายสำหรับ varchar (n) คืออะไร?


15

ฉันต้องการถามถึงความหมายของส่วนนี้จากPostgres docเกี่ยวกับvarchar(n)ประเภท:

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

สมมติว่าฉันมีvarchar(255)ทุ่งนา และตอนนี้คำสั่งต่อไปนี้:

  • หากฟิลด์นี้มีสตริง 10 ไบต์ค่าใช้จ่ายอยู่ที่ 1 ไบต์ ดังนั้นสตริงจะใช้ 11 ไบต์
  • ถ้าเขตข้อมูลถือสตริงที่ใช้ 140 ไบต์ค่าใช้จ่ายอยู่ที่ 4 ไบต์ ดังนั้นสตริงจะใช้ 144 ไบต์

ข้อความข้างต้นเป็นจริงหรือไม่? ที่นี่มีคนเข้าใจเอกสารเช่นเดียวกับผม แต่ที่นี่มีคนระบุค่าใช้จ่ายอยู่เสมอ 4 ไบต์ที่นี่ ?

คำตอบ:


19

แปลกใจที่คู่มือถูกต้อง แต่มีมากกว่านั้น

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

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

สตริงยาวไม่เกินnอักขระ (ไม่ใช่ไบต์)

พวกเขาทั้งหมดใช้varlenaภายใน
"char"(พร้อมเครื่องหมายคำพูดคู่) เป็นสิ่งมีชีวิตที่แตกต่างกันและมีไบต์เดียวเสมอ
สตริงตัวอักษรที่ไม่ได้พิมพ์ ( 'foo') มีโอเวอร์เฮดไบต์เดียว เพื่อไม่ให้สับสนกับค่าที่พิมพ์!

pg_column_size()การทดสอบด้วย

CREATE TEMP TABLE t (id int, v_small varchar, v_big varchar);
INSERT INTO t VALUES (1, 'foo', '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890');

SELECT pg_column_size(id)        AS id
     , pg_column_size(v_small)   AS v_small
     , pg_column_size(v_big)     AS v_big
     , pg_column_size(t)         AS t
FROM   t
UNION ALL  -- 2nd row measuring values in RAM
SELECT pg_column_size(1)
     , pg_column_size('foo'::varchar)
     , pg_column_size('12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890'::varchar)
     , pg_column_size(ROW(1, 'foo'::varchar, '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890'::varchar));

 id | v_small | v_big |  t
----+---------+-------+-----
  4 |       4 |   144 | 176
  4 |       7 |   144 | 176

อย่างที่เห็น:

  • สตริง 3 ไบต์ 'foo' ใช้พื้นที่4 ไบต์บนดิสก์และ7 ไบต์ใน RAM (ดังนั้น 1 ไบต์เทียบกับ 4 ไบต์ของค่าใช้จ่าย)
  • สตริง 140 ไบต์ '123 ... ' ใช้เวลา 144 ไบต์ทั้งบนดิสก์และใน RAM (ดังนั้นจึงมีค่าใช้จ่าย 4 ไบต์เสมอ)
  • การจัดเก็บของintegerไม่มีค่าใช้จ่าย (แต่มีข้อกำหนดการจัดตำแหน่งที่สามารถกำหนดช่องว่างภายใน)
  • แถวมีค่าใช้จ่ายเพิ่มเติม 24 ไบต์สำหรับส่วนหัว tuple (บวก 4 ไบต์เพิ่มเติมต่อ tuple สำหรับตัวชี้รายการในส่วนหัวของหน้า)
  • และสุดท้าย แต่ไม่ท้ายสุด: ค่าโสหุ้ยของขนาดเล็กvarcharยังคงเป็นเพียง 1 ไบต์ในขณะที่ยังไม่ได้แยกออกจากแถว - ดังที่เห็นได้จากขนาดแถว (นั่นเป็นเหตุผลที่บางครั้งมันเร็วกว่าเล็กน้อยในการเลือกทั้งแถว)

ที่เกี่ยวข้อง:


1
ค่าใช้จ่าย 1 ไบต์นั้นยังคงเป็น 1 ไบต์ในดัชนีหรือไม่
dvtan

1
@dtgq: ดัชนีจะเก็บข้อมูลเหมือนกับตารางดังนั้นใช่
Erwin Brandstetter
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.