प्राथमिक कुंजी (InnoDB स्टोरेज इंजन) के रूप में मैसूर बनाम वर्चर?


13

मैं एक वेब एप्लिकेशन (परियोजना प्रबंधन प्रणाली) का निर्माण कर रहा हूं और जब यह प्रदर्शन की बात आती है तो मैं इस बारे में सोच रहा हूं।

मेरे पास एक अंक तालिका है इसके अंदर विभिन्न विदेशी तालिकाओं को जोड़ने वाली 12 विदेशी कुंजियाँ हैं। उन में से 8, मुझे किसी वेब एप्लिकेशन में कोई भी अर्थ निकालने के लिए रिकॉर्ड के लिए अन्य तालिकाओं से शीर्षक क्षेत्र प्राप्त करने के लिए शामिल होने की आवश्यकता होगी, लेकिन फिर इसका मतलब है कि 8 जोड़ जो वास्तव में अत्यधिक अत्यधिक लगते हैं क्योंकि मैं केवल खींच रहा हूं उन सभी में से प्रत्येक के लिए 1 क्षेत्र।

अब मुझे एक ऑटो इन्क्रीमेंटिंग प्राइमरी की का उपयोग करने के लिए भी कहा गया है (जब तक कि इस बात की चिंता नहीं है कि मुझे स्थायी कारणों से GUID का उपयोग किस मामले में करना चाहिए) लेकिन वारचर (अधिकतम लंबाई 32) के प्रदर्शन का उपयोग करना कितना बुरा है? मेरा मतलब है कि इनमें से अधिकांश तालिका में संभवतः कई रिकॉर्ड नहीं हैं (उनमें से अधिकांश 20 से कम होनी चाहिए)। अगर मैं शीर्षक को प्राथमिक कुंजी के रूप में उपयोग करता हूं, तो मुझे 95% समय के लिए जॉइन नहीं करना पड़ेगा इसलिए 95% एसक्यूएल के लिए, मैं किसी भी प्रदर्शन को हिट करूंगा (मुझे लगता है)। केवल नकारात्मक पक्ष यह है कि मैं सोच सकता हूं कि मेरे पास उच्च डिस्क स्थान का उपयोग होगा (लेकिन एक दिन नीचे यह वास्तव में एक बड़ी बात है)।

कारण यह है कि मैं इस सामग्री के बहुत सारे के लिए लुकअप तालिकाओं का उपयोग enums के बजाय कर रहा हूं क्योंकि मुझे इन सभी मूल्यों को एप्लिकेशन के माध्यम से अंतिम उपयोगकर्ता द्वारा कॉन्फ़िगर करने योग्य होना चाहिए।

कई रिकॉर्ड्स को छोड़कर किसी तालिका के लिए प्राथमिक कुंजी के रूप में एक varchar का उपयोग करने के डाउनसाइड क्या हैं?

अद्यतन - कुछ टेस्ट

इसलिए मैंने इस सामान पर कुछ बुनियादी परीक्षण करने का फैसला किया। मेरे पास 100000 रिकॉर्ड हैं और ये आधार प्रश्न हैं:

बेस वर्कर एफके क्वेरी

SELECT i.id, i.key, i.title, i.reporterUserUsername, i.assignedUserUsername, i.projectTitle, 
i.ProjectComponentTitle, i.affectedProjectVersionTitle, i.originalFixedProjectVersionTitle, 
i.fixedProjectVersionTitle, i.durationEstimate, i.storyPoints, i.dueDate, 
i.issueSecurityLevelId, i.creatorUserUsername, i.createdTimestamp, 
i.updatedTimestamp, i.issueTypeId, i.issueStatusId
FROM ProjectManagement.Issues i

आधार INT FK क्वेरी

SELECT i.id, i.key, i.title, ru.username as reporterUserUsername, 
au.username as assignedUserUsername, p.title as projectTitle, 
pc.title as ProjectComponentTitle, pva.title as affectedProjectVersionTitle, 
pvo.title as originalFixedProjectVersionTitle, pvf.title as fixedProjectVersionTitle, 
i.durationEstimate, i.storyPoints, i.dueDate, isl.title as issueSecurityLevelId, 
cu.username as creatorUserUsername, i.createdTimestamp, i.updatedTimestamp, 
it.title as issueTypeId, is.title as issueStatusId
FROM ProjectManagement2.Issues i
INNER JOIN ProjectManagement2.IssueTypes `it` ON it.id = i.issueTypeId
INNER JOIN ProjectManagement2.IssueStatuses `is` ON is.id = i.issueStatusId
INNER JOIN ProjectManagement2.Users `ru` ON ru.id = i.reporterUserId
INNER JOIN ProjectManagement2.Users `au` ON au.id = i.assignedUserId
INNER JOIN ProjectManagement2.Users `cu` ON cu.id = i.creatorUserId
INNER JOIN ProjectManagement2.Projects `p` ON p.id = i.projectId
INNER JOIN ProjectManagement2.`ProjectComponents` `pc` ON pc.id = i.projectComponentId
INNER JOIN ProjectManagement2.ProjectVersions `pva` ON pva.id = i.affectedProjectVersionId
INNER JOIN ProjectManagement2.ProjectVersions `pvo` ON pvo.id = i.originalFixedProjectVersionId
INNER JOIN ProjectManagement2.ProjectVersions `pvf` ON pvf.id = i.fixedProjectVersionId
INNER JOIN ProjectManagement2.IssueSecurityLevels isl ON isl.id = i.issueSecurityLevelId

मैंने निम्नलिखित योगों के साथ इन क्वेरी को भी चलाया:

  • विशिष्ट आइटम का चयन करें (जहां i.key = 43298)
  • समूह द्वारा i.id
  • ऑर्डर द्वारा (it.title for int FK, i.issueTypeId for varchar FK)
  • सीमा (50000, 100)
  • समूह और सीमा एक साथ
  • समूह, आदेश, और सीमा एक साथ

इन परिणामों के लिए जहां:

तीन प्रकार: VARCHAR FK समय / INT FK समय


आधार क्वेरी: ~ 4ms / ~ 52ms

विशिष्ट आइटम का चयन करें: ~ 140ms / ~ 250ms

I.id द्वारा समूह: ~ 4ms / ~ 2.8 सेकेंड

द्वारा आदेश: ~ 231ms / ~ 2 सेक

सीमा: ~ 67ms / ~ 343ms

समूह और सीमा एक साथ: ~ 504ms / ~ 2sec

समूह, आदेश, और सीमा एक साथ: ~ 504ms /~2.3sec

अब मुझे नहीं पता कि मैं एक या दूसरे को (या दोनों को) तेज करने के लिए क्या विन्यास कर सकता हूं, लेकिन ऐसा लगता है कि VARCHAR FK डेटा के लिए प्रश्नों में तेजी से देखता है (कभी-कभी बहुत तेज)।

मुझे लगता है कि मुझे यह चुनना है कि क्या गति में सुधार अतिरिक्त डेटा / सूचकांक आकार के लायक है।


आपका परीक्षण कुछ इंगित करता है। मैं विभिन्न InnoDB सेटिंग्स (बफर पूल, आदि) के साथ भी परीक्षण करूंगा क्योंकि डिफ़ॉल्ट MySQL सेटिंग्स वास्तव में InnoDB के लिए अनुकूलित नहीं हैं।
ypercube y

आपको इन्सर्ट / अपडेट / डिलीट परफॉरमेंस का भी परीक्षण करना चाहिए क्योंकि यह इंडेक्स साइज़ से भी प्रभावित हो सकता है। प्रत्येक InnoDB तालिका की एक संकुल कुंजी आमतौर पर PK होती है और यह (PK) कॉलम हर दूसरे सूचकांक में भी शामिल होता है। यह शायद InnoDB में बड़े PKs का एक बड़ा नकारात्मक पहलू है और मेज पर कई अनुक्रमित हैं (लेकिन 32 बाइट्स मध्यम है, बड़ा नहीं है, इसलिए यह एक समस्या नहीं हो सकती है)।
ypercube y

आपको बड़ी तालिकाओं के साथ भी परीक्षण करना चाहिए (जैसे कि 10-100 मीटर पंक्तियों की श्रेणी में, या बड़ा), अगर आपको उम्मीद है कि आपकी तालिका 100K से अधिक बढ़ सकती है (जो वास्तव में बड़ी नहीं है)।
ypercube y

@ypercube तो मैं डेटा को 2 मिलियन तक बढ़ाता हूं और int FK के लिए चयन स्टेटमेंट धीमी गति से प्राप्त होता है जहां varchar विदेशी कुंजी बहुत स्थिर रहती है। ऐसा लगता है कि चुनिंदा प्रश्नों (जो इस विशेष तालिका और कुछ अन्य पर महत्वपूर्ण होने जा रहा है) में लाभ के लिए varchar डिस्क / मेमोरी आवश्यकताओं में मूल्य के लायक है।
ryanzec

निष्कर्ष में आने से पहले, बस अपने db (और विशेष रूप से InnoDB) सेटिंग्स को भी देखें। छोटे संदर्भ तालिकाओं के साथ, मुझे घातीय वृद्धि की उम्मीद नहीं होगी
ypercube

जवाबों:


9

मैं प्राथमिक कुंजी के लिए निम्नलिखित नियमों का पालन करता हूं:

क) कोई व्यावसायिक अर्थ नहीं होना चाहिए - वे आपके द्वारा विकसित किए जा रहे एप्लिकेशन से पूरी तरह से स्वतंत्र होना चाहिए, इसलिए मैं संख्यात्मक ऑटो उत्पन्न पूर्णांक के लिए जाता हूं। हालाँकि यदि आपको अद्वितीय होने के लिए अतिरिक्त स्तंभों की आवश्यकता है, तो उस का समर्थन करने के लिए अद्वितीय अनुक्रमित बनाएं

ख) जोड़ में प्रदर्शन करना चाहिए - प्राथमिक कुंजी की लंबाई बढ़ने पर varchars बनाम पूर्णांकों में शामिल होना लगभग 2x से 3x धीमा है, इसलिए आप पूर्णांक के रूप में अपनी कुंजी रखना चाहते हैं। चूंकि सभी कंप्यूटर सिस्टम बाइनरी हैं, मुझे संदेह है कि इसकी coz स्ट्रिंग को बाइनरी में बदल दिया जाता है, फिर दूसरों की तुलना में जो बहुत धीमा है

ग) संभवतया सबसे छोटे डेटा प्रकार का उपयोग करें - यदि आप उम्मीद करते हैं कि आपकी तालिका बहुत कम कॉलम कहती है कि ५२ अमेरिकी राज्य हैं, तो संभव है कि २ अंकों के कोड के लिए संभवतया सबसे छोटे प्रकार का उपयोग करें (२) (128) कॉलम बनाम एक बड़े इंट के लिए जो कि 2 बिलियन तक जा सकता है

इसके अलावा, यदि आपके पास प्रोजेक्ट की नाम परिवर्तन (जो असामान्य नहीं है) उदाहरण के लिए प्राथमिक कुंजी से अन्य तालिकाओं में अपने परिवर्तनों को कैस्केडिंग करने के साथ एक चुनौती होगी

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


1
स्ट्रिंग्स को बाइनरी में नहीं बदला जाता है; वे शुरू से ही बाइनरी में संग्रहीत हैं। उन्हें और कैसे संग्रहीत किया जाएगा? शायद आप केस-असंवेदनशील तुलना की अनुमति देने के लिए ऑपरेशन के बारे में सोच रहे हैं?
जॉन ऑफ ऑल ट्रेड्स

6

आपके परीक्षणों में आप varchar vs int keys प्रदर्शन अंतर की तुलना नहीं कर रहे हैं, बल्कि कई जोड़ों की लागत। यह आश्चर्य की बात नहीं है कि 1 तालिका को क्वेरी करना कई तालिकाओं में शामिल होने से तेज है।
Varchar प्राथमिक कुंजी का एक उल्टा सूचकांक का आकार बढ़ रहा है जैसा कि atxdba ने बताया है। यहां तक ​​कि अगर आपके लुकअप टेबल में PK के अलावा कोई अन्य इंडेक्स नहीं है (जो कि काफी संभावना नहीं है, लेकिन संभव है), प्रत्येक टेबल जो संदर्भ लुकअप है, इस कॉलम पर एक इंडेक्स होगा।
प्राकृतिक प्राथमिक कुंजी के बारे में एक और बुरी बात यह है कि उनका मूल्य बदल सकता है जो बहुत सारे कैस्केडिंग अपडेट का कारण बनता है। उदाहरण के लिए, सभी आरडीएमएस, ओरेकल नहीं हैं, यहां तक ​​कि आपके पास भी हैon update cascade। सामान्य तौर पर, बहुत खराब अभ्यास के रूप में विचार करते हुए प्राथमिक कुंजी मूल्य को बदलना। मैं यह नहीं कहना चाहता कि प्राकृतिक प्राथमिक कुंजी हमेशा बुराई होती है; यदि लुकअप मान छोटे हैं और कभी नहीं बदलते हैं तो मुझे लगता है कि स्वीकार्य हो सकता है।

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


3

सबसे बड़ी नकारात्मक स्थिति पीके की पुनरावृत्ति है। आपने डिस्क स्थान उपयोग में वृद्धि की ओर इशारा किया है लेकिन स्पष्ट होने के लिए कि अनुक्रमणिका का आकार आपकी बड़ी चिंता है। चूँकि innodb एक संकुल सूचकांक है, प्रत्येक माध्यमिक सूचकांक आंतरिक रूप से PK की एक प्रति संग्रहीत करता है जिसका उपयोग वह अंततः मिलान रिकॉर्ड खोजने के लिए करता है।

आप कहते हैं कि तालिकाओं के "छोटे" होने की उम्मीद है (20 पंक्तियाँ वास्तव में बहुत छोटी हैं)। यदि आपके पास innodb_buffer_pool_size को बराबर करने के लिए पर्याप्त RAM है

select sum(data_length+index_length) from information_schema.tables where engine='innodb';

फिर ऐसा करो और तुम शायद बहुत बैठे रहोगे। एक सामान्य नियम के रूप में, हालांकि आप कम से कम 30% - अन्य mysql ओवरहेड और कैश के लिए कुल सिस्टम मेमोरी का 40% छोड़ना चाहते हैं। और यह मान रहा है कि यह एक समर्पित DB सर्वर है। यदि आपके पास सिस्टम पर चलने वाली अन्य चीजें हैं, तो आपको उनकी आवश्यकताओं को भी ध्यान में रखना होगा।


1

@Atxdba उत्तर के अलावा - जिसमें बताया गया है कि डिस्क का उपयोग करने के लिए बेहतर क्यों होगा क्योंकि मैं दो बिंदु जोड़ना चाहता था:

  1. यदि आपकी समस्या तालिका VARCHAR FK आधारित है, और मान लें कि आपके पास 20 छोटे VARCHAR (32) FK हैं, तो आपका रिकॉर्ड 20x32bytes लंबाई तक पहुंच सकता है, जबकि जैसा कि आपके उल्लेखित अन्य टेबल लुकअप टेबल हैं, इसलिए INT FK TINYINT FK हो सकता है जो बनाते हैं 20 क्षेत्रों के लिए एक 20 बाइट्स रिकॉर्ड। मैं कई सैकड़ों रिकॉर्ड्स के लिए जानता हूं, लेकिन यह बहुत ज्यादा नहीं बदलेगा, लेकिन जब आपको कई मिलियन मिलेंगे तो मुझे लगता है कि आप अंतरिक्ष की बचत की सराहना करेंगे

  2. स्पीड इश्यू के लिए, मैं कवरिंग इंडेक्स का उपयोग करने पर विचार करूंगा, क्योंकि यह इस क्वेरी के लिए लगता है कि आप लुकअप टेबल से डेटा की अधिक मात्रा प्राप्त नहीं कर रहे हैं जो मैं इंडेक्स को कवर करने के लिए जाऊंगा और एक बार फिर आपके द्वारा उपलब्ध कराई गई परीक्षा VARCHAR FK / W / COITING INDEX और नियमित INT FK।

आशा है कि यह मदद कर सकता है,

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