मैं निम्नलिखित स्थिति के लिए तालिका / सूचकांक डिजाइन पर सलाह की तलाश कर रहा हूं:
मेरे पास एक कंपाउंड प्राइमरी कुंजी (एसेटिड (इंट), डेट (तारीख)) के साथ एक बड़ी टेबल (स्टॉक प्राइस हिस्ट्री डेटा, इनोबीडी, 35 मिलियन पंक्तियाँ और बढ़ती) हैं। मूल्य निर्धारण की जानकारी के अलावा, मेरे पास 200 दोहरे मूल्य हैं जो प्रत्येक रिकॉर्ड के अनुरूप होने की आवश्यकता है।
CREATE TABLE `mytable` (
`assetid` int(11) NOT NULL,
`date` date NOT NULL,
`close` double NOT NULL,
`f1` double DEFAULT NULL,
`f2` double DEFAULT NULL,
`f3` double DEFAULT NULL,
`f4` double DEFAULT NULL,
... skip a few …
`f200` double DEFAULT NULL,
PRIMARY KEY (`assetid`, `date`)) ENGINE=`InnoDB` DEFAULT CHARACTER SET latin1 COLLATE
latin1_swedish_ci ROW_FORMAT=COMPACT CHECKSUM=0 DELAY_KEY_WRITE=0
PARTITION BY RANGE COLUMNS(`date`) PARTITIONS 51;
मैंने शुरू में अद्यतन और पुनर्प्राप्ति में आसानी के लिए सीधे इस तालिका में 200 डबल कॉलम संग्रहीत किए, और यह ठीक काम कर रहा था, क्योंकि इस तालिका पर केवल क्वेरीज़ एसेटिड और तारीख द्वारा की गई थी (ये धार्मिक रूप से इस तालिका के खिलाफ किसी भी क्वेरी में शामिल हैं) ), और 200 डबल कॉलम केवल पढ़े गए थे। मेरे डेटाबेस का आकार 45 गिग के आसपास था
हालाँकि, अब मेरे पास वह आवश्यकता है जहां मुझे इन 200 कॉलमों के किसी भी संयोजन (उदाहरण के लिए f1, f2, ... f200) के द्वारा इस तालिका को क्वेरी करने में सक्षम होना चाहिए, उदाहरण के लिए:
select from mytable
where assetid in (1,2,3,4,5,6,7,....)
and date > '2010-1-1' and date < '2013-4-5'
and f1 > -0.23 and f1 < 0.9
and f117 > 0.012 and f117 < .877
etc,etc
मुझे ऐतिहासिक रूप से इससे पहले डेटा की इस बड़ी मात्रा से निपटना नहीं पड़ा है, इसलिए मेरी पहली वृत्ति यह थी कि इन 200 स्तंभों में से प्रत्येक पर अनुक्रमित की आवश्यकता थी, या मैं बड़ी तालिका स्कैन आदि के साथ हवा करूंगा, मेरे लिए इसका मतलब यह था कि मुझे प्राथमिक कुंजी, मूल्य और मानों को अनुक्रमित करने वाले 200 स्तंभों में से प्रत्येक के लिए एक तालिका की आवश्यकता है। तो मैं उस के साथ चला गया।
CREATE TABLE `f1` (
`assetid` int(11) NOT NULL DEFAULT '0',
`date` date NOT NULL DEFAULT '0000-00-00',
`value` double NOT NULL DEFAULT '0',
PRIMARY KEY (`assetid`, `date`),
INDEX `val` (`value`)
) ENGINE=`InnoDB` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ROW_FORMAT=COMPACT CHECKSUM=0 DELAY_KEY_WRITE=0;
मैंने सभी 200 तालिकाओं को भरा और अनुक्रमित किया। मैंने सभी 200 कॉलमों के साथ मुख्य तालिका को बरकरार रखा, क्योंकि नियमित रूप से इसे एसेटिड और डेट रेंज पर छोड़ दिया जाता है और सभी 200 कॉलम चुने जाते हैं। मुझे लगा कि पढ़ने के उद्देश्यों के लिए उन कॉलमों को पेरेंट टेबल (अनइंस्टैच्ड) में छोड़ दिया गया है, और फिर इसके अलावा उन्हें अपनी टेबल में शामिल करने के लिए (फ़िल्टरिंग में शामिल होने के लिए) सबसे अधिक प्रदर्शन किया जाएगा। मैं क्वेरी के नए रूप पर व्याख्या करता था
select count(p.assetid) as total
from mytable p
inner join f1 f1 on f1.assetid = p.assetid and f1.date = p.date
inner join f2 f2 on f2.assetid = p.assetid and f2.date = p.date
where p.assetid in(1,2,3,4,5,6,7)
and p.date >= '2011-01-01' and p.date < '2013-03-14'
and(f1.value >= 0.96 and f1.value <= 0.97 and f2.value >= 0.96 and f2.value <= 0.97)
वास्तव में मेरा वांछित परिणाम प्राप्त किया गया था, मुझे समझाता है कि स्कैन की गई पंक्तियाँ इस क्वेरी के लिए बहुत छोटी हैं। हालांकि मैं कुछ अवांछनीय दुष्प्रभावों के साथ घायल हो गया।
1) मेरा डेटाबेस 45 गिग से 110 गिग तक चला गया। मैं अब db को RAM में नहीं रख सकता। (हालांकि मेरे पास रास्ते में 256Gig RAM है)
2) नए डेटा के रात के आवेषण को अब एक बार के बजाय 200 बार करने की आवश्यकता है
3) नई 200 टेबलों का रखरखाव / डीफ़्रैग केवल 1 टेबल की तुलना में 200 गुना अधिक समय लेता है। इसे एक रात में पूरा नहीं किया जा सकता है।
4) एफ 1 आदि के खिलाफ पूछताछ जरूरी नहीं है। उदाहरण के लिए:
select min(value) from f1
where assetid in (1,2,3,4,5,6,7)
and date >= '2013-3-18' and date < '2013-3-19'
उपरोक्त क्वेरी, जबकि यह बताती है कि यह <1000 पंक्तियों में दिखता है, इसे पूरा करने में 30+ सेकंड लग सकते हैं। मुझे लगता है कि यह इसलिए है क्योंकि सूचकांक स्मृति में फिट होने के लिए बहुत बड़े हैं।
चूंकि यह बुरी खबर थी, इसलिए मैंने आगे देखा और विभाजन पाया। मैंने मुख्य सारणी पर विभाजन को लागू किया, हर 3 महीने में तारीख पर विभाजन। मासिक मुझे समझ में आ रहा था लेकिन मैंने पढ़ा है कि एक बार जब आप 120 से अधिक विभाजन प्राप्त करते हैं, तो प्रदर्शन में कमी आती है। अगले 20 वर्षों के लिए त्रैमासिक विभाजन मुझे उसी के तहत छोड़ देगा। प्रत्येक विभाजन 2 गिग के तहत एक सा है। मैं विभाजनों की व्याख्या करता था और सब कुछ ठीक से लगता था, इसलिए मुझे लगता है कि विभाजन एक अच्छा कदम था, विश्लेषण / अनुकूलन / मरम्मत के लिए बहुत कम से कम।
मैंने इस लेख के साथ अच्छा समय बिताया
http://ftp.nchu.edu.tw/MySQL/tech-resources/articles/testing-partitions-large-db.html
मेरी तालिका वर्तमान में अभी भी उस पर प्राथमिक कुंजी के साथ विभाजित है। लेख में उल्लेख किया गया है कि प्राथमिक कुंजियाँ एक विभाजित तालिका को धीमा कर सकती हैं, लेकिन यदि आपके पास एक मशीन है जो इसे संभाल सकती है, तो विभाजन तालिका में प्राथमिक कुंजियाँ तेज़ होंगी। यह जानकर कि मेरे पास रास्ते में एक बड़ी मशीन है (256 G RAM), मैंने चाबी छोड़ दी।
इसलिए जैसा कि मैंने इसे देखा, यहाँ मेरे विकल्प हैं
विकल्प 1
1) अतिरिक्त 200 तालिकाओं को हटा दें और f1, f2 आदि मानों को खोजने के लिए क्वेरी को टेबल स्कैन करने दें। गैर-अनूठे सूचकांक वास्तव में एक ठीक से विभाजित तालिका पर प्रदर्शन को चोट पहुंचा सकते हैं। उपयोगकर्ता द्वारा क्वेरी चलाने से पहले एक व्याख्या चलाएं और उन्हें स्कैन करें यदि स्कैन की गई पंक्तियों की संख्या कुछ सीमा से अधिक है जो मैं परिभाषित करता हूं। विशाल डेटाबेस के दर्द से खुद को बचाएं। बिल्ली, यह सब जल्द ही वैसे भी स्मृति में होगा।
उप प्रश्न:
क्या ऐसा लगता है कि मैंने एक उपयुक्त विभाजन योजना को चुना है?
विकल्प 2
एक ही 3 महीने की योजना का उपयोग करके सभी 200 तालिकाओं का विभाजन। छोटी पंक्ति स्कैन का आनंद लें और उपयोगकर्ताओं को बड़ी क्वेरी चलाने की अनुमति दें। अब जब वे कम से कम विभाजित होते हैं, तो मैं रखरखाव प्रयोजनों के लिए एक समय में उन्हें 1 विभाजन का प्रबंधन कर सकता हूं। बिल्ली, यह सब जल्द ही वैसे भी स्मृति में होगा। उन्हें रात में अद्यतन करने के लिए कुशल तरीका विकसित करें।
उप प्रश्न:
क्या आप एक कारण देखते हैं कि मैं इन एफ 1, एफ 2, एफ 3, एफ 4 ... टेबल पर प्राथमिक कुंजी अनुक्रमों से बच सकता हूं, यह जानते हुए कि क्वेरी करते समय मेरे पास हमेशा संपत्ति और तारीख होती है? मेरे लिए काउंटर सहज लगता है, लेकिन मैं इस आकार के डेटा सेट के लिए उपयोग नहीं किया जाता हूं। कि डेटाबेस एक गुच्छा मुझे लगता है हटना होगा
विकल्प 3
उस स्थान को पुनः प्राप्त करने के लिए मास्टर तालिका में f1, f2, f3 कॉलम छोड़ें। अगर मैं 200 विशेषताओं को पढ़ने की आवश्यकता है, तो 200 जुड़ता है, शायद यह उतना धीमा नहीं होगा जितना लगता है।
विकल्प 4
मैंने अब तक जितना सोचा है, आप सभी के पास इसे तैयार करने का बेहतर तरीका है।
* नोट: मैं जल्द ही प्रत्येक आइटम में इन दोहरे मूल्यों में से एक और 50-100 जोड़ रहा हूं, इसलिए मुझे यह जानने की आवश्यकता है कि आने वाला डिजाइन क्या है।
किसी भी और सभी तरह की मदद के लिए धन्यवाद
अपडेट # 1 - 3/24/2013
मैं नीचे दिए गए टिप्पणियों में सुझाए गए विचार के साथ गया और निम्न सेटअप के साथ एक नई तालिका बनाई:
create table 'features'{
assetid int,
date date,
feature varchar(4),
value double
}
मैंने 3 महीने के अंतराल में तालिका का विभाजन किया।
मैंने पहले की 200 टेबलों को उड़ा दिया ताकि मेरा डेटाबेस 45 गिग पर वापस आ जाए और इस नई तालिका को भरना शुरू कर दिया। डेढ़ दिन बाद, यह पूरा हो गया, और मेरा डेटाबेस अब एक चब्बी २२० गिग्स पर बैठता है !
यह मास्टर टेबल से इन 200 मूल्यों को हटाने की संभावना को अनुमति देता है, जैसा कि मैं उन्हें एक में शामिल होने से प्राप्त कर सकता हूं, लेकिन यह वास्तव में मुझे केवल 25 गिग्स वापस दे देगा या शायद
मैंने इसे एसेटिड, प्राइमरी, फ़ीचर और मूल्य पर एक इंडेक्स पर एक प्राथमिक कुंजी बनाने के लिए कहा था, और 9 घंटे की चुगली के बाद वास्तव में यह एक दाँत नहीं बना था और ऐसा लग रहा था कि मैंने उस हिस्से को मार दिया।
मैंने कुछ विभाजनों का पुनर्निर्माण किया, लेकिन यह बहुत अधिक / किसी भी स्थान को पुनः प्राप्त करने के लिए प्रतीत नहीं हुआ।
तो यह समाधान ऐसा लगता है कि यह आदर्श नहीं है। क्या पंक्तियों में मुझे आश्चर्यचकित करने वाले स्तंभों की तुलना में बहुत अधिक जगह मिलती है, क्या ऐसा हो सकता है कि इस समाधान ने इतना अधिक स्थान लिया हो?
मुझे यह लेख आया:
http://www.chrismoos.com/2010/01/31/mysql-partitioning-tables-with-millions-of-rows
इसने मुझे एक विचार दिया। इसे कहते हैं:
सबसे पहले, मैंने तिथि के हिसाब से RANGE विभाजन के बारे में सोचा, और जब मैं अपने प्रश्नों में तिथि का उपयोग कर रहा हूं, तो क्वेरी के लिए बहुत बड़ी तिथि सीमा होना बहुत आम है, और इसका मतलब है कि यह आसानी से सभी विभाजनों को पूरा कर सकता है।
अब मैं तिथि के अनुसार विभाजन भी कर रहा हूं, लेकिन बड़ी तिथि सीमा तक खोजों की अनुमति देगा, जिससे मेरे विभाजन की प्रभावशीलता कम हो जाएगी। जब मैं खोज करूंगा तो मेरे पास हमेशा एक तिथि सीमा होगी, हालांकि मेरे पास हमेशा परिसंपत्तियों की एक सूची भी होगी। शायद मेरा समाधान एसेटिड और दिनांक द्वारा विभाजन के लिए होना चाहिए, जहां मैं आमतौर पर खोजे गए एसेटिड पर्वतमाला की पहचान करता हूं (जो मैं साथ आ सकता हूं, मानक सूची हैं, एसएंडपी 500, रसेल 2000, आदि)। इस तरह मैं लगभग पूरे डेटा सेट को कभी नहीं देखूंगा।
तो फिर, मैं एसेटिड और डेट वैसे भी प्राथमिक रूप से बंद हूं, इसलिए शायद इससे बहुत मदद नहीं मिलेगी।
किसी भी अधिक विचार / टिप्पणी की सराहना की जाएगी।
(value_name varchar(20), value double)
दुकान सब कुछ करने में सक्षम होगा (value_name
किया जा रहा हैf1
,f2
, ...)