पिछले हफ्ते, मैंने हमेशा एन्क्रिप्टेड की सीमाओं के साथ-साथ प्रदर्शन प्रभाव के बारे में लिखा था। मैं मुख्य रूप से निम्नलिखित परिवर्तनों के कारण अधिक परीक्षण करने के बाद एक अनुवर्ती पोस्ट करना चाहता था:
- मैंने स्थानीय के लिए एक परीक्षण जोड़ा, यह देखने के लिए कि क्या नेटवर्क ओवरहेड महत्वपूर्ण था (पहले, परीक्षण केवल दूरस्थ था)। हालांकि, मुझे "नेटवर्क ओवरहेड" को एयर कोट्स में रखना चाहिए, क्योंकि ये एक ही भौतिक होस्ट पर दो वीएम हैं, इसलिए वास्तव में एक वास्तविक नंगे धातु विश्लेषण नहीं है।
- मैंने इसे और अधिक यथार्थवादी बनाने के लिए तालिका में कुछ अतिरिक्त (गैर-एन्क्रिप्टेड) कॉलम जोड़े हैं (लेकिन वास्तव में यह यथार्थवादी नहीं है)। , इज़एक्टिव बिट नॉट न्यूल डिफॉल्ट 1
फिर उसके अनुसार पुनर्प्राप्ति प्रक्रिया में परिवर्तन किया:
ALTER PROCESS dbo.RetrievePeopleASBEGIN SET NOCOUNT ON; टॉप (100) अंतिम नाम, वेतन, दिनांक निर्मित, दिनांक संशोधित, डीबीओ से सक्रिय चुनें। कर्मचारी आदेश द्वारा NEWID ();ENDGO
- तालिका को छोटा करने के लिए एक प्रक्रिया जोड़ी गई (पहले मैं इसे मैन्युअल रूप से परीक्षणों के बीच कर रहा था):
CREATE PROCEDURE dbo.CleanupASBEGIN SET NOCOUNT ON; TRUNCATE TABLE dbo.कर्मचारी;ENDGO
- समय रिकॉर्ड करने के लिए एक प्रक्रिया जोड़ी गई (पहले मैं कंसोल आउटपुट को मैन्युअल रूप से पार्स कर रहा था):
उपयोग उपयोगिता;गो क्रिएट टेबल डीबीओ।टाइमिंग्स(टेस्ट NVARCHAR(32), इन्सर्टटाइम INT, SelectTime INT, TestCompleted DATETIME NOT NULL DEFAULT SYSUTCDATETIME (), होस्टनाम SYSNAME नॉट डिफॉल्ट HOST_NAME ()); GO CREATE PROCEDURE dbo.AddTimeing @Test VARCHAR(32), @InsertTime INT, @SelectTime INTASBEGIN SET NOCOUNT ON; INSERT dbo.Timings(Test,InsertTime,SelectTime) SELECT @Test,@InsertTime,@SelectTime;ENDGO
- मैंने डेटाबेस की एक जोड़ी जोड़ी है जो पृष्ठ संपीड़न का उपयोग करती है - हम सभी जानते हैं कि एन्क्रिप्टेड मान अच्छी तरह से संपीड़ित नहीं होते हैं, लेकिन यह एक ध्रुवीकरण विशेषता है जिसे एन्क्रिप्टेड कॉलम वाले टेबल पर भी एकतरफा उपयोग किया जा सकता है, इसलिए मैंने सोचा कि मैं बस इन्हें भी प्रोफाइल करें। (और
App.Config
. में दो और कनेक्शन स्ट्रिंग जोड़े गए .)<जोड़ें नाम ="सामान्य" कनेक्शनस्ट्रिंग ="...; प्रारंभिक कैटलॉग =सामान्य;"/> <नाम जोड़ें ="एन्क्रिप्ट करें" कनेक्शनस्ट्रिंग ="...; प्रारंभिक कैटलॉग =एन्क्रिप्ट करें; कॉलम एन्क्रिप्शन सेटिंग =सक्षम;"/> <नाम जोड़ें ="NormalCompress" कनेक्शनस्ट्रिंग ="...; प्रारंभिक कैटलॉग =सामान्य कॉम्प्रेस;" /> एन्क्रिप्शन सेटिंग =सक्षम;"/> - मैंने tobi से मिले फीडबैक के आधार पर C# कोड (परिशिष्ट देखें) में कई सुधार किए हैं (जिसके कारण यह कोड समीक्षा प्रश्न सामने आया) और सहकर्मी ब्रुक फिल्पोट (@Macromullet) से कुछ बड़ी सहायता मिली। इनमें शामिल हैं:
- यादृच्छिक नाम/वेतन उत्पन्न करने के लिए संग्रहीत कार्यविधि को समाप्त करना, और इसके बजाय C# में करना
Stopwatch
का उपयोग करके अनाड़ी दिनांक/समय के तार के बजायusing()
का अधिक सुसंगत उपयोग और.Close()
. का उन्मूलन- थोड़ा बेहतर नामकरण परंपराएं (और टिप्पणियां!)
while
for
. के लिए लूप लूप- एक
StringBuilder
का उपयोग करना भोले संयोजन के बजाय (जिसे मैंने शुरू में जानबूझकर चुना था) - कनेक्शन स्ट्रिंग्स को समेकित करना (हालांकि मैं अभी भी जानबूझकर प्रत्येक लूप पुनरावृत्ति के भीतर एक नया कनेक्शन बना रहा हूं)
फिर मैंने एक साधारण बैच फ़ाइल बनाई जो प्रत्येक परीक्षण को 5 बार चलाएगी (और स्थानीय और दूरस्थ कंप्यूटर दोनों पर इसे दोहराया):
के लिएपरीक्षण पूर्ण होने के बाद, उपयोग की गई अवधि और स्थान को मापना तुच्छ होगा (और परिणामों से चार्ट बनाने में एक्सेल में थोड़ा हेरफेर होगा):
-- अवधि चयन होस्टनाम, टेस्ट, औसत इंसर्टटाइम =औसत (1.0 * सम्मिलित समय), औसत चयन समय =औसत (1.0 * चयन समय) Utility.dbo से। होस्टनाम द्वारा टाइमिंग्स ग्रुप, होस्टनाम द्वारा टेस्टर, टेस्ट; -- स्पेस यूज नॉर्मल; - नॉर्मल कंप्रेस; एन्क्रिप्ट करें; एन्क्रिप्टकंप्रेस; sys.dm_db_database_page_allocations(DB_ID(), OBJECT_ID(N'dbo.Employees'), NULL, NULL, N'LIMITED') से COUNT(*)*8.192 चुनें);
अवधि परिणाम
उपरोक्त अवधि क्वेरी से कच्चे परिणाम यहां दिए गए हैं (CANUCK
उस मशीन का नाम है जो SQL सर्वर के इंस्टेंस को होस्ट करता है, और HOSER
वह मशीन है जो कोड के दूरस्थ संस्करण को चलाती है):
अवधि क्वेरी के कच्चे परिणाम
जाहिर है कि दूसरे रूप में कल्पना करना आसान होगा। जैसा कि पहले ग्राफ़ में दिखाया गया है, रिमोट एक्सेस का आवेषण की अवधि (40% से अधिक वृद्धि) पर महत्वपूर्ण प्रभाव पड़ा, लेकिन संपीड़न का बिल्कुल भी प्रभाव नहीं पड़ा। अकेले एन्क्रिप्शन ने किसी भी परीक्षण श्रेणी की अवधि को लगभग दोगुना कर दिया:
100,000 पंक्तियों को सम्मिलित करने की अवधि (मिलीसेकंड)
पढ़ने के लिए, एन्क्रिप्शन या डेटा को दूरस्थ रूप से पढ़ने की तुलना में संपीड़न का प्रदर्शन पर बहुत बड़ा प्रभाव पड़ा:
100 रैंडम पंक्तियों को 1,000 बार पढ़ने की अवधि (मिलीसेकंड)
अंतरिक्ष परिणाम
जैसा कि आपने अनुमान लगाया होगा, संपीड़न इस डेटा को संग्रहीत करने के लिए आवश्यक स्थान की मात्रा को काफी कम कर सकता है (लगभग आधे में), जबकि एन्क्रिप्शन को विपरीत दिशा में डेटा आकार को प्रभावित करते हुए देखा जा सकता है (लगभग इसे तीन गुना)। और, ज़ाहिर है, एन्क्रिप्टेड मानों को संपीड़ित करने से कोई लाभ नहीं होता है:
संपीड़न के साथ या बिना कंप्रेशन के साथ या बिना 100,000 पंक्तियों को संग्रहीत करने के लिए उपयोग किया गया स्थान (KB) एन्क्रिप्शन
सारांश
इससे आपको इस बात का अंदाजा होना चाहिए कि हमेशा एन्क्रिप्टेड को लागू करते समय क्या प्रभाव होने की उम्मीद है। हालांकि, ध्यान रखें कि यह एक बहुत ही विशेष परीक्षण था, और यह कि मैं एक प्रारंभिक CTP बिल्ड का उपयोग कर रहा था। आपका डेटा और एक्सेस पैटर्न बहुत अलग परिणाम दे सकता है, और भविष्य के सीटीपी और .NET फ्रेमवर्क के अपडेट में आगे बढ़ने से इस परीक्षण में भी इनमें से कुछ अंतर कम हो सकते हैं।
आप यह भी देखेंगे कि मेरी पिछली पोस्ट की तुलना में यहां परिणाम बोर्ड भर में थोड़े अलग थे। इसे समझाया जा सकता है:
- सम्मिलित करने का समय सभी मामलों में तेज था क्योंकि अब मुझे यादृच्छिक नाम और वेतन उत्पन्न करने के लिए डेटाबेस में अतिरिक्त राउंड-ट्रिप नहीं करना पड़ रहा है।
- चुनने का समय सभी मामलों में तेज था क्योंकि मैं अब स्ट्रिंग कॉन्सटेनेशन की एक मैला विधि का उपयोग नहीं कर रहा हूं (जिसे अवधि मीट्रिक के हिस्से के रूप में शामिल किया गया था)।
- इस्तेमाल किया गया स्थान दोनों ही मामलों में थोड़ा बड़ा था, मुझे संदेह है कि यादृच्छिक स्ट्रिंग्स के एक अलग वितरण के कारण उत्पन्न हुए थे।
परिशिष्ट A - C# कंसोल एप्लिकेशन कोड
सिस्टम का उपयोग करना;सिस्टम का उपयोग करना।कॉन्फ़िगरेशन;सिस्टम का उपयोग करना। नेमस्पेस AEDemo {वर्ग AEDemo { स्थिर शून्य मुख्य (स्ट्रिंग [] args) {// कोड के प्रत्येक भाग के समय के लिए एक स्टॉपवॉच सेट करें var टाइमर =System.Diagnostics.Stopwatch.StartNew (); // यादृच्छिक वस्तु यादृच्छिक नाम / वेतन प्रस्तुत करने के लिए var यादृच्छिक =नया यादृच्छिक (); // कमांड लाइन तर्क के आधार पर कनेक्ट करें var कनेक्शनस्ट्रिंग =कॉन्फ़िगरेशन प्रबंधक। कनेक्शनस्ट्रिंग्स [तर्क [0]]। ToString (); (var sqlConnection =new SqlConnection (connectionString)) {// का उपयोग करके यह केवल तालिका को छोटा करता है, जिसे मैं पहले मैन्युअल रूप से उपयोग कर रहा था (var sqlCommand =new SqlCommand("dbo.Cleanup", sqlConnection)) { sqlConnection.Open(); sqlCommand.ExecuteNonQuery (); } } // पहले, 100,000 नाम/वेतन जोड़े उत्पन्न करें और उन्हें सम्मिलित करें (int i =1; i <=100000; i++) {// 32750 और 197500 के बीच यादृच्छिक वेतन var randomSalary =random.Next(32750, 197500); // वर्णों की यादृच्छिक संख्या की यादृच्छिक स्ट्रिंग var लंबाई =random.Next(1, 32); चार [] randomCharArray =नया चार [लंबाई]; के लिए (इंट बाइटऑफ़सेट =0; बाइटऑफ़सेट <लंबाई; बाइटऑफ़सेट++) {randomCharArray[byteOffset] =(char)random.Next(65, 90); // ए-जेड} var randomName =नया स्ट्रिंग (randomCharArray); // यह संग्रहीत प्रक्रिया नाम और वेतन को स्वीकार करती है और उन्हें टेबल पर लिखती है // एन्क्रिप्शन सक्षम डेटाबेस में, SqlClient यहां एन्क्रिप्ट करता है // तो एक ट्रेस में आप देखेंगे @LastName =0xAE4C12..., @Salary =0x12EA32... (var sqlConnection =new SqlConnection(connectionString)) { का उपयोग करके (var sqlCommand =new SqlCommand("dbo.AddEmployee", sqlConnection)) { sqlCommand.CommandType =CommandType.StoreedProcedure; sqlCommand.Parameters.Add("@LastName", SqlDbType.NVarChar, 32).Value =randomName; sqlCommand.Parameters.Add("@Salary", SqlDbType.Int).Value =randomSalary; एसक्यूएलकनेक्शन। ओपन (); sqlCommand.ExecuteNonQuery (); } } } // टाइमिंग टाइमर को कैप्चर करें। स्टॉप (); var timeInsert =timer.ElapsedMilliseconds; टाइमर। रीसेट (); टाइमर। प्रारंभ (); वर प्लेसहोल्डर =नया स्ट्रिंगबिल्डर (); के लिए (int i =1; i <=1000; i++) { (var sqlConnection =new SqlConnection (connectionString)) {// लूप के माध्यम से और 100 पंक्तियों को खींचकर, 1,000 बार (var sqlCommand =new SqlCommand ("dbo.RetrieveRandomEmployees) का उपयोग करके ", sqlConnection)) { sqlCommand.CommandType =CommandType.StoreedProcedure; एसक्यूएलकनेक्शन। ओपन (); का उपयोग कर (var sqlDataReader =sqlCommand.ExecuteReader ()) {जबकि (sqlDataReader.Read ()) {// आउटपुट प्लेसहोल्डर के साथ कुछ ठोस करें। एपेंड (sqlDataReader [0]। ToString ()); } } } } } // टाइमिंग को फिर से कैप्चर करें, दोनों को db टाइमर पर लिखें। स्टॉप (); var timeSelect =timer.ElapsedMilliseconds; (var sqlConnection =new SqlConnection (connectionString)) { का उपयोग करके (var sqlCommand =new SqlCommand("Utility.dbo.AddTiming", sqlConnection)) { sqlCommand.CommandType =CommandType.StoreedProcedure; sqlCommand.Parameters.Add("@Test", SqlDbType.NVarChar, 32).Value =args[0]; sqlCommand.Parameters.Add("@InsertTime", SqlDbType.Int).Value =timeInsert; sqlCommand.Parameters.Add("@SelectTime", SqlDbType.Int).Value =timeSelect; एसक्यूएलकनेक्शन। ओपन (); sqlCommand.ExecuteNonQuery (); } } } }}