ดัชนี: จำนวนเต็มกับประสิทธิภาพของสตริงถ้าจำนวนโหนดเท่ากัน


26

ฉันกำลังพัฒนาแอพพลิเคชั่นใน Ruby on Rails ด้วยฐานข้อมูล PostgreSQL (9.4) สำหรับกรณีการใช้งานของฉันคอลัมน์ในตารางจะถูกค้นหาบ่อยมากเนื่องจากทั้งจุดของแอปพลิเคชันกำลังค้นหาแอตทริบิวต์ที่เฉพาะเจาะจงมากในแบบจำลอง

ฉันกำลังตัดสินใจว่าจะใช้integerชนิดหรือเพียงแค่ใช้ประเภทสตริงทั่วไป (เช่นcharacter varying(255), ซึ่งเป็นค่าเริ่มต้นใน Rails ) สำหรับคอลัมน์ที่เป็นผมไม่แน่ใจว่าสิ่งที่แตกต่างของประสิทธิภาพการทำงานจะอยู่ในดัชนี

คอลัมน์เหล่านี้เป็น enums มีขนาดคงที่สำหรับจำนวนค่าที่เป็นไปได้ที่สามารถมีได้ ส่วนใหญ่ความยาว enum ไม่เกิน 5 หมายถึงดัชนีจะมีมากขึ้นหรือน้อยคงที่ตลอดอายุการใช้งานของโปรแกรม ; ดังนั้นจำนวนเต็มและดัชนีสตริงจะเหมือนกันในจำนวนโหนด

อย่างไรก็ตามสตริงที่จะทำดัชนีอาจมีความยาวประมาณ 20 ตัวอักษรซึ่งในหน่วยความจำประมาณ 5x ของจำนวนเต็ม (ถ้าจำนวนเต็ม 4 ไบต์และสตริงนั้นเป็น ASCII บริสุทธิ์ที่ 1 ไบต์ต่อตัวอักษรดังนั้นสิ่งนี้จะเก็บไว้) ฉันไม่รู้ว่าเอ็นจิ้นฐานข้อมูลทำการค้นหาดัชนีอย่างไร แต่ถ้ามันจำเป็นต้อง "สแกน" สตริงจนกว่าจะตรงกันทั้งหมดดังนั้นในสาระสำคัญซึ่งหมายความว่าการค้นหาสตริงจะช้ากว่าการค้นหาจำนวนเต็ม 5 เท่า "สแกน" จนกระทั่งตรงกับการค้นหาจำนวนเต็มจะเป็น 4 ไบต์แทน 20 นี่คือสิ่งที่ฉันจินตนาการ

ค่าการค้นหาคือ (จำนวนเต็ม) 4:

สแกน ............................ พบ | กำลังรับบันทึก ... | BYTE_1 | BYTE_2 | BYTE_3 | BYTE_4 | BYTE_5 | BYTE_6 | BYTE_7 | BYTE_8 | ... | |

ค่าการค้นหาคือ (สตริง) "some_val" (8 ไบต์):

สแกน ................................................. พบ .................................... กำลังรับบันทึก ... | BYTE_1 | BYTE_2 | BYTE_3 | BYTE_4 | BYTE_5 | BYTE_6 | BYTE_7 | BYTE_8 | ... | |

ฉันหวังว่านั่นสมเหตุสมผล โดยทั่วไปเนื่องจากจำนวนเต็มใช้พื้นที่น้อยกว่าจึงสามารถ "จับคู่" ได้เร็วกว่าสตริงคู่ บางทีนี่อาจเป็นการคาดเดาที่ผิด แต่ฉันไม่ชำนาญดังนั้นฉันจึงถามพวกนาย! ฉันคิดว่าคำตอบที่ฉันเพิ่งพบนั้นดูเหมือนจะสนับสนุนสมมติฐานของฉัน แต่ฉันต้องการที่จะแน่ใจ

จำนวนค่าที่เป็นไปได้ในคอลัมน์จะไม่เปลี่ยนแปลงโดยใช้ค่าใดค่าหนึ่งดังนั้นดัชนีจะไม่เปลี่ยนแปลง (เว้นแต่ฉันจะเพิ่มค่าใหม่ให้กับ enum) ในกรณีนี้จะมีความแตกต่างด้านประสิทธิภาพในการใช้งานintegerหรือvarchar(255)หรือใช้ประเภทจำนวนเต็มเหมาะสมหรือไม่


เหตุผลที่ฉันถามก็คือenumประเภทของ Rails จับคู่จำนวนเต็มกับคีย์สตริง แต่ไม่ได้หมายความว่าจะต้องเป็นคอลัมน์ที่ผู้ใช้หันเข้าหากัน โดยพื้นฐานแล้วคุณไม่สามารถทำการตรวจสอบว่าค่า enum เป็นค่าที่ถูกต้องเพราะค่าที่ไม่ถูกต้องจะทำให้เกิดArgumentErrorก่อนที่การตรวจสอบความถูกต้องใด ๆ จะสามารถทำงานได้ การใช้stringประเภทจะอนุญาตให้มีการตรวจสอบความถูกต้อง แต่หากมีค่าใช้จ่ายในการปฏิบัติงานฉันควรที่จะแฮ็กข้อมูลเกี่ยวกับปัญหาการตรวจสอบความถูกต้อง

คำตอบ:


32

คำตอบสั้น ๆ : integerเร็วกว่าvarcharหรือtextในทุกด้าน จะไม่สำคัญมากสำหรับโต๊ะเล็กและ / หรือปุ่มลัด ความแตกต่างจะเพิ่มขึ้นตามความยาวของปุ่มและจำนวนแถว

สตริง ... ความยาว 20 ตัวอักษรซึ่งในหน่วยความจำประมาณ 5x ของจำนวนเต็ม (ถ้าจำนวนเต็ม 4 ไบต์และสตริงเป็น ASCII บริสุทธิ์ที่ 1 ไบต์ต่อตัวอักษรดังนั้นสิ่งนี้จะถือ)

เพื่อความแม่นยำประเภทของตัวอักษร ( textหรือvarchar) จะมีขนาด21ไบต์สำหรับอักขระ ASCII 20 ตัวบนดิสก์และ23ไบต์ใน RAM การประเมินรายละเอียด:

ข้อสำคัญ: COLLATIONกฎสามารถทำให้การเรียงลำดับข้อมูลอักขระมีราคาแพงกว่าซึ่งแตกต่างจากชนิดข้อมูลตัวเลข:

ขนาดดัชนีอาจเป็นสาเหตุของส่วนแบ่งประสิทธิภาพที่แตกต่างกันในกรณีส่วนใหญ่ พิจารณาค่าใช้จ่ายต่อ tuple ดัชนี (โดยทั่วไปเหมือนกับตาราง): 4 ไบต์สำหรับตัวชี้รายการและ24 ไบต์สำหรับส่วนหัวของ tuple ดังนั้น tuple ของดัชนีintegerจะเท่ากับ36 ไบต์ (รวมถึง 4 ไบต์ของการขยายการจัดตำแหน่ง ) และสำหรับvarchar(20)20 อักขระ ASCII ก็จะเป็น52 ไบต์ (รวมถึงการขยายด้วย) รายละเอียด:

ทุกทฤษฎีกัน: ที่ดีที่สุดคือเพียงทดสอบ:

Postgres 9.5แนะนำการเพิ่มประสิทธิภาพสำหรับการเรียงลำดับสตริงข้อมูลอักขระยาว (คำสำคัญ"คีย์ตัวย่อ" ) แต่ข้อผิดพลาดในบางฟังก์ชั่นไลบรารี C บน Linux บังคับให้โครงการปิดใช้งานคุณลักษณะนี้สำหรับการเปรียบเทียบที่ไม่ใช่ C ใน Postgres 9.5.2 รายละเอียดในบันทึกประจำรุ่น

อย่างไรก็ตามหากคุณใช้enumชนิดPostgres จริงๆสิ่งที่ต้องพิจารณาเหล่านี้ส่วนใหญ่จะไม่เกี่ยวข้องเนื่องจากสิ่งเหล่านี้จะถูกนำไปใช้กับintegerค่าภายใน คู่มือ:

enumค่าตรงบริเวณสี่ไบต์บนดิสก์

นอกเหนือ: varchar(255)ใช้เพื่อให้เข้าใจได้ง่ายสำหรับ SQL Server เวอร์ชันก่อนหน้าซึ่งสามารถใช้ชนิดข้อมูลที่มีประสิทธิภาพมากขึ้นภายในได้สูงสุดถึง 255 อักขระ แต่การจำกัดความยาวตัวอักขระ 255 ตัวไม่มีผลกระทบต่อประสิทธิภาพการทำงานของ Postgres เลย


1
ไม่มีการซ่อนการเพิ่มประสิทธิภาพใน SQL Server สำหรับเทียบเช่นvarchar(255) varchar(260)อาจมีเรื่องดังกล่าวกับ SQL Server 6.x แต่สิ่งนี้ไม่เป็นความจริงเป็นเวลานาน
a_horse_with_no_name

@a_horse_with_no_name: ขอบคุณฉันชี้แจงตาม
Erwin Brandstetter

ขออภัยสำหรับการถ่ายนานมากจะยอมรับเรื่องนี้ผมได้รับช้าในการพัฒนาโครงการที่;)
คริส Cirefice

คำตอบนี้ยังใช้ได้กับ Postgres 10 หรือเปล่า?
Matty

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