INT और VARCHAR प्राथमिक कुंजियों के बीच वास्तविक प्रदर्शन अंतर है?


174

क्या MySQL में प्राथमिक कुंजी के रूप में INT बनाम VARCHAR का उपयोग करने के बीच एक औसत दर्जे का प्रदर्शन अंतर है? मैं संदर्भ सूचियों के लिए प्राथमिक कुंजी के रूप में VARCHAR का उपयोग करना चाहता हूं (यूएस स्टेट्स, कंट्री कोड्स) और एक सहकर्मी INT AUTO_INCREMENT पर सभी तालिकाओं के लिए एक प्राथमिक कुंजी के रूप में नहीं देखेगा।

मेरा तर्क, जैसा कि यहां विस्तृत है , यह है कि INT और VARCHAR के बीच प्रदर्शन अंतर नगण्य है, क्योंकि प्रत्येक INT विदेशी कुंजी संदर्भ को संदर्भ की भावना बनाने के लिए एक JOIN की आवश्यकता होगी, एक VARCHAR कुंजी सीधे जानकारी प्रस्तुत करेगी।

तो, क्या किसी को इस विशेष उपयोग-मामले और इसके साथ जुड़े प्रदर्शन की चिंताओं का अनुभव है?


3
मैंने उत्तर "नहीं" के साथ एक पोस्ट किया है जिसमें मैंने कुछ परीक्षण किए हैं ... लेकिन वह SQL सर्वर था, MySQL नहीं। इसलिए मैंने अपना उत्तर हटा दिया।
टिमोथी खौरी

17
@ टिमोथी - आपको इसे हटाना नहीं चाहिए था। मैं इसे मतदान करने की प्रक्रिया में था। अधिकांश SQL डेटाबेस सर्वर में समान क्वेरी प्लानर और समान प्रदर्शन अड़चनें होती हैं।
पॉल टॉम्बलिन

9
@ तीमुथियुस कृपया अपने परिणामों को फिर से लिखें।
जेक मैकग्रॉ

2
इतनी सारी टिप्पणियाँ और उत्तर मान लेते हैं कि कुंजियों का उपयोग जॉइन के लिए किया जाना है। वो नहीं हैं। डेटा संगति के लिए कुंजी का उपयोग किया जाता है - डुप्लिकेट पंक्तियों से बचने के लिए, (एक ही इकाई का प्रतिनिधित्व करने वाली एक से अधिक पंक्ति)। किसी भी कॉलम (या कॉलम का सेट) का उपयोग एक जॉइन में किया जा सकता है, और यह गारंटी देने के लिए कि जॉइन एक-से-शून्य या कई कॉलम है [s] बस यूनिक होने की जरूरत है। कोई भी अद्वितीय सूचकांक इसकी गारंटी देता है, और इसे सार्थक होने की आवश्यकता नहीं है।
चार्ल्स ब्रेटाना

जवाबों:


78

आप एक अच्छी बात यह है कि आप एक सरोगेट कुंजी के बजाय एक प्राकृतिक कुंजी कहा जाता है का उपयोग करके कुछ शामिल प्रश्नों से बच सकते हैं । केवल तभी आप आकलन कर सकते हैं कि इसका लाभ आपके आवेदन में महत्वपूर्ण है।

यही है, आप अपने आवेदन में उन प्रश्नों को माप सकते हैं जो सबसे तेज़ होने के लिए सबसे महत्वपूर्ण हैं, क्योंकि वे बड़ी मात्रा में डेटा के साथ काम करते हैं या उन्हें बहुत बार निष्पादित किया जाता है। यदि ये क्वेरी किसी ज्वाइन को समाप्त करने से लाभान्वित होते हैं, और एक varchar प्राथमिक कुंजी का उपयोग करके पीड़ित नहीं होते हैं, तो इसे करें।

अपने डेटाबेस में सभी तालिकाओं के लिए या तो रणनीति का उपयोग न करें। यह संभावना है कि कुछ मामलों में, एक प्राकृतिक कुंजी बेहतर है, लेकिन अन्य मामलों में एक सरोगेट कुंजी बेहतर है।

अन्य लोग एक अच्छी बात करते हैं कि यह प्राकृतिक कुंजी के लिए अभ्यास में दुर्लभ है कि कभी न बदलें या डुप्लिकेट न हो, इसलिए सरोगेट कुंजी आमतौर पर सार्थक हैं।


3
और कभी-कभी, (imho, अक्सर), दोनों बेहतर है, अन्य तालिकाओं में एफके संदर्भों के लिए उपयोग करने के लिए सरोगेट, और जोड़ों के लिए, और डेटा संगतता सुनिश्चित करने के लिए प्राकृतिक कुंजी
चार्ल्स ब्रेटाना

@CharlesBretana दिलचस्प है। FK के साथ डेटा संगति के लिए एक प्राकृतिक कुंजी का उपयोग करना एक आम बात है? मेरा पहला विचार यह था कि बड़ी मेज पर जो अतिरिक्त भंडारण की आवश्यकता होगी, वह इसे सार्थक नहीं कर सकता है। किसी भी जानकारी की सराहना की है। FYI करें - मेरे पास एक सभ्य प्रोग्रामिंग पृष्ठभूमि है लेकिन मेरा SQL अनुभव ज्यादातर चुनिंदा प्रश्नों तक ही सीमित है
Rob

2
@CharlesBretana जब मैं "इन दोनों को संग्रहीत करता हूं" पढ़ता हूं, तो मुझे लगता है कि "अतिरेक" और "सामान्यीकृत नहीं", जो कि "यह सामान खराब हो सकता है" के बराबर है और "मुझे यकीन है कि दोनों को बदल दिया जाता है अगर एक कभी बदल जाता है"। यदि आपके पास अतिरेक है, तो एक बहुत अच्छा कारण होना चाहिए (जैसे पूरी तरह से अस्वीकार्य प्रदर्शन) क्योंकि अतिरेक हमेशा आपके डेटा के असंगत होने की संभावना है।
jpmc26

3
@ jpmc26, अतिरेक या सामान्यीकरण के बिल्कुल कोई मुद्दे नहीं हैं। एक सरोगेट कुंजी का प्राकृतिक कुंजी में मूल्यों से कोई सार्थक संबंध नहीं है, इसलिए इसे बदलने की आवश्यकता नहीं होनी चाहिए। सामान्यीकरण के रूप में, आप किन सामान्यीकरण मुद्दों के बारे में बात कर रहे हैं? सामान्यीकरण किसी संबंध की सार्थक विशेषताओं पर लागू होता है; एक सरोगेट कुंजी का संख्यात्मक मूल्य, (वास्तव में, एक सरोगेट कुंजी की बहुत अवधारणा) किसी भी सामान्यीकरण के संदर्भ के बाहर पूरी तरह से निहित है।
चार्ल्स ब्रेटाना

1
और आपके अन्य प्रश्न का उत्तर देने के लिए, विशेष रूप से राज्यों की एक तालिका के बारे में, यदि आपके पास मानों के साथ, इस तालिका में एक सरोगेट कुंजी है, तो कहें, 1 से 50 तक, लेकिन आपने राज्य पोस्टल कोड पर एक और विशिष्ट सूचकांक या कुंजी नहीं रखी, (और, मेरी राय में, राज्य के नाम पर भी), तो किसी को अलग-अलग सरोगेट कुंजी मानों के साथ दो पंक्तियों में प्रवेश करने से रोकने के लिए क्या है लेकिन समान डाक कोड और / या राज्य के नाम के साथ? अगर 'NJ', 'न्यू जर्सी' के साथ दो पंक्तियाँ होतीं तो क्लाइंट ऐप इसे कैसे संभालता? प्राकृतिक कुंजी डेटा स्थिरता सुनिश्चित करते हैं!
चार्ल्स ब्रेटाना

81

यह प्रदर्शन के बारे में नहीं है। यह उस बारे में है जो एक अच्छी प्राथमिक कुंजी बनाता है। समय के साथ अनोखा और अपरिवर्तनशील। आप सोच सकते हैं कि एक देश जैसे कोड समय के साथ कभी नहीं बदलता है और प्राथमिक कुंजी के लिए एक अच्छा उम्मीदवार होगा। लेकिन कड़वा अनुभव यह है कि शायद ही कभी ऐसा हो।

INT AUTO_INCREMENT "समय के साथ अद्वितीय और अपरिवर्तनीय" स्थिति को पूरा करता है। इसलिए वरीयता।


25
सच। मेरे सबसे बड़े डेटाबेस में से एक में यूगोस्लाविया और सोवियत संघ की प्रविष्टियाँ हैं। मुझे खुशी है कि वे प्राथमिक कुंजी नहीं हैं।
पॉल टॉम्बलिन

8
@ पहले, फिर ANSI SQL सिंटैक्स ऑन UPDATE CASCADE का समर्थन क्यों करता है?
बिल करविन

5
अपरिवर्तनीयता कुंजी की आवश्यकता नहीं है। किसी भी मामले में, सरोगेट कुंजी कभी-कभी भी बदल जाती है। जरूरत पड़ने पर चाबी बदलने में कुछ भी गलत नहीं है।
nvogel

9
पॉल, इसलिए आपने अपने डेटाबेस में सोवियत संघ को रूस में बदल दिया? और बहाना है कि एसयू कभी मौजूद नहीं है? और एसयू के सभी संदर्भ अब रूस की ओर इशारा करते हैं?
Dainius

6
@ लागा मैं एसयू में पैदा हुआ था इसलिए मुझे पता है कि यह क्या है।
दिनियस

52

मैं इस ऑनलाइन के लिए बेंचमार्क की कमी से थोड़ा परेशान था, इसलिए मैंने खुद एक परीक्षण चलाया।

ध्यान दें कि मैं इसे नियमित रूप से नहीं करता हूं, इसलिए कृपया मेरे सेटअप और चरणों की जांच करें, जो किसी भी कारक के लिए अनपेक्षित रूप से परिणामों को प्रभावित कर सकते हैं, और टिप्पणियों में अपनी चिंताओं को पोस्ट कर सकते हैं।

सेटअप इस प्रकार था:

  • Intel® Core ™ i7-7500U CPU @ 2.70GHz × 4
  • 15.6 GiB RAM, जिसमें से मैंने परीक्षण के दौरान लगभग 8 GB सुनिश्चित किया था।
  • 148.6 जीबी एसएसडी ड्राइव, भरपूर खाली जगह के साथ।
  • उबंटू 16.04 64-बिट
  • लिनक्स के लिए MySQL Ver 14.14 डिस्ट्रिब्यूट 5.7.20, (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;

फिर, मैंने PHP स्क्रिप्ट के साथ प्रत्येक तालिका में 10 मिलियन पंक्तियों को भरा जिसका सार इस प्रकार है:

$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)])बस के साथ बदल दिया गया था 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;(w / कुछ कॉलम नहीं दिखाए गए) का आउटपुट है :

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 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 | 
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

मेरा निष्कर्ष यह है कि इस विशेष उपयोग के मामले में कोई प्रदर्शन अंतर नहीं है।


मुझे पता है कि अब देर हो चुकी है, लेकिन अगर आप उस स्थिति के लिए कम आदर्श स्ट्रिंग उठाते हैं तो मैं परिणाम देखने के लिए उत्सुक हूं। "कैलीफो [rnia]" आदर्श था क्योंकि यह पहले चरित्र की तुलना करने के बाद बेमेल को त्याग सकता था, केवल वास्तविक मैचों पर और अधिक जाँच करने की आवश्यकता थी; "न्यूहैम" जैसी किसी चीज़ ने अधिक दिलचस्प परिणाम दिए होंगे क्योंकि सभी बेमेल को खत्म करने के लिए अधिक चरित्र की तुलना करना नया होगा। इसके अलावा, आपके पूर्णांक को इस तरह सीमित करना भी उनके खिलाफ बाधाओं को कम करता है, मैंने उन्हें बहुत कम से कम 26 मान दिए होंगे।
यूएर्डो

15
कमाल है कि 10 साल पुराने सवाल में, यह केवल दो उत्तरों में से एक है जो सिर्फ अटकलबाजी नहीं है और वास्तविक बेंचमार्क पर निर्भर करता है।
एड्रियन बेकर

1
लेकिन आपकी तालिकाओं में एक प्राथमिक कुंजी नहीं होती है, जो वास्तव में InnoDB एक सॉर्ट की गई डेटा संरचना है। पूर्णांक छँटाई और स्ट्रिंग छँटाई के बीच की गति अलग होनी चाहिए।
मेल्कोर

1
@ मेल्कोर फेयर पॉइंट जो मैं INDEXइसके बजाय उपयोग करता हूं PRIMARY KEY। मुझे अपना तर्क याद नहीं है - मैं शायद यह मान रहा हूं कि PRIMARY KEYसिर्फ INDEXविशिष्टता के साथ। हालाँकि, इस खंड पर पढ़ते हुए कि कैसे InnoDB में federico-razzoli.com/primary-key-in-innodb में चीजें संग्रहीत की जाती हैं , मुझे लगता है कि मेरे परिणाम अभी भी प्राथमिक कुंजी पर लागू होते हैं, और मूल्य लुकअप प्रदर्शन अंतर पर प्रश्न का उत्तर देते हैं। इसके अलावा, आपकी टिप्पणी एल्गोरिदम को छांटने के प्रदर्शन को देखते हुए बताती है, जो मेरे द्वारा उपयोग किए गए केस केस पर लागू नहीं होती है, जो एक सेट में मूल्यों को देख रहा है
Jan 10ankowski

1
लुकअप ऑपरेशन के लिए प्राथमिक कुंजी फ़ील्ड (बाइनरी खोज की तरह) पर तुलना की आवश्यकता होती है, जहाँ int varchar की तुलना में थोड़ा तेज़ होना चाहिए। लेकिन जैसा कि आपके प्रयोगों ने सुझाव दिया, यह स्पष्ट नहीं है (या हो सकता है क्योंकि आपके पास प्राथमिक कुंजी नहीं थी इसलिए प्रश्न सभी धीमे थे)। मुझे लगता है कि यह डालने और देखने पर समान बात है।
मेल्कोर

38

लंबाई पर निर्भर करता है .. यदि varchar 20 अक्षर का होगा, और int 4 है, तो यदि आप int का उपयोग करते हैं, तो आपके सूचकांक में डिस्क पर सूचकांक स्थान के प्रति पृष्ठ पर कई बार नोड्स होंगे ... इसका मतलब है कि ट्रैवर्सिंग सूचकांक को कई भौतिक और / या तार्किक रीड्स के रूप में एक पांचवें की आवश्यकता होगी।

इसलिए, यदि प्रदर्शन एक मुद्दा है, तो अवसर दिया जाता है, हमेशा अपनी तालिकाओं के लिए एक अभिन्न गैर-सार्थक कुंजी (जिसे सरोगेट कहा जाता है) का उपयोग करें, और विदेशी कुंजी के लिए जो इन तालिकाओं में पंक्तियों का संदर्भ देते हैं ...

एक ही समय में , गारंटी डेटा स्थिरता के लिए, हर तालिका जहां यह मायने रखती है चाहिए भी एक सार्थक गैर-संख्यात्मक वैकल्पिक कुंजी, (या अद्वितीय सूचकांक) सुनिश्चित करना है कि डुप्लीकेट पंक्तियों सम्मिलित नहीं किया जा सकता है (नकल सार्थक तालिका विशेषताओं के आधार पर) है।

उस विशिष्ट उपयोग के लिए जिसके बारे में आप बात कर रहे हैं (जैसे राज्य लुकअप) यह वास्तव में कोई फर्क नहीं पड़ता क्योंकि तालिका का आकार बहुत छोटा है .. सामान्य तौर पर कुछ हजार पंक्तियों से कम की तालिकाओं पर सूचकांकों से प्रदर्शन पर कोई प्रभाव नहीं पड़ता है। ..


ज़रूर? सबसे अधिक डेटा प्रारूप पंक्ति आधारित करें? चाबियों को अलग करने के लिए अन्य डेटा है। Isnt कारक 5 यूटोपिक?
मैनुएल श्नाइड 3r

1
@ manuelSchneid3r, क्या? utopic? नहीं, कारक 5 "यूटोपिक" नहीं है। यह सिर्फ 20 से विभाजित है 4. और "डेटा प्रारूप पंक्ति आधारित" का क्या मतलब है? संकेत "पंक्ति आधारित" नहीं हैं, वे संतुलित पेड़ संरचनाएं हैं।
चार्ल्स ब्रेटाना

36

बिलकुल नहीं।

मैंने कई ... कई ... INT, VARCHAR और CHAR के बीच प्रदर्शन जांच की है।

10 मिलियन रिकॉर्ड टेबल जिसमें एक PRIMARY KEY (अनोखी और क्लस्टर की गई) की समान गति और प्रदर्शन (और सबट्री कॉस्ट) थी, कोई फर्क नहीं पड़ता कि मैं तीन में से किसका उपयोग करता था।

कहा जा रहा है ... जो भी आपके आवेदन के लिए सबसे अच्छा है उसका उपयोग करें। प्रदर्शन के बारे में चिंता मत करो।


42
बिना यह जाने कि वर्चर्स कितने समय के लिए थे ... अगर वे 100 बाइट्स के थे, तो गारंटी थी कि आपको 4 बाइट इंट के समान प्रदर्शन नहीं मिल रहा है
चार्ल्स ब्रेटाना

6
यह जानने में भी मदद मिलेगी कि आप किस डेटाबेस का उपयोग कर रहे हैं और डेटाबेस के किस संस्करण का। प्रदर्शन ट्यूनिंग लगभग हमेशा काम किया है और संस्करण से संस्करण में सुधार हुआ है।
डेव ब्लैक

VARCHAR निश्चित रूप से सूचकांक आकार के लिए मायने रखता है। और सूचकांक यह निर्धारित करता है कि स्मृति में कितना फिट हो सकता है। और स्मृति में अनुक्रमणिकाएं उन लोगों की तुलना में कहीं अधिक तेज, बहुत तेज हैं। यह हो सकता है कि आपकी 10 मीटर पंक्तियों के लिए, आपके पास उस सूचकांक के लिए 250MB मेमोरी उपलब्ध हो, और ठीक था। लेकिन अगर आपके पास 100 मीटर पंक्तियां हैं, तो आप उस मेमोरी में कम ठीक होंगे।
पॉल ड्रेपर

9

छोटे कोड के लिए, शायद कोई अंतर नहीं है। यह विशेष रूप से सच है क्योंकि ये कोड रखने वाली तालिका बहुत छोटी होने की संभावना है (अधिक से अधिक एक दो हज़ार पंक्तियाँ) और अक्सर परिवर्तित नहीं होती हैं (जब पिछली बार हमने एक नया यूएस स्टेट जोड़ा था)।

कुंजी के बीच व्यापक भिन्नता वाली बड़ी तालिकाओं के लिए, यह खतरनाक हो सकता है। उदाहरण के लिए, उपयोगकर्ता तालिका से ई-मेल पते / उपयोगकर्ता नाम का उपयोग करने के बारे में सोचें। क्या होता है जब आपके पास कुछ मिलियन उपयोगकर्ता होते हैं और उनमें से कुछ उपयोगकर्ताओं के लंबे नाम या ई-मेल पते होते हैं। अब किसी भी समय आपको उस कुंजी का उपयोग करके इस तालिका में शामिल होने की आवश्यकता है यह बहुत अधिक महंगा हो जाता है।


2
क्या आपको पता है कि यह महंगा होगा? या आप सिर्फ अनुमान लगा रहे हैं?
स्टीव मैक्लियॉड

बेशक यह rdbms कार्यान्वयन पर निर्भर करता है, लेकिन जो मैं समझता हूं कि अधिकांश सर्वर इंडेक्सिंग उद्देश्यों के लिए वास्तविक मूल्य के हैश को रखेंगे। फिर भी, और भले ही यह अपेक्षाकृत कम हैश हो (कहते हैं, 10 बाइट), 2 4 बाइट हैश की तुलना 2 4 बाइट इनट्स से करना अभी भी अधिक काम है।
जोएल कोएहॉर्न

कभी जुड़ने के लिए एक लंबी (चौड़ी) कुंजी का उपयोग करें ... लेकिन अगर यह तालिका में पंक्तियों के लिए अद्वितीय है का सबसे अच्छा प्रतिनिधित्व है, तो बेहतर है एक अद्वितीय कुंजी (या सूचकांक - जो एक ही बात है) उसी पर हो तालिका उन प्राकृतिक मूल्यों का उपयोग करते हुए। कुंजियाँ जुड़ने के लिए नहीं होती हैं, आप अपनी दिल की इच्छाओं पर कुछ भी कर सकते हैं। डेटा संगति सुनिश्चित करने के लिए कुंजी हैं।
चार्ल्स ब्रेटाना

6

प्राथमिक कुंजी के लिए, जो भी भौतिक रूप से पंक्ति को अद्वितीय बनाता है उसे प्राथमिक कुंजी के रूप में निर्धारित किया जाना चाहिए।

एक विदेशी कुंजी के रूप में संदर्भ के लिए, एक सरोगेट के रूप में एक ऑटो इंक्रीमेंटिंग पूर्णांक का उपयोग करना दो मुख्य कारणों के लिए एक अच्छा विचार है।
- पहले, आमतौर पर ज्वाइन में कम ओवरहेड होता है।
- दूसरा, यदि आपको उस तालिका को अपडेट करने की आवश्यकता है जिसमें अद्वितीय 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 माध्यमिक कुंजी को एक अतिरिक्त खोज की आवश्यकता है; जोड़ी को पीके में स्थानांतरित करके, एक दिशा के लिए टाला जाता है।
  • द्वितीयक सूचकांक "कवरिंग" है, इसलिए इसे अतिरिक्त लुकअप की आवश्यकता नहीं है।
  • छुटकारा पाने idऔर एक सूचकांक के कारण यह तालिका छोटी है ।

एक और मामला ( देश ):

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

सभी भी अक्सर नौसिखिया INT'प्राकृतिक' 2-बाइट, लगभग अपरिवर्तित 2-बाइट स्ट्रिंग का उपयोग करने के बजाय 4-बाइट में देश_कोड को सामान्य करते हैं । तेजी से, छोटे, कम JOINs, अधिक पठनीय।


2

HauteLook में, हमने प्राकृतिक कुंजियों का उपयोग करने के लिए अपनी कई तालिकाओं को बदल दिया। हमने प्रदर्शन में वास्तविक दुनिया में वृद्धि का अनुभव किया। जैसा कि आप उल्लेख करते हैं, हमारे कई प्रश्न अब कम जुड़ाव का उपयोग करते हैं, जो प्रश्नों को और अधिक बेहतर बनाता है। हम एक समग्र प्राथमिक कुंजी का उपयोग भी करेंगे यदि यह समझ में आता है। कहा जा रहा है कि, कुछ टेबल के साथ काम करना आसान होता है अगर उनके पास सरोगेट कुंजी है।

इसके अलावा, यदि आप लोगों को अपने डेटाबेस में इंटरफेस लिखने दे रहे हैं, तो सरोगेट कुंजी मददगार हो सकती है। तीसरा पक्ष इस तथ्य पर भरोसा कर सकता है कि सरोगेट कुंजी केवल बहुत ही दुर्लभ परिस्थितियों में बदल जाएगी।


2

मैंने उसी दुविधा का सामना किया। मैंने 3 तथ्य तालिकाओं, सड़क दुर्घटनाओं, दुर्घटनाओं में वाहनों और दुर्घटनाओं में हताहतों के साथ एक DW (नक्षत्र स्कीमा) बनाया। डेटा में 1979 से 2012 तक यूके में दर्ज सभी दुर्घटनाएं और 60 आयाम टेबल शामिल हैं। सभी एक साथ, लगभग 20 मिलियन रिकॉर्ड।

फैक्ट टेबल रिलेशनशिप:

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

RDMS: MySQL 5.6

मूल रूप से एक्सीडेंट इंडेक्स 15 अंकों के साथ एक varchar (संख्या और अक्षर) है। मैंने कोशिश की कि सरोगेट चाबियां न हों, एक बार दुर्घटना सूचकांक कभी नहीं बदलेगा। एक i7 (8 कोर) कंप्यूटर में, DW आयामों के आधार पर लोड के 12 मिलियन रिकॉर्ड के बाद क्वेरी के लिए बहुत धीमा हो गया। बहुत सारे री-वर्क के बाद और बिगिंट सरोगेट कीज़ जोड़ने के बाद मुझे औसत 20% स्पीड परफॉर्मेंस बूस्ट मिला। अभी तक कम प्रदर्शन हासिल करने के लिए, लेकिन वैध प्रयास करें। Im MySQL ट्यूनिंग और क्लस्टरिंग में काम कर रहा है।


1
ऐसा लगता है जैसे आपको विभाजन में देखने की आवश्यकता है।
जेकोफैंड

2

प्रश्न MySQL के बारे में है इसलिए मेरा कहना है कि एक महत्वपूर्ण अंतर है। अगर यह ओरेकल के बारे में था (जो संख्याओं को स्ट्रिंग के रूप में संग्रहीत करता है - हाँ, मैं पहले इस पर विश्वास नहीं कर सकता था) तो बहुत अंतर नहीं था।

तालिका में संग्रहण समस्या नहीं है, लेकिन अद्यतन करना और अनुक्रमणिका का संदर्भ देना है। इसकी प्राथमिक कुंजी के आधार पर रिकॉर्ड को देखने वाली क्वेरी अक्सर होती हैं - आप चाहते हैं कि वे जितनी जल्दी हो सके, क्योंकि वे ऐसा अक्सर होते हैं।

बात सिलिकॉन में स्वाभाविक रूप से 4 बाइट और 8 बाइट पूर्णांकों के साथ सीपीयू सौदों की है । यह दो पूर्णांकों की तुलना करने के लिए वास्तव में तेज़ है - यह एक या दो घड़ी चक्रों में होता है।

अब एक तार को देखें - यह बहुत सारे पात्रों (इन दिनों एक से अधिक बाइट प्रति वर्ण) से बना है। पूर्वता के लिए दो तारों की तुलना एक या दो चक्रों में नहीं की जा सकती है। इसके बजाय स्ट्रिंग्स के पात्रों को एक अंतर मिलने तक पुनरावृत्त होना चाहिए। मुझे यकीन है कि कुछ डेटाबेस में इसे तेजी से बनाने के लिए ट्रिक्स हैं, लेकिन यहां यह अप्रासंगिक है क्योंकि सीपीयू द्वारा सिलिकॉन में स्वाभाविक रूप से एक तेज तुलना की जाती है और तेजी से बिजली गिरती है।

मेरा सामान्य नियम - हर प्राथमिक कुंजी एक विशेष रूप से OO ऐप्स में ORM (Hibernate, Datanucleus, जो कुछ भी हो) का उपयोग करते हुए एक autoincrementing INT होना चाहिए जहां वस्तुओं के बीच बहुत सारे संबंध हैं - वे आमतौर पर एक साधारण KK और के लिए क्षमता के रूप में लागू किया जाएगा उन उपवासों को हल करने के लिए DB आपके ऐप की जवाबदेही के लिए महत्वपूर्ण है।


0

प्रदर्शन निहितार्थ के बारे में निश्चित नहीं है, लेकिन यह संभव समझौता लगता है, कम से कम विकास के दौरान, ऑटो-इन्क्रिमेटेड, पूर्णांक "सरोगेट" कुंजी, साथ ही साथ आपके इच्छित, अद्वितीय, "प्राकृतिक" कुंजी दोनों को शामिल करना होगा। इससे आपको प्रदर्शन का मूल्यांकन करने का अवसर मिलेगा, साथ ही प्राकृतिक कुंजियों की परिवर्तनशीलता सहित अन्य संभावित मुद्दों पर भी विचार होगा।


0

हमेशा की तरह, कोई कंबल उत्तर नहीं हैं। 'निर्भर करता है!' और मैं मुखर नहीं हो रहा हूँ। मूल प्रश्न की मेरी समझ छोटे तालिकाओं की कुंजियों के लिए थी - जैसे कि देश (पूर्णांक आईडी या चार / कोडर कोड) संभावित विदेशी तालिका जैसे पते / संपर्क तालिका की एक विदेशी कुंजी है।

जब आप DB से डेटा वापस चाहते हैं तो यहां दो परिदृश्य हैं। पहले एक सूची / खोज प्रकार की क्वेरी है जहां आप राज्य और देश कोड या नामों के साथ सभी संपर्कों को सूचीबद्ध करना चाहते हैं (आईडी मदद नहीं करेगा और इसलिए लुकअप की आवश्यकता होगी)। दूसरा प्राथमिक कुंजी पर एक दृश्य परिदृश्य है जो एकल संपर्क रिकॉर्ड दिखाता है जहां राज्य, देश का नाम दिखाया जाना चाहिए।

बाद के लिए, यह संभवत: कोई फर्क नहीं पड़ता कि एफके किस पर आधारित है क्योंकि हम एक एकल रिकॉर्ड या कुछ रिकॉर्ड के लिए एक साथ टेबल ला रहे हैं और प्रमुख रीड्स पर। पूर्व (खोज या सूची) परिदृश्य हमारी पसंद से प्रभावित हो सकता है। चूंकि यह देश को दिखाने के लिए आवश्यक है (कम से कम एक पहचानने योग्य कोड और शायद यहां तक ​​कि खोज में भी एक देश कोड शामिल है), सरोगेट कुंजी के माध्यम से एक और तालिका में शामिल होने के लिए संभावित रूप से नहीं हो सकता है (मैं सिर्फ यहां सतर्क रह रहा हूं क्योंकि मैंने वास्तव में परीक्षण नहीं किया है यह, लेकिन अत्यधिक संभावना है) प्रदर्शन में सुधार; इस तथ्य के बावजूद कि यह निश्चित रूप से खोज में मदद करता है।

जैसा कि कोड आकार में छोटे होते हैं - आमतौर पर देश और राज्य के लिए 3 से अधिक वर्ण नहीं, इस परिदृश्य में विदेशी कुंजी के रूप में प्राकृतिक कुंजी का उपयोग करना ठीक हो सकता है।

अन्य परिदृश्‍य जहां कुंजियां लंबे समय तक विभिन्‍न मानों और शायद बड़ी तालिकाओं पर निर्भर होती हैं; सरोगेट कुंजी का शायद फायदा है।


0

मुझे कहने की अनुमति दें हाँ निश्चित रूप से एक अंतर है, प्रदर्शन के दायरे को ध्यान में रखते हुए (बॉक्स परिभाषा से बाहर):

1- सरोगेट इंट का उपयोग करना एप्लिकेशन में तेज है क्योंकि आपको अपने कोड में या अपने प्रश्न में ToUpper (), ToLower (), ToUpperInvarient (), या ToLowerInvarient () का उपयोग करने की आवश्यकता नहीं है और इन 4 फ़ंक्शन के अलग-अलग प्रदर्शन बेंचमार्क हैं। इस पर Microsoft प्रदर्शन नियम देखें। (आवेदन का प्रदर्शन)

2- सरोगेट इंट के उपयोग से समय के साथ चाबी नहीं बदलने की गारंटी मिलती है। यहां तक ​​कि देश कोड भी बदल सकते हैं, विकिपीडिया देखें कि समय के साथ आईएसओ कोड कैसे बदल गए। उपशीर्षक के लिए प्राथमिक कुंजी को बदलने में बहुत समय लगेगा। (डेटा रखरखाव का प्रदर्शन)

3- ऐसा लगता है कि ORM समाधान के साथ समस्याएँ हैं, जैसे कि NHibernate जब PK / FK int नहीं है। (डेवलपर प्रदर्शन)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.