2012-03-16 10 views
12

से सॉर्ट करें मेरे पास एक छवि अपलोडिंग सेवा का एक बहुत ही बुनियादी कार्यान्वयन है, जहां आप छवियां अपलोड कर सकते हैं और उन्हें टैग कर सकते हैं। यह मेरा स्कीमा है:एक अस्थायी बी पेड़ को हटाकर एक SQLite क्वेरी

CREATE TABLE Tag(
    orm_id INTEGER PRIMARY KEY AUTOINCREMENT, 
    pid_high UNSIGNED BIG INT NOT NULL, 
    pid_low UNSIGNED BIG INT NOT NULL, 
    name STRING NOT NULL, 
    CONSTRAINT KeyConstraint UNIQUE (pid_high, pid_low) ON CONFLICT FAIL); 

CREATE TABLE TagBridge(
    orm_id INTEGER PRIMARY KEY AUTOINCREMENT, 
    pid_high UNSIGNED BIG INT NOT NULL, 
    pid_low UNSIGNED BIG INT NOT NULL, 
    image_id_high UNSIGNED BIG INT NOT NULL, 
    image_id_low UNSIGNED BIG INT NOT NULL, 
    tag_id_high UNSIGNED BIG INT NOT NULL, 
    tag_id_low UNSIGNED BIG INT NOT NULL, 
    CONSTRAINT KeyConstraint UNIQUE (pid_high, pid_low) ON CONFLICT FAIL); 

CREATE TABLE Image(
    orm_id INTEGER PRIMARY KEY AUTOINCREMENT, 
    pid_high UNSIGNED BIG INT NOT NULL, 
    pid_low UNSIGNED BIG INT NOT NULL, 
    filehash STRING NOT NULL, 
    mime STRING NOT NULL, 
    uploadedDate INTEGER NOT NULL, 
    ratingsAverage REAL, 
    CONSTRAINT KeyConstraint UNIQUE (pid_high, pid_low) ON CONFLICT FAIL); 

और सूचकांकों

CREATE INDEX ImageTest on Image(pid_high, pid_low, uploadedDate DESC); 
CREATE INDEX ImagefilehashIndex ON Image (filehash); 
CREATE INDEX ImageuploadedDateIndex ON Image (uploadedDate); 
CREATE INDEX TagnameIndex ON Tag (name); 

कारण देखते हैं, अपने मानक प्राथमिक कुंजी के बजाय pid_high/pid_low क्षेत्रों क्योंकि इस सेवा के ग्राहक-आधिकारिक 128 बिट GUIDs का उपयोग करता है कि लेकिन यह क्वेरी गति को महत्वपूर्ण रूप से प्रभावित नहीं करता है।

चूंकि यह इंटरनेट है, इस सेवा पर छवियों का विशाल बहुमत बिल्लियों हैं, और उन्हें 'बिल्ली' के साथ टैग किया गया है। वास्तव में, 50,000 छवियों में से 47,000 को 'बिल्ली' के साथ टैग किया गया है। क्वेरी सभी छवियों है कि 'बिल्ली' के साथ टैग है पाने के लिए

select i.* from Tag t, TagBridge b, Image i 
where 
    b.tag_id_high = t.pid_high AND b.tag_id_low = t.pid_low 
AND b.image_id_high = i.pid_high and b.image_id_low = i.pid_low 
AND t.name ='cat' 
order by uploadedDate DESC LIMIT 20; 

इस के लिए क्वेरी योजना

sele order   from deta 
---- ------------- ---- ---- 
0  0    0  SEARCH TABLE Tag AS t USING INDEX TagnameIndex (name=?) (~1 rows) 
0  1    1  SCAN TABLE TagBridge AS b (~472 rows) 
0  2    2  SEARCH TABLE Image AS i USING INDEX ImageTest (pid_high=? AND pid_low=?) (~1 rows) 
0  0    0  USE TEMP B-TREE FOR ORDER BY 

है मुख्य समस्या यहाँ आदेश के लिए अंतिम पंक्ति, उपयोग अस्थायी बी पेड़ है द्वारा। यह क्वेरी को काफी धीमा कर देता है। 'ऑर्डर बाय' क्लॉज के बिना, पूरी क्वेरी को चलाने के लिए लगभग 0.001 लेते हैं। खंड द्वारा आदेश के साथ, क्वेरी 0.483 लेती है, जो एक 400x प्रदर्शन जुर्माना है।

मैं इस क्वेरी को 0.1 सेकंड के तहत प्राप्त करना चाहता हूं, लेकिन मुझे यकीन नहीं है कि कैसे। मैंने कई अन्य प्रश्नों की कोशिश की है, और सूचकांक जोड़ना और निकालना है, लेकिन यह सबसे तेज़ है कि मैं दौड़ने में सक्षम हूं।

+1

... 'बिल्ली' के साथ टैग टैग करने के लिए आवेग का विरोध। गंभीरता से, हालांकि, सवाल पर अच्छा काम, बहुत विस्तृत। – bernie

+0

मैंने अपना जवाब हटा दिया है, क्योंकि यह कहीं भी नहीं जा रहा था। अगर आपको इसे हल करने का कोई तरीका मिल जाए, तो मैं खुश हूं अगर आप इसे यहां पोस्ट करते हैं और @मेंटियन मुझे तो मैं देख सकता हूं। – Tomalak

+0

@Tomalak: यहां एक जवाब है। – Quassnoi

उत्तर

3

फ़िल्टर और आदेश सूचकांक के बीच चुनने की एक सामान्य समस्या है:

आप लोकप्रिय टैग की एक सूची रखना चाहिए (जिसके लिए आदेश देने के सूचकांक अधिक फायदेमंद है) और अगर टैग लोकप्रिय है, तो फ़िल्टरिंग इंडेक्स को किसी भी तरह से मनाएं, कहें, इस तरह:

SELECT i.* 
FROM Tag t, TagBridge b, Image i 
WHERE b.tag_id_high = t.pid_high AND b.tag_id_low = t.pid_low 
     AND b.image_id_high = i.pid_high AND b.image_id_low = i.pid_low 
     AND t.name || '' = 'cat' 
ORDER BY 
     i.uploadedDate DESC 
LIMIT 20 

वैकल्पिक रूप से, आप अपनी स्कीमा को denormalize कर सकते हैं और uploadedDateTagBridge जोड़ने के लिए, इसे ट्रिगर या जो कुछ भी भरकर जोड़ सकते हैं। तब TagBridge (pid_high, pid_low, uploadedDate, image_id_high, image_id_low) पर एक समग्र सूचकांक बना सकते हैं और क्वेरी एक छोटे से पुनर्लेखन:

SELECT i.* 
FROM TagBridge b, Image i 
WHERE b.tag_id_high = 
     (
     SELECT t.pid_high 
     FROM Tag t 
     WHERE t.name = 'cat' 
     ) 
     AND b.tag_id_low = 
     (
     SELECT t.pid_low 
     FROM Tag t 
     WHERE t.name = 'cat' 
     ) 
     AND i.pid_high = b.image_id_high 
     AND i.pid_low = b.image_id_low 
ORDER BY 
     b.uploadedDate DESC 
LIMIT 20; 

डबल सबक्वेरी है, क्योंकि SQLite टपल वाक्य रचना को नहीं समझता।

+0

+1 denormalizing बहुत अच्छी तरह से काम करेगा। निश्चित रूप से सिंक में सभी 'अपलोड किए गए दिनांक' मानों को रखने के लिए टैग परिवर्तन होने पर देखभाल की जानी चाहिए। मुझे अन्य विचार भी पसंद है। – Tomalak

संबंधित मुद्दे