निश्चित आकार के क्षेत्र पर CHAR बनाम VARCHAR का उपयोग करने का प्रदर्शन प्रभाव क्या है?


58

मेरे पास एक अनुक्रमित स्तंभ है जो एमडी 5 हैश को संग्रहीत करता है। इस प्रकार, कॉलम हमेशा 32-वर्ण मान संग्रहीत करेगा। जो भी कारण के लिए, यह एक चर के बजाय एक चरचर के रूप में बनाया गया था। क्या डेटाबेस को चार्ट में बदलने के लिए माइग्रेट करने की परेशानी के लायक है? यह InnoDB के साथ MySQL 5.0 में है।


6
चेतावनी यह सवाल और इसके उत्तर InnoDB और utf8 के पहले लिखे गए थे जो चूक थे।
रिक जेम्स

जवाबों:


56

इसी तरह का सवाल पहले भी पूछा गया था

MySQL VARCHAR आकार के प्रदर्शन निहितार्थ

यहाँ मेरे जवाब का अंश है

आपको CHAR बनाम VARCHAR का उपयोग करने के tradeoffs का एहसास होना चाहिए

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

VARCHAR क्षेत्रों के साथ, आपको एक पूरी तरह से अलग कहानी मिलती है। उदाहरण के लिए VARCHAR (15) वास्तव में गतिशील रूप से 16 बाइट्स तक, डेटा के लिए 15 तक और, कम से कम, 1 अतिरिक्त बाइट डेटा की लंबाई को संग्रहीत करने के लिए आवंटित करता है। यदि आपके पास स्टोर करने के लिए स्ट्रिंग 'हैलो' है जो 6 बाइट्स लेगा, तो 5. स्ट्रिंग हेरफेर को हमेशा सभी मामलों में लंबाई की जाँच के कुछ प्रकार का प्रदर्शन करना होगा।

जब आप दो काम करते हैं तो ट्रेडऑफ अधिक स्पष्ट होता है: 1. लाखों या अरबों पंक्तियों का संग्रह करना 2. उन स्तंभों को अनुक्रमणित करना जो या तो CHAR या VARCHAR हैं

TRADEOFF # 1 स्पष्ट रूप से, VARCHAR लाभ उठाता है क्योंकि चर-लंबाई डेटा छोटी पंक्तियों का उत्पादन करेगा और इस प्रकार, छोटी भौतिक फाइलें।

TRADEOFF # 2 चूंकि CHAR फ़ील्ड को निश्चित फ़ील्ड चौड़ाई के कारण कम स्ट्रिंग हेरफेर की आवश्यकता होती है, CHAR फ़ील्ड के विरुद्ध अनुक्रमणिका लुकअप औसत रूप से VARCHAR फ़ील्ड की तुलना में 20% अधिक तेज़ होता है। यह मेरी ओर से कोई अनुमान नहीं है। MySQL डेटाबेस डिजाइन और ट्यूनिंग पुस्तक ने इसे साबित करने के लिए एक MyISAM टेबल पर कुछ अद्भुत प्रदर्शन किया। पुस्तक में उदाहरण कुछ इस तरह था:

ALTER TABLE tblname ROW_FORMAT=FIXED;

यह निर्देश सभी VARCHAR को CHAR के रूप में व्यवहार करने के लिए मजबूर करता है। मैंने 2007 में अपनी पिछली नौकरी में ऐसा किया था और बिना किसी और बदलाव के 300GB टेबल ले लिया और 20% तक इंडेक्स लुकअप किया। यह प्रकाशित के रूप में काम किया। हालाँकि, इसने आकार में लगभग दोगुनी एक तालिका का निर्माण किया, लेकिन यह बस # 1 पर वापस जाती है।

आप यह देखने के लिए संग्रहीत डेटा का विश्लेषण कर सकते हैं कि MySQL कॉलम परिभाषा के लिए क्या सिफारिश करता है। बस किसी भी तालिका के खिलाफ निम्नलिखित चलाएँ:

SELECT * FROM tblname PROCEDURE ANALYSE();

यह संपूर्ण तालिका को आगे बढ़ाएगा और इसमें मौजूद डेटा, न्यूनतम फ़ील्ड मान, अधिकतम फ़ील्ड मान और इसके आगे के आधार पर प्रत्येक स्तंभ के लिए स्तंभ परिभाषाएँ सुझाएगा। कभी-कभी, आपको CHAR बनाम VARCHAR की योजना के साथ सामान्य ज्ञान का उपयोग करना होगा। यहाँ एक अच्छा उदाहरण है:

यदि आप IP पते स्टोर कर रहे हैं, तो ऐसे कॉलम के लिए मास्क अधिकतम 15 वर्णों (xxx.xxx.xxx.xxx) पर है। मैं CHAR(15)दिल की धड़कन में सही कूद सकता हूं क्योंकि आईपी पते की लंबाई एक अतिरिक्त बाइट द्वारा नियंत्रित स्ट्रिंग हेरफेर की सभी और बहुत कुछ और अलग जटिलता नहीं होगी। आप अभी भी PROCEDURE ANALYSE()इस तरह के एक स्तंभ के खिलाफ कर सकते हैं । यह VARCHAR की सिफारिश भी कर सकता है। इस उदाहरण में VARCHAR पर मेरा पैसा अभी भी CHAR पर होगा।

CHAR बनाम VARCHAR मुद्दों को उचित योजना के माध्यम से ही हल किया जा सकता है। महान शक्ति के साथ बड़ी जिम्मेदारी आती है (क्लिच लेकिन सच)।

अपडेट करें

जब एमडी 5 की बात आती है, strlenतो संपूर्ण पंक्ति प्रारूप को स्विच करते समय आंतरिक रूप से गणना समाप्त की जानी चाहिए। क्षेत्र की परिभाषा को बदलने की कोई आवश्यकता नहीं होगी।

यदि MD5 कुंजी केवल VARCHAR मौजूद है, तो मैं इसके लिए जाऊंगा और तालिका पंक्ति प्रारूप को निर्धारित करूंगा । यदि अन्य VARCHAR क्षेत्रों के एक हस्ताक्षरित संख्या मौजूद है, तो वे भी लाभान्वित होंगे। बदले में, तालिका लगभग दो बार अपने आकार का विस्तार करेगी। लेकिन अतिरिक्त ट्यूनिंग के बिना प्रश्नों में लगभग 20% अधिक तेजी होनी चाहिए।


1
मुझे लगता है कि मैं एक चार (4) या एक आईपी पते के लिए अहस्ताक्षरित पूर्णांक की तरह कुछ का उपयोग करूँगा
जैक डगलस

@JackPDouglas आप उस एक बिंदु पर सही हैं।
रोलैंडमाइसीडीडीबीए

अनुक्रमणिका को किसी निश्चित लंबाई के साथ वैसे भी संग्रहीत नहीं किया जाता है? मुझे नहीं पता है कि स्टोरेज फॉर्मेट को निश्चित लंबाई में सुधार करने वाले इंडेक्स लुक्स को कैसे बदलना है। क्या आपका मतलब है कि यह टेबल स्कैन में सुधार हुआ है?
मार्कस एडम्स

1
@JackDouglas, क्यों नहीं bitऔर binary?
पचेरियर

@ स्पेसर जो बेहतर होगा, मैं मानता हूं :)
जैक डगलस

19

ऐसा लगता है कि आप 1 बाइट प्रति मान या लगभग 3% बचाकर a में परिवर्तित करेंगे char। शायद इसके लायक नहीं है यदि आप वैसे भी एमडी 5 को हेक्स में स्टोर कर रहे हैं - तो आप binaryइसके बजाय 50% बचा सकते हैं ।

उनका कहना है कि के लिए Ovais के लिए धन्यवाद (टिप्पणी देखें) char(32)कर सकते हैं एक बहुत कुछ 32 से अधिक बाइट का उपयोग करता है, तो आप एक multibyte वर्ण सेट का उपयोग कर रहे हैं।

रिक जेम्स के लिए धन्यवाद कि आप unhexबाइनरी स्ट्रिंग को बाइनरी में बदलने के लिए फ़ंक्शन का उपयोग करें।

create table foo(bar varbinary(100));
insert into foo(bar) values(md5('a')); 
insert into foo(bar) values(unhex(md5('a'))); 
select length(bar) from foo;
| लंबाई (बार) |
| ----------: |
| 32 |
| 16 |

db <> फिडल यहां


बाइनरी को बदलने पर अच्छा कॉल।
RThomas

मैं इसे बाइनरी में परिवर्तित करने की योजना बना रहा हूं। हालांकि अब मुझे लगता है कि इसके बारे में, आकार कोई अलग नहीं होना चाहिए क्योंकि मैं बाइट या चार का उपयोग कर रहा हूं क्योंकि हमारे एन्कोडिंग utf-8 है। या मैं गलत हूँ?
जेसन बेकर

@ जेसन - एन्कोडिंग पर लागू नहीं होता है binary- या मुझे गलत समझा गया है?
जैक डगलस

3
utf-8 के वर्ण सेट के साथ एक चार्ट (32) कॉलम के लिए, भंडारण के लिए हर मूल्य को 32x3 बाइट्स की आवश्यकता होगी। आपको utf-8 होने के लिए MD5 हैश मान सेट करने की आवश्यकता क्यों होगी। बाइनरी (32) में बदलने के लिए प्रति मूल्य 32 बाइट की आवश्यकता होगी।
ovais.tariq

1
BINARYजब तक आप उपयोग नहीं करते तब तक बहुत कम परिवर्तन करना UNHEX()। यही है, आप भंडारण में महत्वपूर्ण स्थान बचाने के लिए UNHEX(MD5(x))16-बाइट में स्टोर कर सकते हैं । BINARY(16)MD5(x)CHAR(32) CHARACTER SET ascii
रिक जेम्स

15

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

http://dev.mysql.com/doc/refman/5.0/en/char.html

पहले दिए गए डॉक्यूमेंट पर पहली टिप्पणी भी ध्यान दें, जो ऊपर दी गई है ... "यदि पूरा रिकॉर्ड निश्चित आकार का है, तो CHAR केवल आपकी पहुंच को गति देगा। यदि आप किसी भी वैरिएबल साइज ऑब्जेक्ट का उपयोग करते हैं, तो आप उन सभी को भी बना सकते हैं।" परिवर्तनशील आकार। आप किसी तालिका में CHAR का उपयोग करके कोई गति प्राप्त नहीं करते हैं जिसमें VARCHAR भी शामिल है "


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