2010-03-21 11 views
6

मैं संबंधपरक डेटाबेस के साथ काम करने के लिए बिल्कुल नया हूं, लेकिन कुछ किताबें पढ़ी हैं और अच्छी डिजाइन की मूल बातें जानी हैं।mySQL दक्षता समस्या - सामान्यीकरण के सही संतुलन को कैसे ढूंढें ...?

मुझे एक डिज़ाइन निर्णय का सामना करना पड़ रहा है, और मुझे यकीन नहीं है कि कैसे जारी रखना है। यहां जो कुछ भी मैं बना रहा हूं उसका एक बहुत ही सरल संस्करण यहां दिया गया है: लोग फोटो 1-5 रेट कर सकते हैं, और व्यक्तिगत वोटों का ट्रैक रखते हुए मुझे तस्वीर पर औसत वोट प्रदर्शित करने की आवश्यकता है। उदाहरण के लिए, 12 लोग मतदान 1, 7 लोगों मतदान 2, आदि आदि

मुझे को सामान्य सनकी शुरू में इस तरह की मेज संरचना तैयार किया गया है: सभी विदेशी कुंजी की कमी और सब कुछ सेट के साथ

Table pictures 
id* | picture | userID | 

Table ratings 
id* | pictureID | userID | rating 

जैसे वे shoudl हो। जब भी कोई चित्र चित्रित करता है, तो मैं सिर्फ रेटिंग में एक नया रिकॉर्ड डालता हूं और इसके साथ किया जाता हूं।

एक तस्वीर की औसत रेटिंग ढूंढने के लिए, मैं सिर्फ कुछ इस तरह चलाने चाहते हैं:

SELECT AVG(rating) FROM ratings WHERE pictureID = '5' GROUP by pictureID 

यह सेटअप इस तरह से मेरे लिए मेरी कल्पना आँकड़े चलाने देता है के बाद। मैं आसानी से ढूंढ सकता हूं कि किसने एक निश्चित तस्वीर को 3 रेट किया, और क्या नहीं।

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

गैर-सामान्यीकृत संस्करण का उपयोग करना अधिक कुशल प्रतीत होता है। उदाहरण:

Table picture 
id | picture | userID | ratingOne | ratingTwo | ratingThree | ratingFour | ratingFive 

औसत की गणना करने के लिए, मुझे बस एक पंक्ति चुननी होगी। यह बहुत अधिक कुशल लगता है, लेकिन बहुत अधिक उलझन में।

क्या कोई मुझे सही दिशा में इंगित कर सकता है कि क्या करना है? मेरा प्रारंभिक शोध दिखाता है कि मुझे "सही संतुलन ढूंढना है", लेकिन मैं उस संतुलन को खोजने के लिए कैसे जा सकता हूं? किसी भी लेख या अतिरिक्त पढ़ने की जानकारी भी सराहना की जाएगी।

धन्यवाद।

+0

आप प्रदर्शन के मुद्दों में चलाने है या तुम सिर्फ पूछना है? – Pentium10

+0

मैंने अभी तक प्रदर्शन समस्याओं में भाग नहीं लिया है। मैं बस कुछ ऐसा डिज़ाइन नहीं करना चाहता जो संभावित रूप से उच्च लोड के तहत बकवास करेगा। – Foo

उत्तर

4

आपका सामान्य दृष्टिकोण बहुत समझ में आता है, denormalized एक नहीं करता है।

Table: pictures 
id* | picture | userID | avg_rating | rating_count 

Table: ratings 
id* | pictureID | userID | rating 

टेल्को चित्रों मूल्यांकन का पुन: गणना की जाएगी के लिए:


मेरे अनुभव में (टेल्को प्रदर्शन प्रबंधन, प्रति 1/4 घंटे datapoints लाखों) हम निम्नलिखित करना होगा एक बार दैनिक, आपको इसे आवधिक करना चाहिए (उदाहरण के लिएप्रति घंटा) या हर बार जब आप डालेंगे (रेटेड तस्वीर के लिए पुनः-कैल्क, पूरी तालिका नहीं)। यह आपको मिलने वाली रेटिंग की मात्रा पर निर्भर करता है।


टेल्को में हम भी अपने 'चित्र' मेज और रेटिंग तालिका में एक 1/4 टाइमस्टैम्प है क्या में रेटिंग की तारीख रखने के लिए, लेकिन मुझे नहीं लगता कि आप विस्तार के उस स्तर की जरूरत है।


'असमान्यीकरण' चित्रों मेज पर एक calculateable तथ्य (गिनती (रेटिंग) और औसत (रेटिंग)) ले जाने के लिए है। यह सीपीयू चक्र बचाता है, लेकिन अधिक भंडारण लागत।

+0

+1, मैं इसकी सिफारिश करता ... –

1

इन रेटिंगों को रेटिंग करने के लिए क्या होगा फ़ील्ड फ़ील्ड में? वोटों की संख्या प्राप्त हुई? तब आप नहीं जान पाएंगे कि वोट किसने डाला। यदि आपको वास्तव में denormalize करने की आवश्यकता है, तो मैं सिर्फ तस्वीर तालिका में "औसत रेटिंग" फ़ील्ड जोड़ूंगा, और अपडेट करें कि जब भी वोट डाला जाता है (और रेटिंग तालिका को रखें)।

अधिक आम तौर पर, समयपूर्व अनुकूलन में पकड़े नहीं जाते हैं। एक टेस्ट स्क्रिप्ट लिखने का प्रयास करें जो 100,000 चित्र और 1 मिलियन रेटिंग (या जो भी आंकड़ा आप समर्थन करना चाहते हैं) बनाता है, और देखें कि आपकी AVG क्वेरी कितनी देर तक लेती है। संभावना है कि यह अभी भी बहुत तेज़ होगा। सुनिश्चित करें कि आपकी "रेटिंग" तालिका में चित्र आईडी पर एक अनुक्रमणिका है, इसलिए डीबी को लाखों पंक्तियों को पार करने की आवश्यकता नहीं है।

+0

धन्यवाद। में इसे याद रखूंगा। मैं टेस्ट केस लिखने पर ध्यान केंद्रित करूंगा और देख सकता हूं कि यह अगली बार कैसा प्रदर्शन करता है। – Foo

1

आरडीबीएमएस दुनिया में, असमान्यीकरण मतलब है

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

लेकिन मॉडल शुद्धता के बारे में क्या?

इस डिज़ाइन के साथ, आप पहले नहीं जानते कि वोट किसने बनाया है (यह जानकारी अब और संग्रहीत नहीं है), और दूसरा, चित्र को पांच गुना से अधिक रेट नहीं कर सकता है।

चूंकि आपके प्रारंभिक मॉडल में इनमें से कोई भी प्रतिबंध नहीं था, मेरा मानना ​​है कि इस तरह का denormalization वह नहीं है जो आप वास्तव में चाहते हैं।

1

दोनों दुनिया का आनंद लेने का एक अच्छा तरीका माइस्क्ल ट्रिगर का उपयोग कर रहा है। http://dev.mysql.com/doc/refman/5.0/en/triggers.html

अब एक ट्रिगर जोड़ें कि जब कोई उपयोगकर्ता चित्र को रेट करता है तो यह चित्र तालिकाओं में avg_rating को अपडेट करेगा। (उसी चयन का उपयोग करके आपने कहा है)

अब जब आप चुनते हैं, तो आप केवल एक टेबल पर चयन कर सकते हैं। और यह हमेशा अद्यतन किया जाता है। और यदि आप रेटिंग तालिका से कौन सी तस्वीर चुन सकते हैं, तो सटीक जानकारी प्राप्त करना चाहते हैं।

2

यह कैसे मैं समस्या दृष्टिकोण होगा http://pastie.org/879604

drop table if exists picture; 
create table picture 
( 
picture_id int unsigned not null auto_increment primary key, 
user_id int unsigned not null, -- owner of the picture, the user who uploaded it 
tot_votes int unsigned not null default 0, -- total number of votes 
tot_rating int unsigned not null default 0, -- accumulative ratings 
avg_rating decimal(5,2) not null default 0, -- tot_rating/tot_votes 
key picture_user_idx(user_id) 
)engine=innodb; 

insert into picture (user_id) values 
(1),(2),(3),(4),(5),(6),(7),(1),(1),(2),(3),(6),(7),(7),(5); 


drop table if exists picture_vote; 
create table picture_vote 
( 
picture_id int unsigned not null, 
user_id int unsigned not null,-- voter 
rating tinyint unsigned not null default 0, -- rating 0 to 5 
primary key (picture_id, user_id) 
)engine=innodb; 

delimiter # 

create trigger picture_vote_before_ins_trig before insert on picture_vote 
for each row 
begin 
declare total_rating int unsigned default 0; 
declare total_votes int unsigned default 0; 

select tot_rating + new.rating, tot_votes + 1 into total_rating, total_votes 
    from picture where picture_id = new.picture_id; 

-- counts/stats 
update picture set 
    tot_votes = total_votes, tot_rating = total_rating, 
    avg_rating = total_rating/total_votes 
where picture_id = new.picture_id; 

end# 
delimiter ; 

आशा है कि यह मदद करता है :)