มีความแตกต่างของประสิทธิภาพจริงระหว่างคีย์หลักของ INT และ VARCHAR หรือไม่


174

มีความแตกต่างของประสิทธิภาพที่วัดได้ระหว่างการใช้ INT กับ VARCHAR เป็นคีย์หลักใน MySQL หรือไม่ ฉันต้องการใช้ VARCHAR เป็นคีย์หลักสำหรับรายการอ้างอิง (คิดว่าสหรัฐฯรหัสประเทศ) และผู้ร่วมงานจะไม่ขยับเขยื่อนไปที่ INT AUTO_INCREMENT เป็นคีย์หลักสำหรับทุกตาราง

ข้อโต้แย้งของฉันตามรายละเอียดที่นี่คือความแตกต่างของประสิทธิภาพระหว่าง INT และ VARCHAR นั้นเล็กน้อยเนื่องจากการอ้างอิงคีย์ต่างประเทศทุก INT จะต้องมีการเข้าร่วมเพื่อให้เข้าใจถึงการอ้างอิงคีย์ VARCHAR จะนำเสนอข้อมูลโดยตรง

ดังนั้นไม่มีใครมีประสบการณ์กับกรณีการใช้งานเฉพาะนี้และความกังวลเกี่ยวกับประสิทธิภาพที่เกี่ยวข้องหรือไม่


3
ฉันโพสต์ด้วยคำตอบ "ไม่" พร้อมรายละเอียดการทดสอบที่ฉันใช้ ... แต่นั่นคือ SQL Server ไม่ใช่ MySQL ดังนั้นฉันจึงลบคำตอบของฉัน
Timothy Khouri

17
@ Timothy - คุณไม่ควรลบมัน ฉันอยู่ระหว่างการลงคะแนน เซิร์ฟเวอร์ฐานข้อมูล SQL ส่วนใหญ่มีตัววางแผนคิวรีที่คล้ายกันและคอขวดของประสิทธิภาพที่คล้ายคลึงกัน
พอลทอมบลิน

9
@ Timothy โปรดโพสต์ผลลัพธ์ของคุณใหม่
Jake McGraw

2
ความคิดเห็นและคำตอบมากมายสมมติว่ามีกุญแจที่จะใช้สำหรับการเข้าร่วม พวกเขาจะไม่. มีกุญแจที่จะใช้สำหรับความสอดคล้องของข้อมูล - เพื่อหลีกเลี่ยงแถวที่ซ้ำกัน (มากกว่าหนึ่งแถวที่เป็นตัวแทนของเอนทิตีเดียวกัน) คอลัมน์ใดก็ได้ (หรือชุดของคอลัมน์) สามารถใช้ในการเข้าร่วมได้และเพื่อรับประกันว่าการเข้าร่วมนั้นเป็นหนึ่งในศูนย์หรือหลาย ๆ คอลัมน์ก็ต้องไม่ซ้ำกัน ดัชนีที่เป็นเอกลักษณ์ใด ๆ รับประกันได้ว่าและมันไม่จำเป็นต้องมีความหมาย
Charles Bretana

คำตอบ:


78

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

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

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

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


3
และบางครั้ง (imho, บ่อยครั้ง), ทั้งคู่ดีกว่า, ตัวแทนที่จะใช้สำหรับการอ้างอิง FK ในตารางอื่น, และสำหรับ Joins, และคีย์ธรรมชาติเพื่อรับรองความสอดคล้องของข้อมูล
Charles Bretana

@CharlesBretana นั่นน่าสนใจ การใช้คีย์ธรรมชาติเพื่อความสอดคล้องของข้อมูลทางด้านข้างของ FK เป็นเรื่องธรรมดาหรือไม่? ความคิดแรกของฉันคือพื้นที่เก็บข้อมูลเพิ่มเติมที่จำเป็นสำหรับโต๊ะขนาดใหญ่อาจไม่คุ้มค่า ข้อมูลใด ๆ ที่เป็นที่นิยม FYI - ฉันมีพื้นหลังการเขียนโปรแกรมที่ดี แต่ประสบการณ์ SQL ของฉันถูก จำกัด ส่วนใหญ่เป็นคำสั่ง SELECT
Rob

2
@CharlesBretana เมื่อฉันอ่าน "เก็บทั้งคู่" ฉันคิดว่า "ความซ้ำซ้อน" และ "ไม่ทำให้เป็นมาตรฐาน" ซึ่งเท่ากับ "สิ่งนี้สามารถทำให้ผิดพลาดได้" และ "ฉันต้องทำให้แน่ใจว่าทั้งคู่จะเปลี่ยนไปถ้ามีใครเปลี่ยนไป" หากคุณมีความซ้ำซ้อนควรมีเหตุผลที่ดีมาก (เช่นประสิทธิภาพที่ไม่สามารถยอมรับได้อย่างสมบูรณ์) เนื่องจากความซ้ำซ้อนนั้นอาจเป็นไปได้เสมอที่ข้อมูลของคุณจะไม่สอดคล้องกัน
jpmc26

3
@ jpmc26 ไม่มีปัญหาเกี่ยวกับความซ้ำซ้อนหรือการทำให้เป็นมาตรฐานที่เกี่ยวข้อง คีย์ตัวแทนจะไม่มีการเชื่อมต่อที่มีความหมายกับค่าในคีย์ธรรมชาติดังนั้นจึงไม่จำเป็นต้องเปลี่ยน ในการทำให้เป็นมาตรฐานคุณกำลังพูดถึงประเด็นการทำให้เป็นมาตรฐานอะไร การปรับสภาพให้เป็นมาตรฐานใช้กับคุณลักษณะที่มีความหมายของความสัมพันธ์ ค่าตัวเลขของคีย์ตัวแทน (จริง ๆ แล้วแนวคิดของคีย์ตัวแทน) นั้นอยู่นอกบริบทของการทำให้เป็นมาตรฐาน
Charles Bretana

1
และเพื่อตอบคำถามอื่น ๆ ของคุณโดยเฉพาะเกี่ยวกับสารบัญหากคุณมีรหัสตัวแทนในตารางนี้โดยมีค่าเช่น frpom 1 ถึง 50 แต่คุณไม่ได้ใส่ดัชนีหรือรหัสเฉพาะอื่นลงในรหัสไปรษณีย์ของรัฐ (และในความเห็นของฉันเกี่ยวกับชื่อรัฐเช่นกัน) แล้วอะไรที่จะห้ามไม่ให้ใครบางคนป้อนสองแถวด้วยค่าคีย์ตัวแทนที่แตกต่างกัน แต่ด้วยรหัสไปรษณีย์และ / หรือชื่อรัฐเดียวกัน แอปไคลเอนต์จะจัดการอย่างไรถ้ามีสองแถวด้วย 'NJ', 'New Jersey' คีย์ธรรมชาติช่วยให้มั่นใจความสอดคล้องของข้อมูล!
Charles Bretana

81

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

INT AUTO_INCREMENT ตรงตามเงื่อนไข "ไม่เหมือนใครและไม่เปลี่ยนแปลงตลอดเวลา" ดังนั้นการตั้งค่า


25
จริง หนึ่งในฐานข้อมูลที่ใหญ่ที่สุดของฉันมีรายการสำหรับยูโกสลาเวียและสหภาพโซเวียต ฉันดีใจที่พวกเขาไม่ใช่กุญแจหลัก
พอลทอมบลิน

8
@ Steve แล้วทำไม ANSI SQL ถึงสนับสนุนไวยากรณ์สำหรับวันที่เรียงซ้อน?
Bill Karwin

5
การเปลี่ยนไม่ได้ไม่ใช่ข้อกำหนดของคีย์ ไม่ว่าในกรณีใด ๆ คีย์ตัวแทนอาจเปลี่ยนแปลงด้วยเช่นกัน ไม่มีอะไรผิดปกติกับการเปลี่ยนปุ่มหากคุณต้องการ
nvogel

9
Paul ดังนั้นคุณเปลี่ยนสหภาพโซเวียตเป็นรัสเซียในฐานข้อมูลของคุณ? และแสร้งว่า SU ไม่มีอยู่จริงเหรอ? และการอ้างอิงทั้งหมดของ SU ตอนนี้ชี้ไปที่รัสเซียหรือไม่
Dainius

6
@alga ฉันเกิดที่ซูดังนั้นฉันจึงรู้ว่ามันคืออะไร
Dainius

52

ฉันค่อนข้างรำคาญกับการขาดมาตรฐานสำหรับออนไลน์ดังนั้นฉันจึงทำการทดสอบด้วยตัวเอง

โปรดทราบว่าฉันไม่ได้ทำตามปกติดังนั้นโปรดตรวจสอบการตั้งค่าและขั้นตอนของฉันสำหรับปัจจัยที่อาจมีผลต่อผลลัพธ์โดยไม่ตั้งใจและโพสต์ข้อกังวลของคุณในความคิดเห็น

การตั้งค่ามีดังนี้:

  • Intel® Core ™ i7-7500U CPU @ 2.70GHz × 4
  • 15.6 GiB RAM ซึ่งฉันมั่นใจว่าประมาณ 8 GB นั้นฟรีในระหว่างการทดสอบ
  • ไดรฟ์ SSD ขนาด 148.6 GB พร้อมพื้นที่ว่างมากมาย
  • Ubuntu 16.04 64 บิต
  • MySQL Ver 14.14 Distrib 5.7.20, สำหรับ Linux (x86_64)

โต๊ะ:

create table jan_int (data1 varchar(255), data2 int(10), myindex tinyint(4)) ENGINE=InnoDB;
create table jan_int_index (data1 varchar(255), data2 int(10), myindex tinyint(4), INDEX (myindex)) ENGINE=InnoDB;
create table jan_char (data1 varchar(255), data2 int(10), myindex char(6)) ENGINE=InnoDB;
create table jan_char_index (data1 varchar(255), data2 int(10), myindex char(6), INDEX (myindex)) ENGINE=InnoDB;
create table jan_varchar (data1 varchar(255), data2 int(10), myindex varchar(63)) ENGINE=InnoDB;
create table jan_varchar_index (data1 varchar(255), data2 int(10), myindex varchar(63), INDEX (myindex)) ENGINE=InnoDB;

จากนั้นฉันเติมเต็ม 10 ล้านแถวในแต่ละตารางด้วยสคริปต์ PHP ที่มีสาระสำคัญดังนี้:

$pdo = get_pdo();

$keys = [ 'alabam', 'massac', 'newyor', 'newham', 'delawa', 'califo', 'nevada', 'texas_', 'florid', 'ohio__' ];

for ($k = 0; $k < 10; $k++) {
    for ($j = 0; $j < 1000; $j++) {
        $val = '';
        for ($i = 0; $i < 1000; $i++) {
            $val .= '("' . generate_random_string() . '", ' . rand (0, 10000) . ', "' . ($keys[rand(0, 9)]) . '"),';
        }
        $val = rtrim($val, ',');
        $pdo->query('INSERT INTO jan_char VALUES ' . $val);
    }
    echo "\n" . ($k + 1) . ' millon(s) rows inserted.';
}

สำหรับintตารางบิต($keys[rand(0, 9)])นั้นถูกแทนที่ด้วย just rand(0, 9)และสำหรับvarcharตารางฉันใช้ชื่อรัฐเต็มของสหรัฐอเมริกาโดยไม่ต้องตัดหรือขยายให้เหลือ 6 อักขระgenerate_random_string()สร้างสตริงสุ่ม 10 ตัวอักษร

จากนั้นฉันก็วิ่งใน MySQL:

  • SET SESSION query_cache_type=0;
  • สำหรับjan_intตาราง:
    • SELECT count(*) FROM jan_int WHERE myindex = 5;
    • SELECT BENCHMARK(1000000000, (SELECT count(*) FROM jan_int WHERE myindex = 5));
  • สำหรับตารางอื่น ๆ เช่นเดียวกับข้างต้นด้วยmyindex = 'califo'สำหรับcharตารางและmyindex = 'california'สำหรับvarcharตาราง

เวลาของBENCHMARKแบบสอบถามในแต่ละตาราง:

  • jan_int: 21.30 วินาที
  • jan_int_index: 18.79 วินาที
  • jan_char: 21.70 วินาที
  • jan_char_index: 18.85 วินาที
  • jan_varchar: 21.76 วินาที
  • jan_varchar_index: 18.86 วินาที

เกี่ยวกับขนาดของตาราง & ดัชนีนี่คือผลลัพธ์ของshow table status from janperformancetest;(ไม่กี่คอลัมน์ที่ไม่แสดง):

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Name              | Engine | Version | Row_format | Rows    | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Collation              |
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| jan_int           | InnoDB |      10 | Dynamic    | 9739094 |             43 |   422510592 |               0 |            0 |   4194304 |           NULL | utf8mb4_unicode_520_ci |  
| jan_int_index     | InnoDB |      10 | Dynamic    | 9740329 |             43 |   420413440 |               0 |    132857856 |   7340032 |           NULL | utf8mb4_unicode_520_ci |   
| jan_char          | InnoDB |      10 | Dynamic    | 9726613 |             51 |   500170752 |               0 |            0 |   5242880 |           NULL | utf8mb4_unicode_520_ci |  
| jan_char_index    | InnoDB |      10 | Dynamic    | 9719059 |             52 |   513802240 |               0 |    202342400 |   5242880 |           NULL | utf8mb4_unicode_520_ci |  
| jan_varchar       | InnoDB |      10 | Dynamic    | 9722049 |             53 |   521142272 |               0 |            0 |   7340032 |           NULL | utf8mb4_unicode_520_ci |   
| jan_varchar_index | InnoDB |      10 | Dynamic    | 9738381 |             49 |   486539264 |               0 |    202375168 |   7340032 |           NULL | utf8mb4_unicode_520_ci | 
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

ข้อสรุปของฉันคือไม่มีประสิทธิภาพแตกต่างกันสำหรับกรณีการใช้งานเฉพาะนี้


ฉันรู้ว่ามันสายไปแล้ว แต่ฉันอยากรู้อยากเห็นผลลัพธ์ถ้าคุณเลือกสตริงที่เหมาะน้อยลงสำหรับสภาพที่ "califo [rnia]" เหมาะอย่างยิ่งเนื่องจากสามารถทิ้งความไม่ตรงกันหลังจากเปรียบเทียบอักขระตัวแรกได้ แต่ต้องตรวจสอบเพิ่มเติมในการแข่งขันจริงเท่านั้น บางอย่างเช่น "newham" จะให้ผลลัพธ์ที่น่าสนใจมากขึ้นเนื่องจากจะเป็นการเปรียบเทียบอักขระใหม่เพื่อกำจัดความไม่ตรงกันทั้งหมด นอกจากนี้การ จำกัด จำนวนเต็มของคุณด้วยวิธีที่จะวางเดิมพันกับพวกเขาฉันจะให้พวกเขาอย่างน้อย 26 ค่า
Uueerdo

15
น่าทึ่งที่ในคำถามอายุ 10 ปีนี่เป็นเพียงหนึ่งในสองคำตอบที่ไม่ได้เป็นเพียงการเก็งกำไรและอาศัยการวัดประสิทธิภาพจริง
Adrian Baker

1
แต่ตารางของคุณไม่มีคีย์หลักซึ่งจริงๆแล้วใน InnoDB เป็นโครงสร้างข้อมูลที่เรียงลำดับแล้ว ความเร็วระหว่างการเรียงจำนวนเต็มและการเรียงลำดับสตริงควรแตกต่างกัน
Melkor

1
จุด @Melkor ยุติธรรมที่ผมใช้แทนINDEX PRIMARY KEYฉันจำเหตุผลของฉันไม่ได้ - ฉันอาจสันนิษฐานว่าPRIMARY KEYเป็นเพียงINDEXข้อ จำกัด ที่มีเอกลักษณ์ อย่างไรก็ตามการอ่านส่วนเกี่ยวกับวิธีการจัดเก็บสิ่งต่าง ๆ ใน InnoDB ในfederico-razzoli.com/primary-key-in-innodbฉันคิดว่าผลลัพธ์ของฉันยังคงนำไปใช้กับคีย์หลักและตอบคำถามเกี่ยวกับประสิทธิภาพการค้นหาค่า นอกจากนี้ความคิดเห็นของคุณยังแนะนำให้ดูประสิทธิภาพของการเรียงลำดับอัลกอริทึมซึ่งไม่สามารถใช้กับกรณีการใช้งานที่ฉันตรวจสอบซึ่งกำลังค้นหาค่าในชุด
ม.ค. Żankowski

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

38

ขึ้นอยู่กับความยาว .. ถ้า varchar จะเป็น 20 ตัวอักษรและ int คือ 4 จากนั้นถ้าคุณใช้ int ดัชนีของคุณจะมีเวลาห้าเท่าเป็นโหนดจำนวนมากต่อหนึ่งหน้าของพื้นที่ดัชนีบนดิสก์ ... นั่นหมายความว่าการสำรวจภายใน ดัชนีจะต้องมีหนึ่งในห้าของจำนวนจริงและ / หรือตรรกะอ่าน

ดังนั้นหากประสิทธิภาพเป็นปัญหาให้โอกาสเสมอใช้คีย์ที่ไม่มีความหมายสำคัญ (เรียกว่าตัวแทน) สำหรับตารางของคุณและสำหรับคีย์ต่างประเทศที่อ้างอิงแถวในตารางเหล่านี้ ...

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

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


แน่ใจหรือไม่? ไม่แถวข้อมูลรูปแบบส่วนใหญ่ตาม? มีข้อมูลอื่นนอกเหนือจากปุ่ม ไม่ใช่ปัจจัย 5 utopic?
ManuelSchneid3r

1
@ manuelSchneid3r อะไรนะ? Utopic? ไม่ปัจจัย 5 ไม่ใช่ "utopic" มันแค่ 20 หารด้วย 4 และ "รูปแบบแถวข้อมูล" หมายถึงอะไร? ดัชนีไม่ใช่ "อิงแถว" ซึ่งเป็นโครงสร้างต้นไม้ที่มีความสมดุล
Charles Bretana

36

ไม่ได้อย่างแน่นอน.

ฉันได้ตรวจสอบประสิทธิภาพหลายครั้ง ... หลายครั้งระหว่าง INT, VARCHAR และ CHAR

ตารางบันทึก 10 ล้านแผ่นพร้อมคีย์หลัก (ไม่เหมือนใครและคลัสเตอร์) มีความเร็วและประสิทธิภาพเท่ากัน (และราคาทรีย่อย) ไม่ว่าจะใช้สามแบบไหน

ที่ถูกกล่าวว่า ... ใช้สิ่งที่ดีที่สุดสำหรับใบสมัครของคุณ ไม่ต้องกังวลกับประสิทธิภาพ


42
ไม่มีความหมายโดยไม่ทราบว่า varchars นานเท่าไหร่ ... ถ้าพวกมันมีขนาด 100 ไบต์ widem รับประกันได้ว่าคุณจะไม่ได้รับประสิทธิภาพเท่ากับ 4 ไบต์ int
Charles Bretana

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

VARCHAR แน่นอนที่สำคัญสำหรับขนาดของดัชนี และดัชนีกำหนดจำนวนหน่วยความจำที่พอดี และดัชนีในหน่วยความจำไกลมากเร็วกว่าที่ไม่ได้เป็น อาจเป็นได้ว่าสำหรับแถว 10 ม. ของคุณคุณมีหน่วยความจำ 250MB สำหรับดัชนีนั้นและไม่เป็นไร แต่ถ้าคุณมี 100m แถวคุณจะไม่ค่อยดีในความทรงจำนั้น
พอลเดรเปอร์

9

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

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


2
คุณรู้หรือไม่ว่าสิ่งนี้จะมีราคาแพง หรือคุณแค่คาดเดา
Steve McLeod

แน่นอนมันขึ้นอยู่กับการนำ rdbms มาใช้ แต่จากสิ่งที่ฉันเข้าใจว่าเซิร์ฟเวอร์ส่วนใหญ่จะเก็บค่าแฮชของมูลค่าที่แท้จริงสำหรับการทำดัชนี ถึงแม้ว่าจะเป็นแฮชสั้น ๆ (เช่น 10 ไบต์) แต่ก็ยังคงทำงานได้ดีกว่าการเปรียบเทียบแฮช 2 10 ไบต์มากกว่า 2 4 ไบต์ ints
Joel Coehoorn

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

6

สำหรับคีย์หลักสิ่งใดก็ตามที่ทำให้เป็นเอกลักษณ์ของแถวควรถูกกำหนดเป็นคีย์หลัก

สำหรับการอ้างอิงเป็น foreign key การใช้จำนวนเต็มที่เพิ่มขึ้นอัตโนมัติเป็นตัวแทนเป็นแนวคิดที่ดีสำหรับสองเหตุผลหลัก
- อันดับแรกมีค่าใช้จ่ายเกิดขึ้นน้อยกว่าในการเข้าร่วมตามปกติ
- ประการที่สองหากคุณจำเป็นต้องอัปเดตตารางที่มี varchar ที่ไม่ซ้ำกันการอัปเดตจะต้องเรียงซ้อนลงในตารางย่อยทั้งหมดและอัปเดตทั้งหมดรวมถึงดัชนีในขณะที่มีตัวแทนตัวแทนจะต้องอัปเดต ตารางต้นแบบและดัชนีของมัน

ข้อเสียเปรียบที่จะใช้ตัวแทนคือคุณอาจอนุญาตให้เปลี่ยนความหมายของตัวแทน:

ex.
id value
1 A
2 B
3 C

Update 3 to D
id value
1 A
2 B
3 D

Update 2 to C
id value
1 A
2 C
3 D

Update 3 to B
id value
1 A
2 C
3 B

ทุกอย่างขึ้นอยู่กับสิ่งที่คุณต้องกังวลในโครงสร้างของคุณและสิ่งที่มีความหมายมากที่สุด


3

กรณีทั่วไปที่ตัวแทนAUTO_INCREMENTเจ็บปวด:

รูปแบบสคีมาทั่วไปคือการทำแผนที่หลายต่อหลายคน :

CREATE TABLE map (
    id ... AUTO_INCREMENT,
    foo_id ...,
    bar_id ...,
    PRIMARY KEY(id),
    UNIQUE(foo_id, bar_id),
    INDEX(bar_id) );

ประสิทธิภาพของรูปแบบนี้ดีขึ้นมากโดยเฉพาะเมื่อใช้ InnoDB:

CREATE TABLE map (
    # No surrogate
    foo_id ...,
    bar_id ...,
    PRIMARY KEY(foo_id, bar_id),
    INDEX      (bar_id, foo_id) );

ทำไม?

  • ปุ่มรอง InnoDB ต้องการการค้นหาพิเศษ โดยการย้ายทั้งคู่เข้าไปใน PK ซึ่งหลีกเลี่ยงได้ในทิศทางเดียว
  • ดัชนีรองคือ "ครอบคลุม" ดังนั้นจึงไม่จำเป็นต้องค้นหาเพิ่มเติม
  • ตารางนี้มีขนาดเล็กลงเนื่องจากการกำจัดidและดัชนีหนึ่งรายการ

อีกกรณี ( ประเทศ ):

country_id INT ...
-- versus
country_code CHAR(2) CHARACTER SET ascii

ทั้งหมดนี้บ่อยครั้งที่ผู้ฝึกหัดจะปรับ Country_code ให้เป็น 4 ไบต์INTแทนการใช้ 'ไบต์' 2 ไบต์ 'แบบธรรมชาติ' ซึ่งเป็นสตริงขนาด 2 ไบต์ที่เกือบจะไม่มีการเปลี่ยนแปลง เข้าร่วมได้เร็วขึ้นเล็กลงและอ่านน้อยลง


2

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

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


2

ฉันเผชิญภาวะที่กลืนไม่เข้าคายไม่ออกเดียวกัน ฉันสร้าง DW (Constellation schema) ด้วยตารางข้อเท็จจริง 3 แบบ, อุบัติเหตุบนท้องถนน, ยานพาหนะในอุบัติเหตุและการบาดเจ็บล้มตายจากอุบัติเหตุ ข้อมูลรวมถึงอุบัติเหตุทั้งหมดที่บันทึกในสหราชอาณาจักรตั้งแต่ปี 2522 ถึง 2555 และตาราง 60 มิติ ทั้งหมดรวมกันประมาณ 20 ล้านบันทึก

ความสัมพันธ์ตารางข้อเท็จจริง:

+----------+          +---------+
| Accident |>--------<| Vehicle |
+-----v----+ 1      * +----v----+
     1|                    |1
      |    +----------+    |
      +---<| Casualty |>---+
         * +----------+ *

RDMS: MySQL 5.6

โดยทั่วไปดัชนีอุบัติเหตุคือ varchar (ตัวเลขและตัวอักษร) โดยมี 15 หลัก ฉันพยายามที่จะไม่มีกุญแจตัวแทนเมื่อดัชนีอุบัติเหตุจะไม่เปลี่ยนแปลง ในคอมพิวเตอร์ i7 (8 คอร์) DW นั้นช้าเกินกว่าที่จะสืบค้นหลังจากโหลดได้ 12 ล้านเร็กคอร์ดขึ้นอยู่กับขนาด หลังจากใช้งานซ้ำแล้วซ้ำอีกและเพิ่มปุ่มตัวแทนที่ใหญ่มากฉันได้รับการเพิ่มประสิทธิภาพความเร็วเฉลี่ย 20% ยังได้รับประสิทธิภาพต่ำ แต่ลองถูกต้อง ฉันทำงานในการปรับแต่ง MySQL และการจัดกลุ่ม


1
ดูเหมือนคุณจะต้องมองเข้าไปที่การแบ่งพาร์ติชัน
jcoffland

2

คำถามเกี่ยวกับ MySQL ดังนั้นฉันบอกว่ามีความแตกต่างที่สำคัญ ถ้ามันเกี่ยวกับ Oracle (ซึ่งเก็บตัวเลขเป็นสตริง - ใช่ฉันไม่อยากจะเชื่อเลยในตอนแรก) ก็ไม่ต่างกันมากนัก

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

สิ่งที่เป็นข้อเสนอของ CPU ที่มี 4 ไบต์และ 8 จำนวนเต็มไบต์ธรรมชาติในซิลิกอน มันเร็วมากที่จะเปรียบเทียบจำนวนเต็มสองจำนวน - มันเกิดขึ้นในหนึ่งหรือสองรอบนาฬิกา

ตอนนี้ดูสตริง - มันประกอบด้วยอักขระจำนวนมาก (มากกว่าหนึ่งไบต์ต่ออักขระในวันนี้) การเปรียบเทียบสองสายเพื่อนำหน้าไม่สามารถทำได้ในหนึ่งหรือสองรอบ แต่จะต้องทำซ้ำอักขระของสตริงจนกว่าจะพบความแตกต่าง ฉันแน่ใจว่ามีเทคนิคที่จะทำให้เร็วขึ้นในฐานข้อมูลบางอย่าง แต่นั่นไม่เกี่ยวข้องกับที่นี่เพราะการเปรียบเทียบ int ทำตามธรรมชาติและฟ้าผ่าเร็วในซิลิคอนโดยซีพียู

กฎทั่วไปของฉัน - คีย์หลักทุกอันควรเป็น autoincrementing INT โดยเฉพาะอย่างยิ่งในแอป OO โดยใช้ ORM (Hibernate, Datanucleus, อะไรก็ตาม) ที่มีความสัมพันธ์ระหว่างวัตถุมากมาย - โดยปกติแล้วพวกมันจะถูกใช้เป็น FK อย่างง่ายและความสามารถ ฐานข้อมูลเพื่อแก้ไขความรวดเร็วเหล่านั้นมีความสำคัญต่อการตอบสนองของแอปของคุณ


0

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


0

ตามปกติไม่มีคำตอบแบบครอบคลุม 'มันขึ้นอยู่กับ!' และฉันไม่ได้เป็นคนขี้กลัว ความเข้าใจของฉันเกี่ยวกับคำถามเดิมสำหรับคีย์บนตารางเล็ก ๆ เช่นประเทศ (รหัสจำนวนเต็มหรือรหัส char / varchar) เป็นคีย์ต่างประเทศไปยังตารางขนาดใหญ่ที่อาจเกิดขึ้นเช่นตารางที่อยู่ / ติดต่อ

มีสองสถานการณ์ที่นี่เมื่อคุณต้องการข้อมูลกลับจากฐานข้อมูล อันดับแรกคือรายการ / ประเภทการสืบค้นของแบบสอบถามที่คุณต้องการแสดงรายชื่อผู้ติดต่อทั้งหมดด้วยรหัสรัฐและประเทศหรือชื่อ (รหัสจะไม่ช่วยและจะต้องค้นหา) อีกเหตุการณ์หนึ่งคือรับสถานการณ์ในคีย์หลักซึ่งแสดงระเบียนรายชื่อติดต่อเดียวที่ชื่อรัฐต้องแสดงประเทศ

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

เนื่องจากรหัสมีขนาดเล็ก - ปกติไม่เกิน 3 ตัวอักษรสำหรับประเทศและรัฐจึงอาจใช้คีย์ธรรมชาติเป็นคีย์ต่างประเทศในสถานการณ์นี้

สถานการณ์อื่น ๆ ที่คีย์ขึ้นอยู่กับค่า varchar ที่ยาวนานขึ้นและอาจอยู่ในตารางที่ใหญ่กว่า คีย์ตัวแทนอาจมีข้อได้เปรียบ


0

ให้ฉันบอกว่าใช่มีความแตกต่างอย่างแน่นอนโดยคำนึงถึงขอบเขตของประสิทธิภาพ (คำจำกัดความนอกกรอบ):

1- การใช้ตัวแทนเสมือนนั้นเร็วกว่าในแอปพลิเคชั่นเพราะคุณไม่จำเป็นต้องใช้ ToUpper (), ToLower (), ToUpperInvarient () หรือ ToLowerInvarient () ในรหัสของคุณหรือในแบบสอบถามของคุณ ดูกฎการปฏิบัติงานของ Microsoft เกี่ยวกับสิ่งนี้ (ประสิทธิภาพการใช้งาน)

2- การใช้ตัวแทนเสมือนรับประกันว่าจะไม่เปลี่ยนกุญแจเมื่อเวลาผ่านไป แม้แต่รหัสประเทศอาจเปลี่ยนแปลงได้โปรดดู Wikipedia ว่ารหัส ISO เปลี่ยนแปลงไปอย่างไรเมื่อเวลาผ่านไป ซึ่งจะใช้เวลาในการเปลี่ยนคีย์หลักสำหรับ subtrees (ประสิทธิภาพของการบำรุงรักษาข้อมูล)

3- ดูเหมือนว่ามีปัญหาเกี่ยวกับโซลูชัน ORM เช่น NHibernate เมื่อ PK / FK ไม่ได้เป็น int (ประสิทธิภาพของนักพัฒนา)

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