2009-09-02 16 views
27

ठीक है मुझे परिणामों को फ़िल्टर करने के लिए कुछ उपयोगकर्ता इनपुट के आधार पर एक क्वेरी बनाने की आवश्यकता है।मेरी क्वेरी कितनी खराब है?

SELECT * FROM my_table ORDER BY ordering_fld; 

, चार पाठ बॉक्स है, जिसमें उन डेटा फ़िल्टर कर सकते हैं कर रहे हैं, जिसका अर्थ है मैं गतिशील के लिए इसे में एक "कहां" खंड का निर्माण करना होगा:

क्वेरी मूल रूप से कुछ इस तरह चला जाता है पहले फ़िल्टर का उपयोग किया गया और फिर प्रत्येक और बाद वाले फ़िल्टर के लिए "AND" खंड दर्ज किए गए।

क्योंकि मैं ऐसा करने के लिए बहुत आलसी हूं, मैंने अभी प्रत्येक फिल्टर को "और" खंड बना दिया है और डिफ़ॉल्ट रूप से क्वेरी में "WHERE 1" खंड लगाया है।

तो अब मेरे पास है:

SELECT * FROM my_table WHERE 1 {AND filters} ORDER BY ordering_fld; 

तो मेरे सवाल है, मैं कुछ है कि प्रतिकूल किसी भी तरह से मैं के बारे में दूर से चिंतित होना चाहिए में मेरी क्वेरी का प्रदर्शन या buggered कुछ और ऊपर को प्रभावित करेगा किया है है?

+0

रेली दिलचस्प सवाल –

+10

क्या मेरी क्वेरी इस में बड़ी दिखती है? –

+6

क्या यह सिर्फ मुझे है या Evernoob बेहद बहादुर है? मैं कभी भी अन्य डेवलपर्स से भरी साइट नहीं पूछना चाहूंगा (जिन्हें कुख्यात रूप से राय दी गई है) मेरा कोड कितना बुरा था? –

उत्तर

37

MySQL आपके 1 दूर ऑप्टिमाइज़ करेगा।

मैं बस अपना परीक्षण डेटाबेस पर इस क्वेरी भाग गया:

EXPLAIN EXTENDED 
SELECT * 
FROM t_source 
WHERE 1 AND id < 100 

और यह मेरे निम्नलिखित description दिया:

select `test`.`t_source`.`id` AS `id`,`test`.`t_source`.`value` AS `value`,`test`.`t_source`.`val` AS `val`,`test`.`t_source`.`nid` AS `nid` from `test`.`t_source` where (`test`.`t_source`.`id` < 100) 

आप देख सकते हैं, सभी में कोई 1

MySQL में WHERE clause optimization पर दस्तावेज़ीकरण में यह उल्लेख है:

  • लगातार तह:

    (a<b AND b=c) AND a=5 
    -> b>5 AND b=c AND a=5 
    
  • लगातार हालत हटाने (निरंतर तह की वजह से आवश्यक):

    (B>=5 AND B=5) OR (B=6 AND 5=5) OR (B=7 AND 5=6) 
    -> B=5 OR B=6 
    

नोट 5 = 5 और 5 = 6 उपर्युक्त उदाहरण में भागों।

+0

EXPLAIN का उपयोग करके और प्रलेखन को देखकर – knittl

+8

'@ knittl' को देखने का प्रयास करने के लिए +1: यदि प्रत्येक डेवलपर 'EXPLAIN' का उपयोग करता है और दस्तावेज़ीकरण को देखता है, तो दुनिया एक बहुत अच्छी जगह होगी! – Quassnoi

+0

+1 दुनिया को एक अच्छी जगह बनाने की कोशिश करने के लिए +1 :) – waqasahmed

2

प्रदर्शन में सुधार करने, खेतों पर स्तंभ अनुक्रमणिका का उपयोग में सुनने "कहाँ"

2

स्टैंडर्ड SQL इंजेक्शन यहाँ अस्वीकरण ...

एक बात तुम कर सकते हो, एसक्यूएल इंजेक्शन से बचने के लिए के बाद से आप जानते हैं केवल चार है पैरामीटर एक संग्रहीत प्रक्रिया का उपयोग करते हैं जहां आप फ़ील्ड या न्यूल के लिए मान पास करते हैं। मैं mySQL संग्रहीत proc वाक्य रचना के बारे में सुनिश्चित नहीं हूँ, लेकिन क्वेरी

SELECT * 
    FROM my_table 
WHERE Field1 = ISNULL(@Field1, Field1) 
    AND Field2 = ISNULL(@Field2, Field2) 
    ... 
ORDRE BY ordering_fld 
+0

जो फ़ील्ड 1, इत्यादि पर इंडेक्स के उपयोग को रोकने के लिए प्रेरित करता है, को ISNULL –

+0

के बजाय COALESCE का भी उपयोग करना चाहिए सही प्रारूप @ फ़ील्ड आईएस नल या t.col = @ फ़ील्ड होगा। यह अन्यथा बर्बाद इंडेक्स लुकअप या टेबल स्कैन है। –

8

करने के लिए नीचे उबाल हैं आप अपनी क्वेरी व्याख्या कर सकते हैं:
http://dev.mysql.com/doc/refman/5.0/en/explain.html

और अगर यह कुछ अलग करता है देखते हैं, जो मुझे शक है। मैं 1 = 1 का उपयोग करूंगा, बस इतना स्पष्ट है।

आप LIMIT 1000 या कुछ जोड़ना चाहते हैं, जब कोई पैरामीटर उपयोग नहीं किया जाता है और तालिका बड़ी हो जाती है, तो क्या आप वास्तव में सब कुछ वापस करना चाहते हैं?

+0

'@ केएम': टैग के अनुसार, यह' LIMIT 1000' होना चाहिए :) – Quassnoi

+0

@Quassnoi, धन्यवाद, जब मैंने पहली बार जवाब दिया था, तो मैं mysql सोच रहा था, लेकिन जब मैंने संपादित किया और _TOP 1000_ भाग जोड़ा, तो मुझे लगता था कि SQL सर्वर । –

4

यदि एसक्यूएल स्वयं को बनाने से बचने के लिए आपकी चुनी भाषा में कोई अच्छा तरीका है, तो इसके बजाय इसका उपयोग करें। मुझे पायथन और डीजेगो पसंद है, और Django ORM उपयोगकर्ता इनपुट के आधार पर फ़िल्टर फ़िल्टर करना बहुत आसान बनाता है।

यदि आप स्वयं SQL को बनाने के लिए प्रतिबद्ध हैं, तो सुनिश्चित करें कि SQL इंजेक्शन के विरुद्ध उपयोगकर्ता इनपुट को स्वच्छ करना सुनिश्चित करें, और अपने फ़िल्टर तर्क से एक अलग मॉड्यूल में SQL भवन को समाहित करने का प्रयास करें।

इसके अलावा, क्वेरी प्रदर्शन तब तक आपकी चिंता नहीं होनी चाहिए जब तक कि यह कोई समस्या न हो जाए, जो शायद तब तक नहीं होगा जब तक आपके पास हजारों या लाखों पंक्तियां न हों। और जब इसे अनुकूलित करने का समय आता है, तो WHERE और JOIN के लिए उपयोग किए गए कॉलम पर कुछ अनुक्रमणिका जोड़ना एक लंबा रास्ता तय करता है।

5

WHERE 1 एक स्थिर, निर्धारिक अभिव्यक्ति है जिसे किसी भी सभ्य डीबी इंजन द्वारा "अनुकूलित" किया जाएगा।

2

हम समान बहुत लंबा नहीं पहले कुछ कर रहा हूँ और वहाँ कुछ चीजें हैं जो हमने देखा कर रहे हैं:

  • स्तंभों हम (संभवतः) छानने थे, बेहतर प्रदर्शन
  • सूचक की स्थापना
  • फ़िल्टर का उपयोग नहीं होने पर WHERE 1 भाग पूरी तरह से छोड़ा जा सकता है। (सुनिश्चित नहीं है कि यह आपके मामले पर लागू होता है) कोई फर्क नहीं पड़ता है, लेकिन सही लगता है।
  • एसक्यूएल इंजेक्शन

भूल नहीं किया जाना चाहिए इसके अलावा, अगर आप 'केवल' 4 फिल्टर है, तो आप एक संग्रहीत प्रक्रिया का निर्माण और शून्य मान में गुजरती हैं और उनके लिए जांच कर सकता है। (जैसे n8wrl इस बीच में सुझाव दिया)

+0

मैं एसक्यूएल इंजेक्शन के बारे में ज्यादा चिंतित नहीं हूं, मैं इसे संभालने में सक्षम हूं।यह और अधिक था कि मैं जो किया था उसकी स्वीकार्यता के बारे में सिर्फ उत्सुक था। – Evernoob

2

यही काम करेंगे - कुछ विचार:

सामान्य रूप में के बारे में गतिशील रूप से बनाया एसक्यूएल, कुछ डेटाबेस (Oracle कम से कम), इसलिए यदि आप खत्म, प्रश्नों के लिए निष्पादन की योजना कैश होगा एक ही क्वेरी को कई बार चलाना इसे स्क्रैच से पूरी तरह से शुरू नहीं करना पड़ेगा। यदि आप गतिशील रूप से निर्मित SQL का उपयोग करते हैं, तो आप डेटाबेस के लिए प्रत्येक बार एक अलग क्वेरी बना रहे हैं, यह एक ही क्वेरी के 100 रनों के बजाय 100 अलग-अलग प्रश्नों की तरह दिखेगा।

आपको शायद यह पता लगाने के लिए प्रदर्शन को मापने की आवश्यकता होगी कि यह आपके लिए पर्याप्त रूप से पर्याप्त काम करता है या नहीं।

क्या आपको सभी कॉलम चाहिए? स्पष्ट रूप से निर्दिष्ट करने के लिए उन्हें शायद का उपयोग कर से बेहतर है * वैसे भी है क्योंकि:

  • आप नेत्रहीन देख सकते हैं कि कॉलम में लौटाए जा रहे
  • आप जोड़ सकते हैं या बाद में तालिका में कॉलम निकालते हैं, तो वे अपने इंटरफेस में परिवर्तन नहीं होगा
+0

ओरेकल सबमिट की गई क्वेरी की सामग्री के आधार पर कैश की जांच करता है, न कि उपयोगकर्ता द्वारा दिए गए फ़ंक्शन या प्रक्रिया को चलाने के तथ्य। –

2

बुरा नहीं, मुझे यह स्निपेट नहीं पता था कि 'यह पहला फ़िल्टर 3' प्रश्न है।

आपको अपने कोड (^^) से शर्मिंदा होना चाहिए, यह प्रदर्शन के लिए कुछ भी नहीं करता है क्योंकि किसी भी डीबी इंजन इसे अनुकूलित करेगा।

+0

हाहा, मुझे अपने कोड से शर्मिंदा क्यों होना चाहिए? यदि डीबी इंजन इसे अनुकूलित करता है, तो चीजों के डीबी पक्ष पर कोई नुकसान नहीं होता है और मेरा व्यवसाय तर्क अब स्पष्ट और अगले व्यक्ति के लिए अधिक पठनीय है। तो शर्म की बात कहां है? – Evernoob

+0

क्योंकि आप "1 = 1" जोड़ते हैं, जो बेकार कोड है, जो खराब है ... बेकार लेकिन बुरा। लेकिन हर कोई ऐसा करता है ^^ –

2

एकमात्र कारण मैंने WHERE 1 = 1 का उपयोग किया है गतिशील एसक्यूएल के लिए है; यह AND ... का उपयोग कर WHERE खंडों को जोड़ने के लिए एक हैक है। यह कुछ ऐसा नहीं है जिसमें मैं अपने एसक्यूएल में अन्यथा शामिल करूंगा - यह समग्र रूप से क्वेरी को प्रभावित करने के लिए कुछ भी नहीं करता है क्योंकि यह हमेशा सत्य होने का मूल्यांकन करता है और इसमें शामिल टेबल (टेबल) को हिट नहीं करता है, इसलिए कोई इंडेक्स लुकअप या टेबल स्कैन नहीं है यह।

मैं कैसे MySQL वैकल्पिक मापदंड हैंडल नहीं बोल सकता है, लेकिन मुझे पता है कि का उपयोग कर निम्न:

WHERE (@param IS NULL OR t.column = @param) 

... वैकल्पिक पैरामीटर से निपटने में विशिष्ट तरीका है। COALESCE और ISNULL आदर्श नहीं हैं क्योंकि क्वेरी अभी भी सेंटीनेल मान के आधार पर इंडेक्स (या बदतर, तालिका स्कैन) का उपयोग कर रही है। मैंने जो उदाहरण दिया है, वह तब तक तालिका को हिट नहीं करेगा जब तक कोई मान प्रदान नहीं किया जाता है।

उसने कहा, ओरेकल (9i, 10g) के साथ मेरा अनुभव दिखाता है कि यह बहुत अच्छी तरह से [WHERE (@param IS NULL OR t.column = @param)] को संभाल नहीं करता है। मैंने एसक्यूएल को गतिशील होने के द्वारा परिवर्तित करके एक बड़ा प्रदर्शन लाभ देखा, और यह निर्धारित करने के लिए CONTEXT चर का उपयोग किया कि क्या जोड़ना है। एसक्यूएल सर्वर 2005 का मेरा प्रभाव यह है कि इन्हें बेहतर तरीके से संभाला जाता है।

2

मैं आमतौर पर कुछ इस तरह किया है:

for(int i=0; i<numConditions; i++) { 
    sql += (i == 0 ? "WHERE " : "AND "); 
    sql += dbFieldNames[i] + " = " + safeVariableValues[i]; 
} 

उत्पन्न क्वेरी एक छोटे से स्वच्छ बनाता है।

2

एक वैकल्पिक मैं कभी कभी का उपयोग जहां खंड एक एक सरणी का निर्माण करने और फिर उन्हें एक साथ शामिल है:

my @wherefields; 
foreach $c (@conditionfields) { 
    push @wherefields, "$c = ?", 
} 

my $sql = "select * from table"; 
if(@wherefields) { $sql.=" WHERE " . join (" AND ", @wherefields); } 

ऊपर पर्ल में लिखा है, लेकिन सबसे अधिक भाषाओं कुछ प्रकार है की funciton में शामिल हो।

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