Database
 sql >> डेटाबेस >  >> RDS >> Database

एसक्यूएल को पूरा करना। सफलता और असफलता की कहानियां

मैं एक ऐसी कंपनी के लिए काम कर रहा हूं जो पांच साल से अधिक समय से डेटाबेस इंटरैक्शन के लिए आईडीई विकसित करती है। इस लेख को लिखना शुरू करने से पहले, मुझे नहीं पता था कि आगे कितनी काल्पनिक कहानियाँ होंगी।

मेरी टीम आईडीई भाषा सुविधाओं का विकास और समर्थन करती है, और कोड स्वतः पूर्णता प्रमुख है। मैंने कई रोमांचक चीजों का सामना किया। कुछ चीजें हमने पहले प्रयास से बहुत अच्छी कीं, और कुछ अन्य कई शॉट्स के बाद भी असफल रहीं।

SQL और बोलियों को पार्स करना

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

वे कितनी दूर आगे देख सकते हैं, इसके आधार पर एक पार्सर वर्गीकरण होता है:LA(1), LA(2), या LA(*), जिसका अर्थ है कि एक पार्सर सही कांटे को परिभाषित करने के लिए जितना आवश्यक हो उतना आगे देख सकता है।

कभी-कभी, एक वैकल्पिक खंड का अंत दूसरे वैकल्पिक खंड की शुरुआत से मेल खाता है। ये स्थितियां पार्सिंग को चलाने के लिए बहुत कठिन बनाती हैं। टी-एसक्यूएल चीजों को आसान नहीं बनाता है। साथ ही, कुछ SQL कथनों में ऐसे अंत हो सकते हैं, लेकिन जरूरी नहीं कि वे पिछले कथनों की शुरुआत के साथ विरोध कर सकते हैं।

क्या आपको विश्वास नहीं होता? व्याकरण के माध्यम से औपचारिक भाषाओं का वर्णन करने का एक तरीका है। आप इस या उस टूल का उपयोग करके इसमें से एक पार्सर उत्पन्न कर सकते हैं। व्याकरण का वर्णन करने वाले सबसे उल्लेखनीय उपकरण और भाषाएं वाईएसीसी और एएनटीएलआर हैं।

वाईएसीसी -जेनरेटेड पार्सर्स का उपयोग MySQL, MariaDB और PostgreSQL इंजन में किया जाता है। हम कोशिश कर सकते हैं और उन्हें सीधे स्रोत कोड से ले सकते हैं और कोड पूर्णता develop विकसित कर सकते हैं और इन पार्सर्स का उपयोग करके SQL विश्लेषण पर आधारित अन्य कार्य। इसके अलावा, इस उत्पाद को मुफ्त विकास अपडेट प्राप्त होंगे, और पार्सर उसी तरह व्यवहार करेगा जैसे स्रोत इंजन करता है।

तो हम अभी भी ANTLR का उपयोग क्यों कर रहे हैं? ? यह दृढ़ता से C#/.NET का समर्थन करता है, इसमें एक अच्छा टूलकिट है, इसका सिंटैक्स पढ़ने और लिखने में बहुत आसान है। एएनटीएलआर सिंटैक्स इतना आसान हो गया है कि माइक्रोसॉफ्ट अब इसे अपने आधिकारिक सी # दस्तावेज़ीकरण में उपयोग करता है।

लेकिन जब पार्सिंग की बात आती है तो SQL जटिलता पर वापस जाते हैं। मैं सार्वजनिक रूप से उपलब्ध भाषाओं के व्याकरण के आकार की तुलना करना चाहूंगा। डीबीफोर्ज में, हम अपने व्याकरण के टुकड़ों का उपयोग करते हैं। वे दूसरों की तुलना में अधिक पूर्ण हैं। दुर्भाग्य से, वे विभिन्न कार्यों का समर्थन करने के लिए C# कोड के इन्सर्ट के साथ अतिभारित हैं।

विभिन्न भाषाओं के व्याकरण के आकार इस प्रकार हैं:

JS - 475 पार्सर पंक्तियाँ + 273 लेक्सर्स =748 पंक्तियाँ

जावा - 615 पार्सर पंक्तियाँ + 211 लेक्सर्स =826 पंक्तियाँ

सी# - 1159 पार्सर पंक्तियाँ + 433 लेक्सर्स =1592 पंक्तियाँ

С++ – 1933 पंक्तियाँ

MySQL – 2515 पार्सर पंक्तियाँ + 1189 लेक्सर्स =3704 पंक्तियाँ

टी-एसक्यूएल - 4035 पार्सर पंक्तियाँ + 896 लेक्सर्स =4931 पंक्तियाँ

PL SQL - 6719 पार्सर पंक्तियाँ + 2366 लेक्सर्स =9085 पंक्तियाँ

कुछ लेक्सर्स के अंत में भाषा में उपलब्ध यूनिकोड वर्णों की सूची होती है। भाषा की जटिलता के मूल्यांकन के संबंध में वे सूचियाँ बेकार हैं। इस प्रकार, मेरे द्वारा ली गई पंक्तियों की संख्या हमेशा इन सूचियों से पहले समाप्त होती है।

भाषा व्याकरण में पंक्तियों की संख्या के आधार पर भाषा विश्लेषण की जटिलता का मूल्यांकन बहस का विषय है। फिर भी, मेरा मानना ​​है कि बड़ी विसंगति दिखाने वाली संख्याओं को दिखाना महत्वपूर्ण है।

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

युद्धों की भविष्यवाणी करें

कोड पार्सिंग के दौरान, शब्द कभी-कभी आपको यह नहीं बताता कि दो विकल्पों में से किसे चुनना है। इस प्रकार की अशुद्धियों को हल करने वाला तंत्र है आगे की ओर देखना एएनटीएलआर में। पार्सर विधि if's . की सम्मिलित श्रृंखला है , और उनमें से प्रत्येक एक कदम आगे दिखता है। इस प्रकार की अनिश्चितता उत्पन्न करने वाले व्याकरण का उदाहरण देखें:

rule1:
  'a' rule2 | rule3
;

rule2:
  'b' 'c' 'd'
;

rule3:
  'b' 'c' 'e'
;

नियम 1 के मध्य में, जब टोकन 'ए' पहले ही पास हो चुका होता है, तो पार्सर नियम का पालन करने के लिए दो कदम आगे की ओर देखेगा। यह जाँच एक बार फिर की जाएगी, लेकिन आगे की ओर को बाहर करने के लिए इस व्याकरण को फिर से लिखा जा सकता है . नकारात्मक पक्ष यह है कि इस तरह के अनुकूलन संरचना को नुकसान पहुंचाते हैं, जबकि प्रदर्शन में वृद्धि अपेक्षाकृत कम होती है।

इस तरह की अनिश्चितता को हल करने के लिए और अधिक जटिल तरीके हैं। उदाहरण के लिए, सिंटैक्स विधेय (SynPred) ANTLR3 . में तंत्र . यह तब मदद करता है जब किसी खंड का वैकल्पिक अंत अगले वैकल्पिक खंड की शुरुआत को पार कर जाता है।

ANTLR3 के संदर्भ में, एक विधेय एक उत्पन्न विधि है जो विकल्पों में से एक के अनुसार एक आभासी पाठ प्रविष्टि करता है . सफल होने पर, यह सत्य . लौटाता है मूल्य, और विधेय पूर्णता सफल है। जब यह एक आभासी प्रविष्टि होती है, तो इसे बैकट्रैकिंग . कहा जाता है मोड प्रविष्टि। यदि कोई विधेय सफलतापूर्वक काम करता है, तो वास्तविक प्रविष्टि होती है।

यह केवल एक समस्या है जब एक विधेय दूसरे विधेय के अंदर शुरू होता है। तब एक दूरी सैकड़ों या हजारों बार पार हो सकती है।

आइए एक सरलीकृत उदाहरण की समीक्षा करें। अनिश्चितता के तीन बिंदु हैं:(ए, बी, सी)।

  1. पार्सर ए में प्रवेश करता है, पाठ में अपनी स्थिति याद रखता है, एक स्तर -1 आभासी प्रविष्टि शुरू करता है।
  2. पार्सर बी में प्रवेश करता है, पाठ में अपनी स्थिति याद रखता है, एक स्तर -2 आभासी प्रविष्टि शुरू करता है।
  3. पार्सर सी में प्रवेश करता है, पाठ में अपनी स्थिति याद रखता है, एक स्तर -3 आभासी प्रविष्टि शुरू करता है।
  4. पार्सर लेवल-3 की वर्चुअल एंट्री पूरी करता है, लेवल-2 पर वापस आता है, और C को एक बार फिर पास करता है।
  5. पार्सर लेवल-2 की वर्चुअल एंट्री पूरी करता है, लेवल-1 पर लौटता है और एक बार फिर बी और सी पास करता है।
  6. पार्सर एक आभासी प्रविष्टि को पूरा करता है, लौटाता है, और ए, बी, और सी के माध्यम से एक वास्तविक प्रविष्टि करता है।

नतीजतन, सी के भीतर सभी चेक 4 बार, बी के भीतर - 3 बार, ए - 2 बार के भीतर किए जाएंगे।

लेकिन क्या होगा यदि कोई उपयुक्त विकल्प सूची में दूसरे या तीसरे स्थान पर हो? तब विधेय चरणों में से एक विफल हो जाएगा। पाठ में इसकी स्थिति वापस लुढ़क जाएगी, और दूसरा विधेय चलना शुरू हो जाएगा।

ऐप के फ़्रीज़ होने के कारणों का विश्लेषण करते समय, हम अक्सर SynPred . के ट्रेस पर ठोकर खाते हैं कई हजार बार निष्पादित। सिनप्रेड s पुनरावर्ती नियमों में विशेष रूप से समस्याग्रस्त हैं। अफसोस की बात है कि SQL अपनी प्रकृति से पुनरावर्ती है। लगभग हर जगह उपश्रेणियों का उपयोग करने की क्षमता की कीमत होती है। हालांकि, विधेय को दूर करने के लिए नियम में हेरफेर करना संभव है।

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

हमने एक आसान रेगुलर एक्सप्रेशन बनाया है विशेष MSBuild कार्य . द्वारा चलाए जा रहे विधेय की संख्या को नियंत्रित करने के लिए उपकरण . यदि विधेय की संख्या फ़ाइल में निर्दिष्ट संख्या से मेल नहीं खाती है, तो कार्य तुरंत निर्माण में विफल हो गया और एक त्रुटि के बारे में चेतावनी दी।

त्रुटि देखते समय, एक डेवलपर को निरर्थक विधेय को हटाने के लिए नियम के कोड को कई बार फिर से लिखना चाहिए। यदि कोई विधेय से बच नहीं सकता है, तो डेवलपर उसे एक विशेष फ़ाइल में जोड़ देगा जो समीक्षा के लिए अतिरिक्त ध्यान खींचती है।

दुर्लभ मौकों पर, हमने एएनटीएलआर-जेनरेट किए गए लोगों से बचने के लिए सी # का उपयोग करके अपनी भविष्यवाणी भी लिखी है। सौभाग्य से, यह विधि भी मौजूद है।

व्याकरण विरासत

जब हमारे समर्थित डीबीएमएस में कोई परिवर्तन होता है, तो हमें उन्हें अपने टूल में पूरा करना होता है। व्याकरणिक वाक्यविन्यास निर्माण के लिए समर्थन हमेशा एक प्रारंभिक बिंदु होता है।

हम प्रत्येक SQL बोली के लिए एक विशेष व्याकरण बनाते हैं। यह कुछ कोड दोहराव को सक्षम बनाता है, लेकिन उनमें क्या समानता है यह खोजने की कोशिश करने से कहीं अधिक आसान है।

हम अपना खुद का एएनटीएलआर व्याकरण प्रीप्रोसेसर लिखने के लिए गए जो व्याकरण विरासत करता है।

यह भी स्पष्ट हो गया कि हमें बहुरूपता के लिए एक तंत्र की आवश्यकता है - न केवल वंश में नियम को फिर से परिभाषित करने की क्षमता बल्कि मूल को भी बुलाने की क्षमता। आधार नियम को कॉल करते समय हम स्थिति को नियंत्रित करना भी चाहेंगे।

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

हमने एक एमएसबिल्ड टास्क लिखा था जिसे प्री-बिल्ड-एक्शन के रूप में पूरे-बिल्ड सिस्टम में एम्बेड किया गया था। कार्य इसके आधार और विरासत में मिले साथियों से परिणामी व्याकरण उत्पन्न करके एएनटीएलआर व्याकरण के लिए प्रीप्रोसेसर का काम करना था। परिणामी व्याकरण ANTLR द्वारा ही संसाधित किया गया था।

ANTLR पोस्टप्रोसेसिंग

कई प्रोग्रामिंग भाषाओं में, कीवर्ड का उपयोग विषय नामों के रूप में नहीं किया जा सकता है। SQL में बोली के आधार पर 800 से 3000 कीवर्ड हो सकते हैं। उनमें से ज्यादातर डेटाबेस के अंदर के संदर्भ से बंधे हैं। इस प्रकार, उन्हें ऑब्जेक्ट नाम के रूप में मना करना उपयोगकर्ताओं को निराश करेगा। इसलिए SQL में आरक्षित और अनारक्षित कीवर्ड हैं।

आप अपनी वस्तु को बिना उद्धृत किए आरक्षित शब्द (चयन, से, आदि) के रूप में नाम नहीं दे सकते हैं, लेकिन आप इसे एक अनारक्षित शब्द (वार्तालाप, उपलब्धता, आदि) के लिए कर सकते हैं। यह इंटरैक्शन पार्सर के विकास को कठिन बना देता है।

शाब्दिक विश्लेषण के दौरान, संदर्भ अज्ञात है, लेकिन एक पार्सर को पहले से ही पहचानकर्ता और कीवर्ड के लिए अलग-अलग संख्याओं की आवश्यकता होती है। इसलिए हमने एएनटीएलआर पार्सर में एक और पोस्टप्रोसेसिंग जोड़ा। इसने सभी स्पष्ट पहचानकर्ता जांचों को एक विशेष विधि को कॉल करने के साथ बदल दिया।

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

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

पेड़ों के बिना वाक्य रचना विश्लेषण में त्रुटियां

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

  1. संपादक में पाठ को पार्स करें। तब आपको एक सिंटैक्स ट्री मिलता है।
  2. गाड़ी के नीचे एक नोड ढूंढें और उसे व्याकरण से मिलाएँ।
  3. पता लगाएं कि प्वाइंट पर कौन से कीवर्ड और ऑब्जेक्ट प्रकार उपलब्ध होंगे।

इस मामले में, व्याकरण को ग्राफ या स्टेट मशीन के रूप में कल्पना करना आसान है।

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

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

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

ANTLR3 हमारे माप के अनुसार ANTLR4 की तुलना में 6 गुना तेजी से काम करता है। साथ ही, बड़ी स्क्रिप्ट के लिए सिंटैक्स ट्री बहुत अधिक RAM ले सकता है, जो अच्छी खबर नहीं थी, इसलिए हमें विजुअल स्टूडियो और SQL मैनेजमेंट स्टूडियो के 32-बिट एड्रेस स्पेस के भीतर काम करने की आवश्यकता थी।

ANTLR पार्सर पोस्ट-प्रोसेसिंग

स्ट्रिंग्स के साथ काम करते समय, सबसे महत्वपूर्ण क्षणों में से एक है शाब्दिक विश्लेषण का चरण जहां हम स्क्रिप्ट को अलग-अलग शब्दों में विभाजित करते हैं।

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

यह पता चला कि पार्सर फ़ाइल का विश्लेषण करते समय आउटऑफमेमरी अपवाद के कारण यह विफल हो गया। इस फ़ाइल में कोड की 200,000 से अधिक पंक्तियाँ हैं।

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

स्पैन एपीआई से पहले सबस्ट्रिंग के बिना शाब्दिक विश्लेषण

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

फ़ाइल खोलने के दौरान बैकग्राउंड लेक्सिंग

सिंटैक्स हाइलाइटिंग शाब्दिक विश्लेषण पर आधारित है। इस ऑपरेशन में आमतौर पर डिस्क से टेक्स्ट पढ़ने की तुलना में बहुत अधिक समय लगता है। क्या चालबाजी है? एक थ्रेड में, टेक्स्ट को फ़ाइल से पढ़ा जा रहा है, जबकि लेक्सिकल विश्लेषण एक अलग थ्रेड में किया जाता है।

लेक्सर पाठ को पंक्ति-दर-पंक्ति पढ़ता है। यदि यह एक ऐसी पंक्ति का अनुरोध करता है जो मौजूद नहीं है, तो यह रुक जाएगी और प्रतीक्षा करेगी।

BCL से BlockingCollection समान आधार पर काम करता है, और एल्गोरिथ्म में समवर्ती निर्माता-उपभोक्ता पैटर्न का एक विशिष्ट अनुप्रयोग शामिल है। मुख्य थ्रेड में काम करने वाला संपादक पहली हाइलाइट की गई लाइन के बारे में डेटा का अनुरोध करता है, और यदि यह अनुपलब्ध है, तो यह रुक जाएगा और प्रतीक्षा करेगा। हमारे संपादक में हमने दो बार निर्माता-उपभोक्ता पैटर्न और ब्लॉकिंग-संग्रह का उपयोग किया है:

  1. फ़ाइल से पढ़ना एक निर्माता है, जबकि लेक्सर एक उपभोक्ता है।
  2. लेक्सर पहले से ही एक निर्माता है, और टेक्स्ट एडिटर एक उपभोक्ता है।

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

अस्पष्ट अनुकूलन:आंशिक शाब्दिक विश्लेषण

वाक्यात्मक विश्लेषण आमतौर पर दो स्तरों में विभाजित होता है:

  • इनपुट कैरेक्टर स्ट्रीम को भाषा के नियमों के आधार पर लेक्सेम (टोकन) प्राप्त करने के लिए संसाधित किया जाता है - इसे लेक्सिकल विश्लेषण कहा जाता है
  • पार्सर औपचारिक व्याकरण के नियमों के अनुसार टोकन स्ट्रीम की जांच करता है और अक्सर एक सिंटैक्स ट्री बनाता है।

स्ट्रिंग प्रोसेसिंग एक महंगा ऑपरेशन है। इसे अनुकूलित करने के लिए, हमने हर बार पाठ का पूर्ण शाब्दिक विश्लेषण नहीं करने का निर्णय लिया, लेकिन केवल उस हिस्से का पुनर्विश्लेषण किया जो बदल गया था। लेकिन ब्लॉक कमेंट्स या लाइन्स जैसे मल्टीलाइन कंस्ट्रक्शन से कैसे निपटें? हमने प्रत्येक पंक्ति के लिए एक लाइन-एंड स्थिति संग्रहीत की:"कोई मल्टीलाइन टोकन नहीं" =0, "एक ब्लॉक टिप्पणी की शुरुआत" =1, "एक मल्टीलाइन स्ट्रिंग शाब्दिक की शुरुआत" =2। शाब्दिक विश्लेषण परिवर्तित अनुभाग से शुरू होता है और तब समाप्त होता है जब लाइन-एंड स्थिति संग्रहीत एक के बराबर होती है।

इस समाधान के साथ एक समस्या थी:ऐसी संरचनाओं में लाइन नंबरों की निगरानी करना बेहद असुविधाजनक है, जबकि लाइन नंबर एएनटीएलआर टोकन की एक आवश्यक विशेषता है क्योंकि जब कोई लाइन डाली या हटाई जाती है, तो अगली पंक्ति की संख्या तदनुसार अपडेट की जानी चाहिए। पार्सर को टोकन सौंपने से पहले, हमने तुरंत एक लाइन नंबर सेट करके इसे हल किया। बाद में हमने जो परीक्षण किए, उनसे पता चला कि प्रदर्शन में 15-25% सुधार हुआ है। वास्तविक सुधार और भी अधिक था।

इस सब के लिए आवश्यक RAM की मात्रा हमारी अपेक्षा से बहुत अधिक निकली। एक ANTLR टोकन में शामिल हैं:एक प्रारंभिक बिंदु - 8 बाइट्स, एक समापन बिंदु - 8 बाइट्स, शब्द के पाठ का एक लिंक - 4 या 8 बाइट्स (स्वयं स्ट्रिंग का उल्लेख नहीं), दस्तावेज़ के पाठ का एक लिंक - 4 या 8 बाइट्स, और एक टोकन प्रकार - 4 बाइट्स।

तो हम किस नतीजे पर पहुंचे? हमने प्रदर्शन पर ध्यान केंद्रित किया और ऐसी जगह रैम की अत्यधिक खपत प्राप्त की जिसकी हमें उम्मीद नहीं थी। हमने नहीं सोचा था कि ऐसा होगा क्योंकि हमने कक्षाओं के बजाय हल्के ढांचे का उपयोग करने की कोशिश की। उन्हें भारी वस्तुओं से बदलकर, हम बेहतर प्रदर्शन प्राप्त करने के लिए जानबूझकर अतिरिक्त मेमोरी खर्च के लिए गए। सौभाग्य से, इसने हमें एक महत्वपूर्ण सबक सिखाया, इसलिए अब प्रत्येक प्रदर्शन अनुकूलन प्रोफाइलिंग मेमोरी खपत के साथ समाप्त होता है और इसके विपरीत।

यह एक नैतिक के साथ एक कहानी है। कुछ सुविधाओं ने लगभग तुरंत काम करना शुरू कर दिया और अन्य ने बस थोड़ी जल्दी काम करना शुरू कर दिया। आखिरकार, अगर कोई ऐसी वस्तु नहीं होती जहां कोई एक थ्रेड टोकन स्टोर कर सके, तो बैकग्राउंड लेक्सिकल एनालिसिस ट्रिक करना असंभव होगा।

आगे की सभी समस्याएं .NET स्टैक पर डेस्कटॉप विकास के संदर्भ में सामने आती हैं।

32-बिट समस्या

कुछ उपयोगकर्ता हमारे उत्पादों के स्टैंडअलोन संस्करणों का उपयोग करने का विकल्प चुनते हैं। अन्य विजुअल स्टूडियो और एसक्यूएल सर्वर प्रबंधन स्टूडियो के अंदर काम करने के लिए चिपके रहते हैं। उनके लिए कई एक्सटेंशन विकसित किए गए हैं। इनमें से एक एक्सटेंशन SQL कम्प्लीट है। स्पष्ट करने के लिए, यह मानक कोड पूर्णता SSMS और SQL के लिए VS की तुलना में अधिक शक्तियाँ और सुविधाएँ प्रदान करता है।

सीपीयू और रैम संसाधनों दोनों के संदर्भ में एसक्यूएल पार्सिंग एक बहुत ही महंगी प्रक्रिया है। सर्वर पर अनावश्यक कॉल के बिना, उपयोगकर्ता स्क्रिप्ट में वस्तुओं की सूची का संकेत देने के लिए, हम ऑब्जेक्ट कैश को रैम में संग्रहीत करते हैं। अक्सर, यह ज्यादा जगह नहीं लेता है, लेकिन हमारे कुछ उपयोगकर्ताओं के पास ऐसे डेटाबेस होते हैं जिनमें एक चौथाई मिलियन ऑब्जेक्ट होते हैं।

एसक्यूएल के साथ काम करना अन्य भाषाओं के साथ काम करने से काफी अलग है। सी # में, कोड की एक हजार लाइनों के साथ भी व्यावहारिक रूप से कोई फाइल नहीं है। इस बीच, SQL में एक डेवलपर एक डेटाबेस डंप के साथ काम कर सकता है जिसमें कोड की कई मिलियन लाइनें होती हैं। इसमें कुछ भी असामान्य नहीं है।

DLL-नर्क इनसाइड VS

.NET Framework में प्लगइन्स विकसित करने के लिए एक आसान टूल है, यह एक एप्लिकेशन डोमेन है। सब कुछ एक अलग तरीके से किया जाता है। उतारना संभव है। अधिकांश भाग के लिए, एक्सटेंशन का कार्यान्वयन, शायद, मुख्य कारण है कि एप्लिकेशन डोमेन पेश किए गए थे।

इसके अलावा, एमएएफ फ्रेमवर्क है, जिसे कार्यक्रम में ऐड-ऑन बनाने की समस्या को हल करने के लिए एमएस द्वारा डिजाइन किया गया था। यह इन ऐड-ऑन को इस हद तक अलग करता है कि यह उन्हें एक अलग प्रक्रिया में भेज सकता है और सभी संचारों को अपने हाथ में ले सकता है। सच कहूँ तो, यह समाधान बहुत बोझिल है और इसने अधिक लोकप्रियता हासिल नहीं की है।

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

21वीं सदी में किसी भी अन्य अनुप्रयोग की तरह, हमारे पास बहुत अधिक निर्भरताएँ हैं। उनमें से अधिकांश .NET दुनिया में प्रसिद्ध, समय-सिद्ध और लोकप्रिय पुस्तकालय हैं।

संदेशों को लॉक के अंदर खींचना

यह व्यापक रूप से ज्ञात नहीं है कि .NET Framework प्रत्येक WaitHandle के अंदर Windows संदेश कतार को पंप करेगा। इसे प्रत्येक लॉक के अंदर रखने के लिए, किसी एप्लिकेशन में किसी भी ईवेंट के किसी भी हैंडलर को कॉल किया जा सकता है यदि इस लॉक के पास कर्नेल मोड में स्विच करने का समय है, और इसे स्पिन-प्रतीक्षा चरण के दौरान रिलीज़ नहीं किया गया है।

इसके परिणामस्वरूप कुछ बहुत ही अप्रत्याशित स्थानों में पुन:प्रवेश हो सकता है। कई बार इसने "गणना के दौरान संग्रह को संशोधित किया गया" और विभिन्न ArgumentOutOfRangeException जैसी समस्याओं को जन्म दिया।

SQL का उपयोग करके समाधान में असेंबली जोड़ना

जब परियोजना बढ़ती है, तो असेंबलियों को जोड़ने का कार्य, पहली बार में सरल, एक दर्जन जटिल चरणों में विकसित होता है। एक बार, हमें समाधान में एक दर्जन अलग-अलग असेंबली जोड़नी पड़ी, हमने एक बड़ा रिफैक्टरिंग किया। लगभग 300 .NET परियोजनाओं के आधार पर उत्पाद और परीक्षण सहित लगभग 80 समाधान तैयार किए गए।

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

  1. नया प्रोजेक्ट बनाएं.
  2. इसमें एक प्रमाणपत्र जोड़ें। बिल्ड का टैग सेट करें।
  3. एक संस्करण फ़ाइल जोड़ें।
  4. उन पथों को पुन:कॉन्फ़िगर करें जहां परियोजना जा रही है।
  5. आंतरिक विनिर्देश से मेल खाने के लिए फ़ोल्डर का नाम बदलें।
  6. परियोजना को एक बार फिर समाधान में जोड़ें।
  7. ऐसी कुछ असेंबली जोड़ें जिनसे सभी परियोजनाओं को लिंक की आवश्यकता हो।
  8. बिल्ड को सभी आवश्यक समाधानों में जोड़ें:परीक्षण और उत्पाद।
  9. सभी उत्पाद समाधानों के लिए, असेंबली को इंस्टॉलेशन में जोड़ें।

इन 9 चरणों को लगभग 10 बार दोहराना पड़ा। चरण 8 और 9 इतने छोटे नहीं हैं, और हर जगह बिल्ड जोड़ना भूलना आसान है।

इतने बड़े और नियमित कार्य का सामना करते हुए, कोई भी सामान्य प्रोग्रामर इसे स्वचालित करना चाहेगा। ठीक यही हम करना चाहते थे। लेकिन हम यह कैसे इंगित करते हैं कि नए बनाए गए प्रोजेक्ट में वास्तव में कौन से समाधान और इंस्टॉलेशन जोड़े जाएं? बहुत सारे परिदृश्य हैं और क्या अधिक है, उनमें से कुछ की भविष्यवाणी करना मुश्किल है।

हम एक पागल विचार के साथ आए। समाधान कई-से-अनेक जैसी परियोजनाओं से जुड़े होते हैं, उसी तरह से इंस्टॉलेशन वाले प्रोजेक्ट, और SQL ठीक उसी तरह के कार्यों को हल कर सकता है जो हमारे पास थे।

हमने एक .नेट कोर कंसोल ऐप बनाया है जो स्रोत फ़ोल्डर में सभी .sln फ़ाइलों को स्कैन करता है, डॉटनेट सीएलआई की मदद से उनसे परियोजनाओं की सूची पुनर्प्राप्त करता है, और इसे SQLite डेटाबेस में रखता है। कार्यक्रम के कुछ तरीके हैं:

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

यद्यपि SQL क्वेरी के माध्यम से समाधानों की सूची को इंगित करने का विचार बोझिल लग सकता है, इसने सभी मौजूदा मामलों को पूरी तरह से बंद कर दिया और भविष्य में किसी भी संभावित मामले की संभावना है।

मुझे परिदृश्य का प्रदर्शन करने दो। एक प्रोजेक्ट बनाएं “A” और इसे उन सभी समाधानों में जोड़ें जहां प्रोजेक्ट “B” प्रयोग किया जाता है:

dbforgeasm add-project Folder1\Folder2\A "SELECT s.Id FROM Projects p JOIN Solutions s ON p.SolutionId = s.Id WHERE p.Name = 'B'"

LiteDB के साथ एक समस्या

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

इस कार्य को लागू करने के लिए, फ़ाइलों की सामग्री को कहीं किनारे पर सहेजना आवश्यक था, और इसे अक्सर और जल्दी से करें। सामग्री के अलावा, कुछ मेटाडेटा को सहेजना आवश्यक था, जिससे फ़ाइल सिस्टम में सीधे भंडारण असुविधाजनक हो गया।

उस समय, हमें लाइटडीबी लाइब्रेरी मिली, जिसने हमें इसकी सादगी और प्रदर्शन से प्रभावित किया। लाइटडीबी एक त्वरित हल्का एम्बेडेड डेटाबेस है, जो पूरी तरह से सी # में लिखा गया था। गति और समग्र सादगी ने हमें जीत लिया।

विकास प्रक्रिया के दौरान, पूरी टीम लाइटडीबी के साथ काम करने से संतुष्ट थी। हालाँकि, मुख्य समस्याएँ रिलीज़ के बाद शुरू हुईं।

आधिकारिक दस्तावेज ने गारंटी दी कि डेटाबेस ने कई थ्रेड्स के साथ-साथ कई प्रक्रियाओं से समवर्ती पहुंच के साथ उचित कार्य सुनिश्चित किया। आक्रामक सिंथेटिक परीक्षणों से पता चला है कि डेटाबेस बहु-थ्रेडेड वातावरण में सही ढंग से काम नहीं करता है।

समस्या को जल्दी से ठीक करने के लिए, हमने स्व-लिखित इंटरप्रोसेस ReadWriteLock की मदद से प्रक्रियाओं को सिंक्रनाइज़ किया। अब, लगभग तीन वर्षों के बाद, लाइटडीबी काफी बेहतर तरीके से काम कर रहा है।

स्ट्रीमस्ट्रिंगलिस्ट

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

  1. फाइल लाइन को लाइन से पढ़ने के लिए। फ़ाइल में ऑफ़सेट याद रखें.
  2. अनुरोध पर, अगली पंक्ति जारी करें एक आवश्यक ऑफ़सेट सेट करें, और डेटा वापस करें।

मुख्य कार्य पूरा हो गया है। यह संरचना फ़ाइल आकार की तुलना में अधिक स्थान नहीं लेती है। परीक्षण के चरण में, हम बड़ी और बहुत बड़ी फ़ाइलों के लिए मेमोरी फ़ुटप्रिंट की अच्छी तरह जाँच करते हैं। बड़ी फ़ाइलों को लंबे समय तक संसाधित किया गया था, और छोटी फ़ाइलों को तुरंत संसाधित किया जाएगा।

निष्पादन की जाँच करने के लिए कोई संदर्भ नहीं था समय . रैम को रैंडम एक्सेस मेमोरी कहा जाता है - यह एसएसडी और विशेष रूप से एचडीडी पर इसका प्रतिस्पर्धात्मक लाभ है। ये ड्राइवर रैंडम एक्सेस के लिए बुरी तरह से काम करने लगते हैं। यह पता चला कि इस दृष्टिकोण ने फ़ाइल को पूरी तरह से मेमोरी में लोड करने की तुलना में लगभग 40 गुना धीमा कर दिया। इसके अलावा, हम संदर्भ के आधार पर फ़ाइल को 2,5 -10 पूरे समय पढ़ते हैं।

समाधान सरल था, और सुधार इतना काफ़ी था कि ऑपरेशन में फ़ाइल के पूरी तरह से मेमोरी में लोड होने की तुलना में थोड़ा अधिक समय लगता था।

इसी तरह, रैम की खपत भी नगण्य थी। हमें रैम से डेटा को कैशे प्रोसेसर में लोड करने के सिद्धांत में प्रेरणा मिली। जब आप किसी ऐरे एलीमेंट को एक्सेस करते हैं, तो प्रोसेसर उसके कैशे में दर्जनों पड़ोसी तत्वों को कॉपी करता है क्योंकि आवश्यक तत्व अक्सर पास होते हैं।

कई डेटा संरचनाएं शीर्ष प्रदर्शन हासिल करने के लिए इस प्रोसेसर अनुकूलन का उपयोग करती हैं। यह इस ख़ासियत के कारण है कि सरणी तत्वों तक यादृच्छिक पहुंच अनुक्रमिक पहुंच की तुलना में बहुत धीमी है। हमने एक समान तंत्र लागू किया:हमने एक हजार तारों का एक सेट पढ़ा और उनके ऑफसेट को याद किया। जब हम 1001वीं स्ट्रिंग तक पहुँचते हैं, तो हम पहले 500 स्ट्रिंग्स को छोड़ देते हैं और अगले 500 को लोड करते हैं। अगर हमें पहली 500 लाइनों में से किसी की भी आवश्यकता होती है, तो हम अलग से जाते हैं, क्योंकि हमारे पास पहले से ही ऑफ़सेट है।

प्रोग्रामर को गैर-कार्यात्मक आवश्यकताओं को सावधानीपूर्वक तैयार करने और जांचने की आवश्यकता नहीं है। नतीजतन, हमें भविष्य के मामलों के लिए याद आया, कि हमें लगातार स्मृति के साथ क्रमिक रूप से काम करने की आवश्यकता है।

अपवादों का विश्लेषण करना

आप वेब पर आसानी से उपयोगकर्ता गतिविधि डेटा एकत्र कर सकते हैं। हालाँकि, डेस्कटॉप अनुप्रयोगों के विश्लेषण के मामले में ऐसा नहीं है। ऐसा कोई उपकरण नहीं है जो Google Analytics जैसे मीट्रिक और विज़ुअलाइज़ेशन टूल का अविश्वसनीय सेट देने में सक्षम हो। क्यों? यहाँ मेरी धारणाएँ हैं:

  1. डेस्कटॉप अनुप्रयोग विकास के इतिहास के बड़े हिस्से में, उनके पास वेब तक कोई स्थिर और स्थायी पहुंच नहीं थी।
  2. डेस्कटॉप अनुप्रयोगों के लिए कई विकास उपकरण हैं। इसलिए, सभी UI ढांचे और प्रौद्योगिकियों के लिए एक बहुउद्देश्यीय उपयोगकर्ता डेटा संग्रह उपकरण बनाना असंभव है।

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

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

इसके अलावा, आपके पास सभी एकत्रित डेटा का विश्लेषण करने और सबसे अधिक समस्याग्रस्त मॉड्यूल और कक्षाएं खोजने का अवसर है। विश्लेषण के परिणामों के आधार पर, आप कार्यक्रम के इन भागों को कवर करने के लिए रीफैक्टरिंग या अतिरिक्त परीक्षणों की योजना बना सकते हैं।

स्टैक डिकोडिंग सेवा

.NET बिल्ड में IL कोड होता है, जिसे कई विशेष प्रोग्रामों का उपयोग करके, ऑपरेटर के लिए सटीक, आसानी से C# कोड में वापस परिवर्तित किया जा सकता है। प्रोग्राम कोड को सुरक्षित रखने के तरीकों में से एक इसका आक्षेप है। कार्यक्रमों का नाम बदला जा सकता है; विधियों, चरों और वर्गों को बदला जा सकता है; कोड को इसके समकक्ष से बदला जा सकता है, लेकिन यह वास्तव में समझ से बाहर है।

स्रोत कोड को अस्पष्ट करने की आवश्यकता तब प्रकट होती है जब आप अपने उत्पाद को इस तरह वितरित करते हैं कि उपयोगकर्ता को आपके एप्लिकेशन का निर्माण मिलता है। डेस्कटॉप एप्लिकेशन वे मामले हैं। परीक्षकों के लिए मध्यवर्ती बिल्ड सहित सभी बिल्ड सावधानी से अस्पष्ट हैं।

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

अलग-अलग संस्करणों और संपादकों को अलग-अलग तरीके से भ्रमित किया गया, जिससे डेवलपर के लिए समस्या का अध्ययन करना मुश्किल हो गया या उसे गलत रास्ते पर भी रखा जा सकता था। यह स्पष्ट था कि इस प्रक्रिया को स्वचालित किया जाना था।

deobfuscation नक्शा प्रारूप बहुत सीधा निकला। हमने आसानी से इसका विश्लेषण किया और एक स्टैक डिकोडिंग प्रोग्राम लिखा। इससे कुछ समय पहले, उत्पाद संस्करणों द्वारा अपवादों को प्रस्तुत करने और उन्हें स्टैक द्वारा समूहित करने के लिए एक वेब UI विकसित किया गया था। यह SQLite में डेटाबेस के साथ एक .NET कोर वेबसाइट थी।

SQLite छोटे समाधानों के लिए एक साफ-सुथरा उपकरण है। हमने वहां भी deobfuscation नक्शे लगाने की कोशिश की। प्रत्येक बिल्ड ने लगभग 500 हजार एन्क्रिप्शन और डिक्रिप्शन जोड़े उत्पन्न किए। SQLite इतनी आक्रामक डालने की दर को संभाल नहीं सका।

जबकि एक बिल्ड पर डेटा डेटाबेस में डाला गया था, दो और कतार में जोड़े गए थे। उस समस्या से कुछ समय पहले, मैं क्लिकहाउस पर एक रिपोर्ट सुन रहा था और इसे आज़माने के लिए उत्सुक था। यह उत्कृष्ट साबित हुआ, डालने की दर 200 गुना से अधिक बढ़ गई।

उस ने कहा, स्टैक डिकोडिंग (डेटाबेस से पढ़ना) लगभग 50 गुना धीमा हो गया, लेकिन चूंकि प्रत्येक स्टैक में 1 ms से कम समय लगा, इसलिए इस समस्या का अध्ययन करने में समय व्यतीत करना लागत-अप्रभावी था।

अपवादों के वर्गीकरण के लिए ML.NET

On the subject of the automatic processing of exceptions, we made a few more enhancements.

We already had the Web-UI for a convenient review of exceptions grouped by stacks. We had a Grafana for high-level analysis of product stability at the level of versions and product lines. But a programmer’s eye, constantly craving optimization, caught another aspect of this process.

Historically, dbForge line development was divided among 4 teams. Each team had its own functionality to work on, though the borderline was not always obvious. Our technical support team, relying on their experience, read the stack and assigned it to this or that team. They managed it quite well, yet, in some cases, mistakes occurred. The information on errors from analytics came to Jira on its own, but the support team still needed to classify tasks by team.

In the meantime, Microsoft introduced a new library – ML.NET. And we still had this classification task. A library of that kind was exactly what we needed. It extracted stacks of all resolved exceptions from Redmine, a project management system that we used earlier, and Jira, which we use at present.

We obtained a data array that contained some 5 thousand pairs of Exception StackTrace and command. We put 100 exceptions aside and used the rest of the exceptions to teach a model. The accuracy was about 75%. Again, we had 4 teams, hence, random and round-robin would only attain 25%. It sufficiently saved up their time.

To my way of thinking, if we considerably clean up incoming data array, make a thorough examination of the ML.NET library, and theoretical foundation in machine learning, on the whole, we can improve these results. At the same time, I was impressed with the simplicity of this library:with no special knowledge in AI and ML, we managed to gain real cost-benefits in less than an hour.

निष्कर्ष

Hopefully, some of the readers happen to be users of the products I describe in this article, and some lines shed light on the reasons why this or that function was implemented this way.

And now, let me conclude:

We should make decisions based on data and not assumptions. It is about behavior analytics and insights that we can obtain from it.

We ought to constantly invest in tools. There is nothing wrong if we need to develop something for it. In the next few months, it will save us a lot of time and rid us of routine. Routine on top of time expenditure can be very demotivating.

When we develop some internal tools, we get a super chance to try out new technologies, which can be applied in production solutions later on.

There are infinitely many tools for data analysis. Still, we managed to extract some crucial information using SQL tools. This is the most powerful tool to formulate a question to data and receive an answer in a structured form.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. एसक्यूएल में टीसीएल कमांड

  2. एक पुस्तकालय डेटा मॉडल

  3. पार्स पैरामीटर डिफ़ॉल्ट मान PowerShell का उपयोग कर - भाग 2

  4. पीएल/एसक्यूएल ट्यूटोरियल:पीएल/एसक्यूएल के बारे में वह सब कुछ जो आपको जानना आवश्यक है

  5. Azure SQL डेटाबेस के लिए बैंडविड्थ के अनुकूल क्वेरी प्रोफाइलिंग