SQL SELECT speed int เทียบกับ varchar


110

ฉันอยู่ในขั้นตอนการสร้างตารางและมันทำให้ฉันสงสัย

ถ้าฉันเก็บไว้บอกว่ารถที่มียี่ห้อ (fx BMW, Audi ect.) มันจะสร้างความแตกต่างกับความเร็วในการสืบค้นหรือไม่ถ้าฉันเก็บ make เป็น int หรือ varchar

ก็คือ

SELECT * FROM table WHERE make = 5 AND ...;

เร็ว / ช้ากว่า

SELECT * FROM table WHERE make = 'audi' AND ...;

หรือความเร็วจะมากหรือน้อยเท่ากัน?

คำตอบ:


100

การเปรียบเทียบ Int นั้นเร็วกว่าการเปรียบเทียบ varchar สำหรับข้อเท็จจริงง่ายๆที่ ints ใช้พื้นที่น้อยกว่า varchars

สิ่งนี้ถือเป็นจริงทั้งสำหรับการเข้าถึงที่ไม่ได้จัดทำดัชนีและการจัดทำดัชนี วิธีที่เร็วที่สุดคือคอลัมน์ int ที่จัดทำดัชนี


จากที่ฉันเห็นคุณติดแท็กคำถาม postgreql คุณอาจสนใจการใช้พื้นที่ของประเภทวันที่ต่างๆ:

  • intฟิลด์ครอบครองระหว่าง 2 ถึง 8 ไบต์โดยที่ 4 มักจะเกินพอ (-2147483648 ถึง +2147483647)
  • รูปแบบตัวอักษรครอบครอง4 ไบต์บวกสตริงที่เกิดขึ้นจริง

13
คุณกำลังอ้างถึงหน้า 7.4 ในเวอร์ชันใหม่จะใช้ความยาว 1 ไบต์ + หากคุณมี <126 ไบต์ นอกจากนี้โปรดทราบว่าเหตุผลที่สตริงช้ากว่ามากมักจะเป็นการเปรียบเทียบที่ไวต่อการเรียงลำดับนั้นมีราคาแพงมหาศาลไม่ใช่ว่าสตริงจะใช้พื้นที่มากกว่า แต่ผลสุดท้ายก็เหมือนเดิมแน่นอน
Magnus Hagander

@ แม็กนัส - ขอบคุณสำหรับการแจ้งเตือน อย่าลังเลที่จะแก้ไขคำตอบของฉันเนื่องจากฉันเห็นว่าคุณมีคะแนนตัวแทนเพียงพอ
Robert Munteanu

"ไม่ใช่ว่าสตริงจะใช้พื้นที่มากกว่า" ... สตริงของอักขระที่สูงกว่าขนาดต่ำสุดจะใช้พื้นที่มากกว่าตัวเลขที่มีความแม่นยำสูงเนื่องจากตัวเลข (เอกพจน์) มีหน่วยคงที่สตริงจึงเป็นประเภทรวมเสมอ . 8 ไบต์สำหรับตัวเลข 64 บิต 4 ไบต์ต่ออักขระในสตริงรวมทั้งไบต์ความยาวหรือโครงสร้าง หรืออักขระเทอร์มิเนเตอร์อื่นสำหรับการใช้งานที่ไร้เดียงสาอย่างไม่น่าเชื่อ ...
MrMesees

@RobertMunteanu เฮ้โรเบิร์ตขอโทษที่ฉันรู้ว่านี่เป็นโพสต์เก่า แต่ฉันสามารถตรวจสอบ ... ต่อไปนี้ได้ไหม: ในการค้นหาจำนวนเต็มฉันต้องเชื่อมโยงแต่ละคอลัมน์สตริงกับตารางอื่น (ความสัมพันธ์) อย่างไรก็ตามนั่นหมายความว่าจำเป็นต้องมีการดำเนินการเข้าร่วมเพิ่มเติมสำหรับแต่ละแบบสอบถาม ฉันจะตรวจสอบได้อย่างไรว่าการแลกเปลี่ยนนี้คุ้มค่าหรือไม่? ขอบคุณ!
AiRiFiEd

2
"เปรียบเทียบ Int จะเร็วกว่าการเปรียบเทียบ varchar สำหรับความจริงง่ายๆที่ ints ใช้พื้นที่มากน้อยกว่า varchars" - นี้ไม่เป็นความจริงโดยทั่วไป ขึ้นอยู่กับ DBMS ที่คุณใช้และประเภทข้อมูลและสตริงที่แน่นอนที่คุณต้องการแทรกอาจกลายเป็นว่า ints 8 ไบต์ของคุณยาวกว่า ascii varchars ที่มีรหัสข้อความที่มีความยาวเฉลี่ย 3-4 ตัวอักษร ดังนั้นคำตอบนี้ - ไม่ชัดเจนและไม่มีบริบทที่เฉพาะเจาะจงหรือผลการทดลอง - ไม่ได้ตอบคำถามจริงๆ ทุกคนรู้ว่า varchars ได้รับอนุญาตให้ใช้พื้นที่มากกว่า ints แต่ไม่จำเป็นต้องทำ
Marcin Wojnarski

37

เกณฑ์มาตรฐานคร่าวๆ:

4 ล้านบันทึกใน Postgres 9.x

Table A = base table with some columns
Table B = Table A + extra column id of type bigint with random numbers
Table C = Table A + extra column id of type text with random 16-char ASCII strings

ผลลัพธ์บนแล็ปท็อป RAM 8GB, i7, SSD:

Size on disk:                A=261MB        B=292MB        C=322MB
Non-indexed by id: select count(*), select by id: 450ms same on all tables
Insert* one row per TX:       B=9ms/record        C=9ms/record
Bulk insert* in single TX:    B=140usec/record    C=180usec/record
Indexed by id, select by id:  B=about 200us       C=about 200us

* inserts to the table already containing 4M records

ดังนั้นดูเหมือนว่าการตั้งค่านี้ตราบใดที่ดัชนีของคุณพอดีกับ RAM ข้อความ bigint เทียบกับ 16-char จะไม่มีความแตกต่างในด้านความเร็ว


6
น่าสนใจมาก. ความแตกต่างเป็นเรื่องเล็กน้อยได้อย่างไร?
Chibueze Opata

18

มันจะเร็วขึ้นเล็กน้อยโดยใช้ int แทน varchar สิ่งที่สำคัญกว่าสำหรับความเร็วคือการมีดัชนีบนฟิลด์ที่แบบสอบถามสามารถใช้เพื่อค้นหาเรกคอร์ด

มีอีกเหตุผลหนึ่งที่ต้องใช้ int และนั่นคือการทำให้ฐานข้อมูลเป็นปกติ แทนที่จะเก็บข้อความ 'Mercedes-Benz' ไว้หลายพันครั้งในตารางคุณควรจัดเก็บ ID และเก็บชื่อแบรนด์ไว้ในตารางแยกต่างหาก


คุณช่วยอธิบายเพิ่มเติมได้ไหม คุณหมายความว่าแทนที่จะMercedes-Benzไปหลายพันร้านค้าครั้ง 1ID ตัวอย่างเช่นตารางcar_brandsคอลัมน์BrandsและId. แถวMercedes-Benzและ1. และในคอลัมน์ตารางหลักและความคุ้มค่าBrands 1และเมื่อSELECTแล้วเป็นครั้งแรกที่ได้รับIdจากตารางแล้วcar_brands SELECT Something FROM main_table WHERE Brands = (SELECT Id FROM car_brands WHERE Brands = Mercedes-Benz)หรือแนวทางอื่น ๆ ?
Andris

3
@ user2118559: ใช่นั่นคือวิธีการจัดเก็บ select something from main_table c inner join car_brands b on b.Id = c.Brands where b.Brands = 'Mercedes-Benz'เพื่อให้ได้ข้อมูลที่คุณมักจะใช้เข้าร่วมมากกว่าแบบสอบถามย่อย:
Guffa

ทำไมต้องโหวตลง? หากคุณไม่อธิบายสิ่งที่คุณคิดว่าผิดมันก็ไม่สามารถปรับปรุงคำตอบได้
Guffa

8

การแจกแจงประสิทธิภาพที่แท้จริงของการเปรียบเทียบสตริงกับแบบไม่ลอยในกรณีนี้ขนาดใดก็ตามที่ไม่ได้ลงนามและลงนามก็ไม่สำคัญ ขนาดคือความแตกต่างที่แท้จริงของประสิทธิภาพ ไม่ว่าจะเป็น 1byte + (สูงสุด 126bytes) เทียบกับการเปรียบเทียบ 1,2,4 หรือ 8 byte ... เห็นได้ชัดว่า non-float มีขนาดเล็กกว่าสตริงและลอยดังนั้นจึงเป็นมิตรกับ CPU ในการประกอบ

การเปรียบเทียบสตริงกับสตริงในทุกภาษาช้ากว่าสิ่งที่ CPU สามารถเปรียบเทียบได้ใน 1 คำสั่ง แม้แต่การเปรียบเทียบ 8 ไบต์ (64 บิต) กับ CPU 32 บิตก็ยังเร็วกว่า VARCHAR (2) หรือใหญ่กว่า * อีกครั้งดูที่ชุดประกอบที่ผลิต (แม้จะทำด้วยมือ) ต้องใช้คำแนะนำเพิ่มเติมในการเปรียบเทียบถ่านโดยถ่านที่มากกว่าตัวเลข CPU 1 ถึง 8 ไบต์

ตอนนี้เร็วขึ้นแค่ไหน? ขึ้นอยู่กับปริมาณข้อมูลด้วย หากคุณกำลังเปรียบเทียบ 5 กับ 'audi' - และนั่นคือ DB ทั้งหมดของคุณความแตกต่างที่เกิดขึ้นนั้นน้อยมากที่คุณจะไม่เคยเห็น ขึ้นอยู่กับ CPU การใช้งาน (ไคลเอนต์ / เซิร์ฟเวอร์เว็บ / สคริปต์ ฯลฯ ) คุณอาจจะไม่เห็นมันจนกว่าคุณจะมีการเปรียบเทียบบนเซิร์ฟเวอร์ DB ไม่กี่ร้อยครั้ง (อาจถึงสองพันเปรียบเทียบก่อนที่จะสังเกตเห็นได้)

  • เพื่อให้ข้อพิพาทที่ไม่ถูกต้องเกี่ยวกับการเปรียบเทียบแฮชเป็นโมฆะ อัลกอริทึมการแฮชส่วนใหญ่ทำงานช้าดังนั้นคุณจึงไม่ได้รับประโยชน์จากสิ่งต่างๆเช่น CRC64 และเล็กกว่า เป็นเวลากว่า 12 ปีที่ฉันพัฒนาอัลกอริทึมการค้นหาสำหรับเครื่องมือค้นหาหลายเขตและ 7 ปีสำหรับสำนักงานเครดิต ทุกสิ่งที่คุณสามารถเก็บเป็นตัวเลขได้เร็วขึ้น ... ตัวอย่างเช่นหมายเลขโทรศัพท์รหัสไปรษณีย์แม้แต่สกุลเงิน * 1000 (ที่เก็บข้อมูล) สกุลเงิน div 1000 (การเรียกค้น) จะเร็วกว่า DECIMAL สำหรับการเปรียบเทียบ

Ozz


6

ดัชนีหรือไม่ int เร็วขึ้นมาก (ยิ่ง varchar นานเท่าไรก็ยิ่งได้รับช้าลง)

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


3
ตัวอย่างเช่น 5 ล้านรายการของ "audi" ดัชนีจะไม่เก็บเพียงชุดเดียวของสตริง "audi" และจำนวนเต็ม 5 ล้านจำนวนเต็มของ primary_key หรือไม่ ความแตกต่างของขนาดจะใหญ่ขนาดนั้นจริง ๆ ไม่ว่าจะเป็น vchar หรือจำนวนเต็ม?
lulalala

คุณพูดถูก lulalala แต่สำหรับคอลัมน์ที่จะมีสตริงแบบสุ่มคำตอบนั้นยุติธรรมเพียงพอ
Awais fiaz


3

คำแนะนำ: ถ้าค่าที่เป็นไปได้สำหรับสนามแต่งหน้าจะไม่เคย (หรือไม่ค่อย) การเปลี่ยนแปลงที่คุณสามารถใช้ ENUM ประนีประนอม มันรวมความเร็วที่ดีกับการอ่านที่ดี


1
ที่น่าสนใจความแตกต่างของความเร็วระหว่าง ENUM และ int จะเป็นอย่างไร
googletorp

PostgresSQL มีenumประเภทข้อมูลหรือไม่ ฉันแม้ว่ามันเป็นเฉพาะ MySQL
Robert Munteanu

Postgres มี ENUM แต่ฉันไม่คิดว่าจะใช้งานได้เหมือนกับ MySQL postgresql.org/docs/current/static/datatype-enum.html
googletorp

2
ประสิทธิภาพที่ชาญฉลาด ENUM ควรทำงานมากหรือน้อยเช่นเดียวกับ int ในช่องค้นหา แต่เป็น varchar ในรายการเป้าหมาย (เนื่องจากต้องถ่ายโอนสตริงทั้งหมดไปยังไคลเอ็นต์เพื่อให้แถวที่ตรงกันไม่ใช่เฉพาะ int)
Magnus Hagander

1
นี่คือการอ่านที่น่าสนใจเกี่ยวกับสาเหตุที่ไม่ใช้ enum ใน MySQL (เพียงเพื่อเติมเชื้อเพลิงให้กับไฟ: D)
เหี่ยว

1

หากคุณเปิดการจัดทำดัชนีในฟิลด์ใดฟิลด์หนึ่งก็จะเร็วขึ้น สำหรับคำถามของคุณผมคิดว่าจะเร็วกว่าintvarchar


0

ค่อนข้างญาติ ใช่ INT จะเร็วขึ้น แต่คำถามคือหากเห็นได้ชัดเจนในสถานการณ์ของคุณ VARCHAR เป็นเพียงคำเล็ก ๆ หรือข้อความที่ยาวกว่า? และมีกี่แถวในตาราง? หากมีเพียงไม่กี่แถวก็มักจะถูกบัฟเฟอร์ทั้งหมดในหน่วยความจำ (เมื่อมีการร้องขอบ่อยครั้ง) ในกรณีนี้คุณจะไม่สังเกตเห็นความแตกต่างมากนัก แน่นอนว่ามีการจัดทำดัชนีซึ่งจะมีความสำคัญมากขึ้นเมื่อตารางเติบโตขึ้น การใช้ SSD อาจเร็วกว่า HD ด้วยการสืบค้นที่ปรับให้เหมาะสม นอกจากนี้ตัวควบคุมดิสก์ที่ดีบางครั้งก็เร่งความเร็วในการสืบค้น> 10x สิ่งนี้อาจเหลือที่ว่างสำหรับการใช้ VARCHAR ซึ่งทำให้การอ่านและการเขียนแบบสอบถามง่ายขึ้น (ไม่จำเป็นต้องเขียนการรวมที่ซับซ้อน) และเร่งการพัฒนา อย่างไรก็ตามพวกเจ้าระเบียบจะไม่เห็นด้วยและทำให้ทุกอย่างเป็นปกติ

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