हाल ही में, मैं एक ऐसे एप्लिकेशन में आया जिसने डीबी प्रश्नों को उत्पन्न किया। मैं समझता हूं कि इसमें कोई नई बात नहीं है, लेकिन जब एप्लिकेशन धीमी गति से चलने लगी और मुझे मंदी के कारण का पता लगाना था, तो मैं इन प्रश्नों को पाकर चकित रह गया। यहां बताया गया है कि SQL सर्वर को कभी-कभी क्या करना पड़ता है:
SELECT COUNT(DISTINCT "pr"."id") FROM ((((((((((((((((("SomeTable" "pr" LEFT OUTER JOIN "SomeTable1698" "uf_pr_id_698" ON "uf_pr_id_698"."request" = "pr"."id") LEFT OUTER JOIN "SomeTable1700" "ufref3737_i2" ON "ufref3737_i2"."request" = "pr"."id") LEFT OUTER JOIN "SomeTable1666" "x0" ON "x0"."request" = "ufref3737_i2"."f6_callerper") LEFT OUTER JOIN "SomeTable1666" "uf_ufref4646_i3_f58__666" ON "uf_ufref4646_i3_f58__666"."request" = "ufref3737_i2"."f58_") LEFT OUTER JOIN "SomeTable1694" "x1" ON "x1"."request" = "ufref3737_i2"."f38_servicep") LEFT OUTER JOIN "SomeTable3754" "ufref3754_i12" ON "pr"."id" = "ufref3754_i12"."request") LEFT OUTER JOIN "SomeTable1698" "uf_ufref3754_i12_reference_698" ON "uf_ufref3754_i12_reference_698"."request" = "ufref3754_i12"."reference") LEFT OUTER JOIN "SomeTable1698" "x2" ON "x2"."request" = "ufref3737_i2"."f34_parentse") LEFT OUTER JOIN "SomeTable4128" "ufref3779_4128_i14" ON "ufref3737_i2"."f34_parentse" = "ufref3779_4128_i14"."request") LEFT OUTER JOIN "SomeTable1859" "x3" ON "x3"."request" = "ufref3779_4128_i14"."reference") LEFT OUTER JOIN "SomeTable3758" "ufref3758_i15" ON "pr"."id" = "ufref3758_i15"."request") LEFT OUTER JOIN "SomeTable1698" "uf_ufref3758_i15_reference_698" ON "uf_ufref3758_i15_reference_698"."request" = "ufref3758_i15"."reference") LEFT OUTER JOIN "SomeTable3758" "ufref3758_i16" ON "pr"."id" = "ufref3758_i16"."request") LEFT OUTER JOIN "SomeTable4128" "ufref3758_4128_i16" ON "ufref3758_i16"."reference" = "ufref3758_4128_i16"."request") LEFT OUTER JOIN "SomeTable1859" "x4" ON "x4"."request" = "ufref3758_4128_i16"."reference") LEFT OUTER JOIN "SomeTable4128" "ufref4128_i17" ON "pr"."id" = "ufref4128_i17"."request") LEFT OUTER JOIN "SomeTable1859" "uf_ufref4128_i17_reference_859" ON "uf_ufref4128_i17_reference_859"."request" = "ufref4128_i17"."reference") LEFT OUTER JOIN "SomeTable1666" "uf_ufref4667_i25_f69__666" ON "uf_ufref4667_i25_f69__666"."request" = "uf_pr_id_698"."f69_" WHERE ("uf_pr_id_698"."f1_applicant" IN (248,169,180,201,203,205,209,215,223,357,371,379,3502,3503,3506,3514,3517,3531,3740,3741) OR "x0"."f24_useracco" IN (578872,564618,565084,566420,566422,566936,567032,567260,567689,579571,580813,594452,611522,611523,615836,621430,628371,633044,634132,634136) OR "uf_ufref4646_i3_f58__666"."f24_useracco" IN (578872,564618,565084,566420,566422,566936,567032,567260,567689,579571,580813,594452,611522,611523,615836,621430,628371,633044,634132,634136) OR "uf_ufref4667_i25_f69__666"."f24_useracco" IN (578872,564618,565084,566420,566422,566936,567032,567260,567689,579571,580813,594452,611522,611523,615836,621430,628371,633044,634132,634136) OR ("uf_pr_id_698"."f10_status" Is Null OR "uf_pr_id_698"."f10_status" <> 111) AND "ufref3737_i2"."f96_" = 0 AND (("ufref3737_i2"."f17_source" Is Null OR "ufref3737_i2"."f17_source" <> 566425) AND ("ufref3737_i2"."f17_source" Is Null OR "ufref3737_i2"."f17_source" <> 566424) OR ("uf_pr_id_698"."f10_status" Is Null OR "uf_pr_id_698"."f10_status" <> 56) ) AND ("uf_pr_id_698"."f12_responsi" IN (578872,564618,565084,566420,566422,566936,567032,567260,567689,579571,580813,594452,611522,611523,615836,621430,628371,633044,634132,634136) OR "x1"."f19_restrict" IN (578872,564618,565084,566420,566422,566936,567032,567260,567689,579571,580813,594452,611522,611523,615836,621430,628371,633044,634132,634136) OR "uf_ufref3754_i12_reference_698"."f12_responsi" IN (578872,564618,565084,566420,566422,566936,567032,567260,567689,579571,580813,594452,611522,611523,615836,621430,628371,633044,634132,634136) OR "x2"."f12_responsi" IN (578872,564618,565084,566420,566422,566936,567032,567260,567689,579571,580813,594452,611522,611523,615836,621430,628371,633044,634132,634136) OR "x3"."f5_responsib" IN (578872,564618,565084,566420,566422,566936,567032,567260,567689,579571,580813,594452,611522,611523,615836,621430,628371,633044,634132,634136) OR "uf_ufref3758_i15_reference_698"."f12_responsi" IN (578872,564618,565084,566420,566422,566936,567032,567260,567689,579571,580813,594452,611522,611523,615836,621430,628371,633044,634132,634136) OR "x4"."f5_responsib" IN (578872,564618,565084,566420,566422,566936,567032,567260,567689,579571,580813,594452,611522,611523,615836,621430,628371,633044,634132,634136) OR "uf_ufref4128_i17_reference_859"."f5_responsib" IN (578872,564618,565084,566420,566422,566936,567032,567260,567689,579571,580813,594452,611522,611523,615836,621430,628371,633044,634132,634136)) AND ("uf_pr_id_698"."f12_responsi" Is Null OR "uf_pr_id_698"."f12_responsi" <> 579420) ) AND "pr"."area" IN (700) AND "pr"."area" IN (700) AND "pr"."deleted_by_user"=0 AND "pr"."temporary" = 0
वस्तुओं के नाम बदल दिए गए हैं।
सबसे खास बात यह थी कि एक ही टेबल को कई बार इस्तेमाल किया गया था, और कोष्ठकों की संख्या ने मुझे पागल कर दिया था। मैं अकेला नहीं था जिसे यह कोड पसंद नहीं आया, SQL सर्वर ने भी इसकी सराहना नहीं की और इसके लिए एक योजना बनाने के लिए बहुत अधिक संसाधन खर्च किए। क्वेरी 50-150 ms तक चल सकती है, और योजना निर्माण में 2.5 ms तक का समय लग सकता है। आज, मैं इस मुद्दे को ठीक करने के तरीकों पर विचार नहीं करूंगा, लेकिन मैं एक बात बताऊंगा - मेरे मामले में, आवेदन में क्वेरी पीढ़ी को ठीक करना असंभव था।
इसके बजाय, मैं उन कारणों का विश्लेषण करना चाहूंगा कि SQL सर्वर इतने लंबे समय के लिए क्वेरी प्लान क्यों बनाता है। SQL सेवर सहित किसी भी DBMS में, मुख्य अनुकूलन समस्या तालिकाओं को एक दूसरे के साथ जोड़ने की विधि है। जॉइन मेथड के अलावा, टेबल जॉइन का क्रम बहुत महत्वपूर्ण है।
आइए टेबल जॉइन के क्रम के बारे में विस्तार से बात करते हैं। यह समझना बहुत महत्वपूर्ण है कि टेबल जॉइन की संभावित संख्या तेजी से बढ़ती है, रैखिक रूप से नहीं। फॉक्स उदाहरण, 2 तालिकाओं में शामिल होने के लिए केवल 2 संभावित विधियां हैं, और संख्या 3 तालिकाओं के लिए 12 विधियों तक पहुंच सकती है। अलग-अलग जुड़ने वाले अनुक्रमों में अलग-अलग क्वेरी लागत हो सकती है, और SQL सर्वर अनुकूलक को सबसे इष्टतम विधि का चयन करना होगा। लेकिन जब तालिकाओं की संख्या अधिक होती है, तो यह एक संसाधन-गहन कार्य बन जाता है। यदि SQL सर्वर सभी संभावित रूपों पर जाना शुरू कर देता है, तो ऐसी क्वेरी को कभी भी निष्पादित नहीं किया जा सकता है। इसीलिए, SQL सर्वर कभी भी ऐसा नहीं करता है और हमेशा एक अच्छी योजना की तलाश करता है, न कि सबसे अच्छी योजना की। SQL सर्वर हमेशा निष्पादन समय और योजना गुणवत्ता के बीच समझौता करने का प्रयास करता है।
यहां शामिल होने के तरीकों की घातीय वृद्धि का एक उदाहरण है। SQL सर्वर विभिन्न जुड़ने के तरीकों (बाएं-गहरे, दाएं-गहरे, झाड़ीदार पेड़) का चयन कर सकता है। देखने में यह इस तरह दिखता है:
नीचे दी गई तालिका में तालिकाओं की संख्या बढ़ने पर शामिल होने के संभावित तरीकों को दिखाया गया है:
आप इन मूल्यों को स्वयं प्राप्त कर सकते हैं:
बाएं-गहरे: . के लिए 5! =5 x 4 x 3 x 2 x 1 =120
झाड़ीदार पेड़ के लिए: (2n–2)!/(n–1)!
निष्कर्ष :जॉइन की संख्या पर विशेष ध्यान दें और अनुकूलक के रास्ते में न आएं। यदि आप एकाधिक जॉइन वाली क्वेरी में वांछित परिणाम प्राप्त करने में विफल रहते हैं, तो इसे कई छोटे प्रश्नों में तोड़ दें और आप परिणाम से आश्चर्यचकित होंगे।
पी.एस. बेशक, हमें यह समझना चाहिए कि टेबल जॉइन के अनुक्रम को परिभाषित करने के अलावा, क्वेरी ऑप्टिमाइज़र को जॉइन टाइप, डेटा एक्सेस मेथड (स्कैन, सीक) आदि का भी चयन करना चाहिए।
उपयोगी उत्पाद:
SQL पूर्ण - अपने कोड को आसानी से लिखें, सुशोभित करें, पुन:सक्रिय करें और अपनी उत्पादकता बढ़ाएं।