SQL प्रश्नों का परीक्षण करने का सबसे अच्छा तरीका [बंद]


109

मैंने एक समस्या में भाग लिया है जिसमें हम जटिल SQL प्रश्नों को त्रुटियों के साथ बाहर रखते हैं। अनिवार्य रूप से यह गलत ग्राहकों को मेल भेजने और इस तरह अन्य 'समस्याओं' के परिणामस्वरूप होता है।

SQL प्रश्न बनाने के साथ सभी का अनुभव कैसा है? हम हर दूसरे सप्ताह में डेटा के नए समूह बना रहे हैं।

इसलिए यहाँ मेरे कुछ विचार और उनकी सीमाएँ हैं:

  • परीक्षण डेटा बनाते समय यह साबित होगा कि हमारे पास सभी सही आंकड़े हैं जो उत्पादन में विसंगतियों के बहिष्कार को लागू नहीं करता है। वह डेटा है जिसे आज गलत माना जाएगा लेकिन 10 साल पहले सही हो सकता है; इसे प्रलेखित नहीं किया गया था और इसलिए डेटा निकाले जाने के बाद ही हम इसके बारे में जानते हैं।

  • वेन आरेख और डेटा मानचित्र बनाएं यह क्वेरी के डिज़ाइन का परीक्षण करने का एक ठोस तरीका प्रतीत होता है, हालांकि यह गारंटी नहीं देता है कि कार्यान्वयन सही है। यह डेवलपर्स को आगे की योजना बनाने और सोचने के रूप में मिलता है कि वे क्या लिख ​​रहे हैं।

किसी भी इनपुट के लिए धन्यवाद जो आप मेरी समस्या को दे सकते हैं।

जवाबों:


164

आप फ़ंक्शंस 200 लाइनों के साथ एक आवेदन नहीं लिखेंगे। आप उन लंबे कार्यों को छोटे कार्यों में शामिल करेंगे, जिनमें से प्रत्येक एक स्पष्ट रूप से परिभाषित जिम्मेदारी के साथ होगा।

अपने SQL को ऐसा क्यों लिखें?

जैसे आप अपने कार्यों को विघटित करते हैं , वैसे ही अपने प्रश्नों का निस्तारण करें । यह उन्हें छोटा, सरल, समझने में आसान , परीक्षण करने में आसान, रिफलेक्टर करने में आसान बनाता है। और यह आपको उनके बीच "शिम", और उनके चारों ओर "रैपर" जोड़ने की अनुमति देता है, जैसे आप प्रक्रियात्मक कोड में करते हैं।

आप यह कैसे करते हैं? प्रत्येक महत्वपूर्ण चीज़ को बनाने से एक दृश्य में एक क्वेरी करता है। फिर आप इन सरल विचारों से अधिक जटिल प्रश्नों की रचना करते हैं, जैसे आप अधिक आदिम कार्यों से अधिक जटिल कार्यों की रचना करते हैं।

और बड़ी बात यह है कि विचारों की अधिकांश रचनाओं के लिए , आपको अपने RDBMS से बिल्कुल समान प्रदर्शन मिलेगा। (कुछ के लिए आप ऐसा नहीं करेंगे। तो क्या? समय से पहले अनुकूलन सभी बुराई की जड़ है। सही ढंग से कोड पहले, फिर आप की जरूरत है तो अनुकूलन।)

यहां एक जटिल क्वेरी को विघटित करने के लिए कई दृश्य का उपयोग करने का एक उदाहरण है।

उदाहरण में, क्योंकि प्रत्येक दृश्य केवल एक परिवर्तन जोड़ता है, प्रत्येक को त्रुटियों को खोजने के लिए स्वतंत्र रूप से परीक्षण किया जा सकता है, और परीक्षण सरल हैं।

यहाँ उदाहरण में आधार तालिका है:

create table month_value( 
    eid int not null, month int, year int,  value int );

यह तालिका त्रुटिपूर्ण है, क्योंकि यह दो कॉलम, महीने और साल का उपयोग करती है, एक डेटम, एक निरपेक्ष महीने का प्रतिनिधित्व करने के लिए। यहां नए, गणना किए गए कॉलम के लिए हमारे विनिर्देशन हैं:

हम इसे एक रैखिक परिवर्तन के रूप में करेंगे, जैसे कि यह (वर्ष, महीना) के समान होता है, और ऐसा किसी भी (वर्ष, महीने) के लिए एक और केवल मूल्य होता है, और सभी मान लगातार होते हैं:

create view cm_absolute_month as 
select *, year * 12 + month as absolute_month from month_value;

अब हमें जो परीक्षण करना है, वह हमारी कल्पना में निहित है, अर्थात् किसी भी प्रकार (वर्ष, माह) के लिए, एक और केवल एक (पूर्ण_मौत) है, और वह (निरपेक्ष_मूर्ति) लगातार हैं। आइए कुछ परीक्षण लिखें।

हमारी परीक्षा एक SQL selectक्वेरी होगी, जिसमें निम्न संरचना होगी: एक परीक्षण नाम और एक केस स्टेटमेंट एक साथ दिया गया है। परीक्षण का नाम सिर्फ एक मनमाना स्ट्रिंग है। केस स्टेटमेंट सिर्फ case whenटेस्ट स्टेटमेंट है then 'passed' else 'failed' end

परीक्षण कथन सिर्फ एसक्यूएल चयन (उपश्रेणियाँ) होंगे जो परीक्षण पास करने के लिए सही होने चाहिए।

यहाँ हमारा पहला परीक्षण है:

--a select statement that catenates the test name and the case statement
select concat( 
-- the test name
'For every (year, month) there is one and only one (absolute_month): ', 
-- the case statement
   case when 
-- one or more subqueries
-- in this case, an expected value and an actual value 
-- that must be equal for the test to pass
  ( select count(distinct year, month) from month_value) 
  --expected value,
  = ( select count(distinct absolute_month) from cm_absolute_month)  
  -- actual value
  -- the then and else branches of the case statement
  then 'passed' else 'failed' end
  -- close the concat function and terminate the query 
  ); 
  -- test result.

उस क्वेरी को चलाने से यह परिणाम प्राप्त होता है: For every (year, month) there is one and only one (absolute_month): passed

जब तक month_value में पर्याप्त परीक्षण डेटा है, तब तक यह परीक्षण काम करता है।

हम पर्याप्त परीक्षण डेटा के लिए एक परीक्षण भी जोड़ सकते हैं:

select concat( 'Sufficient and sufficiently varied month_value test data: ',
   case when 
      ( select count(distinct year, month) from month_value) > 10
  and ( select count(distinct year) from month_value) > 3
  and ... more tests 
  then 'passed' else 'failed' end );

अब हम इसे लगातार परीक्षण करते हैं:

select concat( '(absolute_month)s are consecutive: ',
case when ( select count(*) from cm_absolute_month a join cm_absolute_month b 
on (     (a.month + 1 = b.month and a.year = b.year) 
      or (a.month = 12 and b.month = 1 and a.year + 1 = b.year) )  
where a.absolute_month + 1 <> b.absolute_month ) = 0 
then 'passed' else 'failed' end );

अब हम अपने परीक्षण, जो कि केवल एक फ़ाइल में हैं, और डेटाबेस के विरुद्ध उस स्क्रिप्ट को चलाते हैं। दरअसल, अगर हम अपने दृश्य परिभाषाओं को किसी स्क्रिप्ट (या स्क्रिप्ट्स में संग्रहीत करते हैं, तो मैं संबंधित फाइल के लिए एक फाइल की सिफारिश करता हूं) को डेटाबेस के विरुद्ध चलाया जा सकता है, हम प्रत्येक दृश्य के लिए एक ही स्क्रिप्ट में अपने परीक्षण जोड़ सकते हैं , ताकि (फिर से) -) हमारे विचार को बनाने से दृश्य के परीक्षण भी चलते हैं। इस तरह, जब हम दोबारा निर्माण करते हैं, तो हम दोनों प्रतिगमन परीक्षण प्राप्त करते हैं, और जब निर्माण के खिलाफ दृश्य निर्माण चलता है, तो दृश्य का उत्पादन में भी परीक्षण किया जाएगा।


27
यह पहली बार है जब मैं sql में साफ कोड और यूनिट परीक्षण देख रहा हूं, मैं दिन के लिए खुश हूं :)
मैक्सिम ARNSTAMM

1
भयानक एसक्यूएल हैक
CodeFarmer

13
यह बहुत अच्छा है, लेकिन कॉलम के लिए एक अक्षर के नाम और मुश्किल से देखने योग्य नामों का उपयोग क्यों करें? SQL को पाइथन की तुलना में कम स्व-दस्तावेजीकरण या पठनीय क्यों होना चाहिए?
snl

1
कुछ उपयोगी के लिए बहुत बढ़िया स्पष्टीकरण जो मैंने एसक्यूएल / डीबी दुनिया में कभी नहीं देखा था। साथ ही जिस तरह से आपने यहाँ डेटाबेस का परीक्षण किया है वह भी मुझे पसंद है।
जैक्स्टीन

एक चेतावनी के रूप में, मैंने sql विचारों को देखा है जो sql दृश्यों में शामिल होते हैं, PostgreSQL पर बहुत खराब प्रदर्शन करते हैं। मैंने इस तकनीक का प्रभावी रूप से M $ SQL के साथ उपयोग किया है।
बेन लियायनज

6

एक परीक्षण प्रणाली डेटाबेस बनाएं जिसे आप जितनी बार चाहें उतनी बार पुनः लोड कर सकते हैं। अपना डेटा लोड करें या अपना डेटा बनाएं और इसे सहेजें। इसे पुनः लोड करने का एक आसान तरीका तैयार करें। अपनी विकास प्रणाली को उस डेटाबेस में संलग्न करें और उत्पादन में जाने से पहले अपने कोड को मान्य करें। अपने आप को हर बार किक करें जब आप किसी मुद्दे को उत्पादन में आने दें। ज्ञात समस्याओं को सत्यापित करने और समय के साथ अपने परीक्षण सूट को बढ़ाने के लिए परीक्षणों का एक सूट बनाएँ।


4

आप DbUnit की जांच करना चाहते हैं , तो आप डेटा के एक निश्चित सेट के साथ अपने कार्यक्रमों के लिए इकाई परीक्षण लिखने की कोशिश कर सकते हैं। इस तरह से आपको कम या ज्यादा पूर्वानुमानित परिणामों के साथ प्रश्नों को लिखने में सक्षम होना चाहिए।

दूसरी चीज़ जो आप करना चाहते हैं, वह है आपका SQL Server निष्पादन स्टैक प्रोफ़ाइल करना और यह पता लगाना कि क्या सभी प्रश्न वास्तव में सही हैं, उदाहरण के लिए, यदि आप केवल एक क्वेरी का उपयोग कर रहे हैं, जो सही और गलत दोनों परिणाम लौटाती है, तो स्पष्ट रूप से क्वेरी होना प्रश्न में इस्तेमाल किया गया है, लेकिन क्या होगा यदि आपका आवेदन कोड में विभिन्न बिंदुओं पर अलग-अलग प्रश्न भेज रहा है?

आपकी क्वेरी को ठीक करने का कोई भी प्रयास निरर्थक होगा ... दुष्ट प्रश्न अभी भी गलत परिणामों को दूर करने वाले हो सकते हैं।


2

पुन: tpdi

case when ( select count(*) from cm_abs_month a join cm_abs_month b  
on (( a.m + 1 = b.m and a.y = b.y) or (a.m = 12 and b.m = 1 and a.y + 1 = b.y) )   
where a.am + 1 <> b.am ) = 0  

ध्यान दें कि यह केवल यह जांचता है कि लगातार महीनों के लिए मान स्थिर हैं, न कि लगातार डेटा मौजूद है (जो कि संभवत: शुरू में आपका इरादा था)। यह हमेशा पास होगा यदि आपका कोई भी स्रोत डेटा स्थिर नहीं है (जैसे कि आपके पास केवल-गिने महीने भी हैं), भले ही आपकी गणना पूरी तरह से बंद हो।

मैं भी कुछ याद कर रहा हूँ, या उस दूसरे खंड के गलत महीने मूल्य को टक्कर देता है? (यानी कि 12/2011 1/2010 के बाद आता है)

क्या बुरा है, अगर मुझे सही तरीके से याद है, तो SQL सर्वर कम से कम आपको 10 से कम स्तरों की अनुमति देता है, इससे पहले कि ऑप्टिमाइज़र अपने आभासी हाथों को हवा में फेंके और हर अनुरोध पर पूर्ण टेबल स्कैन करना शुरू कर दे, इसलिए इस दृष्टिकोण को अधिक न करें।

अपने परीक्षण के मामलों से बाहर निकलने का परीक्षण करना याद रखें!

अन्यथा इनपुट के अधिकांश या सभी संभावित रूपों को शामिल करने के लिए डेटा का एक बहुत विस्तृत सेट बनाना, उस डेटा के खिलाफ अपेक्षित परिणामों के लिए जाँच को स्वचालित करने के लिए SqlUnit या DbUnit या किसी अन्य * यूनिट का उपयोग करना, और समीक्षा करना, बनाए रखना और अद्यतन करना जितना आम तौर पर आवश्यक लगता है। जाने का रास्ता।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.