मैंने कर्सर का उपयोग करने के बारे में कई बार लिखा है और कैसे, ज्यादातर मामलों में, सेट-आधारित तर्क का उपयोग करके अपने कर्सर को फिर से लिखना अधिक कुशल है।
हालांकि, मैं यथार्थवादी हूं।
मुझे पता है कि ऐसे मामले हैं जहां कर्सर "आवश्यक" हैं - आपको किसी अन्य संग्रहीत प्रक्रिया को कॉल करने या प्रत्येक पंक्ति के लिए एक ई-मेल भेजने की आवश्यकता है, आप प्रत्येक डेटाबेस के विरुद्ध रखरखाव कार्य कर रहे हैं, या आप एक बार का कार्य चला रहे हैं जो बस सेट-आधारित में बदलने के लिए समय निवेश करने लायक नहीं है।
आप (शायद) इसे आज कैसे कर रहे हैं
भले ही आप अभी भी कर्सर का उपयोग कर रहे हों, आपको कम से कम सावधान रहना चाहिए कि काफी महंगे डिफ़ॉल्ट विकल्पों का उपयोग न करें। ज्यादातर लोग अपने कर्सर को इस तरह से शुरू करते हैं:
DECLARE c CURSOR FOR SELECT whatever FROM ...
अब फिर, तदर्थ, एकबारगी कार्यों के लिए, यह शायद ठीक है। लेकिन वहाँ हैं…
इसे करने के अन्य तरीके
मैं डिफ़ॉल्ट का उपयोग करके कुछ परीक्षण चलाना चाहता था और उनकी तुलना विभिन्न कर्सर विकल्पों जैसे LOCAL
से करना चाहता था , स्थिर
, READ_ONLY
और FAST_FORWARD
. (विकल्पों में से एक टन हैं, लेकिन ये सबसे अधिक उपयोग किए जाने वाले हैं क्योंकि वे सबसे सामान्य प्रकार के कर्सर संचालन पर लागू होते हैं जिनका लोग उपयोग करते हैं।) न केवल मैं कुछ अलग संयोजनों की कच्ची गति का परीक्षण करना चाहता था, बल्कि शीत सेवा के पुनरारंभ होने और गर्म कैश के साथ, दोनों tempdb और स्मृति पर भी प्रभाव।
जिस क्वेरी को मैंने कर्सर को फीड करने का निर्णय लिया वह sys.objects
. के विरुद्ध एक बहुत ही सरल क्वेरी है , AdventureWorks2012 नमूना डेटाबेस में। यह मेरे सिस्टम पर 318,500 पंक्तियाँ देता है (4GB RAM वाला एक बहुत ही विनम्र 2-कोर सिस्टम):
SELECT c1.[object_id] FROM sys.objects AS c1 CROSS JOIN (SELECT TOP 500 name FROM sys.objects) AS c2;
फिर मैंने इस क्वेरी को विभिन्न विकल्पों (डिफ़ॉल्ट सहित) के साथ एक कर्सर में लपेटा और कुछ परीक्षण चलाए, कुल सर्वर मेमोरी को मापने के लिए, टेम्पर्ड को आवंटित पृष्ठ (sys.dm_db_task_space_usage
के अनुसार) और/या sys.dm_db_session_space_usage
), और कुल अवधि। मैंने ग्लेन बेरी और रॉबर्ट डेविस की लिपियों का उपयोग करके tempdb विवाद का निरीक्षण करने का भी प्रयास किया, लेकिन मेरी कमजोर प्रणाली पर मैं किसी भी विवाद का पता नहीं लगा सका। निश्चित रूप से मैं भी एसएसडी पर हूं और सिस्टम पर कुछ और नहीं चल रहा है, इसलिए ये ऐसी चीजें हो सकती हैं जिन्हें आप अपने स्वयं के परीक्षणों में जोड़ना चाहते हैं यदि tempdb एक बाधा होने की अधिक संभावना है।
तो अंत में प्रश्न कुछ इस तरह दिखे, निदान संबंधी प्रश्नों को उपयुक्त बिंदुओं पर शामिल किया गया:
DECLARE @i INT = 1; DECLARE c CURSOR -- LOCAL -- LOCAL STATIC -- LOCAL FAST_FORWARD -- LOCAL STATIC READ_ONLY FORWARD_ONLY FOR SELECT c1.[object_id] FROM sys.objects AS c1 CROSS JOIN (SELECT TOP 500 name FROM sys.objects) AS c2 ORDER BY c1.[object_id]; OPEN c; FETCH c INTO @i; WHILE (@@FETCH_STATUS = 0) BEGIN SET @i += 1; -- meaningless operation FETCH c INTO @i; END CLOSE c; DEALLOCATE c;
परिणाम
अवधि
यकीनन सबसे महत्वपूर्ण और सामान्य उपाय है, "इसमें कितना समय लगा?" खैर, डिफ़ॉल्ट विकल्पों (या केवल LOCAL
के साथ) के साथ कर्सर चलाने में लगभग पांच गुना समय लगा निर्दिष्ट), या तो निर्दिष्ट करने की तुलना में STATIC
या FAST_FORWARD
:
स्मृति
मैं अतिरिक्त मेमोरी को भी मापना चाहता था जो SQL सर्वर प्रत्येक कर्सर प्रकार को पूरा करते समय अनुरोध करेगा। इसलिए मैंने प्रदर्शन काउंटर कुल सर्वर मेमोरी (KB)
को मापते हुए, प्रत्येक कोल्ड कैश परीक्षण से पहले बस पुनः आरंभ किया। प्रत्येक परीक्षण से पहले और बाद में। यहां सबसे अच्छा संयोजन था LOCAL FAST_FORWARD
:
tempdb उपयोग
यह परिणाम मेरे लिए आश्चर्यजनक था। चूंकि एक स्थिर कर्सर की परिभाषा का अर्थ है कि यह पूरे परिणाम को tempdb पर कॉपी करता है, और यह वास्तव में sys.dm_exec_cursors
में व्यक्त किया जाता है। स्नैपशॉट
. के रूप में , मुझे उम्मीद थी कि tempdb पृष्ठों पर हिट कर्सर के सभी स्थिर रूपों के साथ अधिक होगी। यह मामला नहीं था; फिर से हम डिफ़ॉल्ट कर्सर और केवल LOCAL
के साथ tempdb उपयोग पर लगभग 5X हिट देखते हैं निर्दिष्ट:
निष्कर्ष
वर्षों से मैं इस बात पर जोर दे रहा हूं कि निम्नलिखित विकल्प हमेशा आपके कर्सर के लिए निर्दिष्ट किए जाने चाहिए:
LOCAL STATIC READ_ONLY FORWARD_ONLY
इस बिंदु से, जब तक मुझे आगे के क्रमपरिवर्तन का परीक्षण करने का मौका नहीं मिलता है या किसी भी मामले को खोजने का मौका नहीं मिलता है, जहां यह सबसे तेज़ विकल्प नहीं है, मैं निम्नलिखित की सिफारिश करूंगा:
LOCAL FAST_FORWARD
(एक तरफ के रूप में, मैंने LOCAL
. को छोड़कर परीक्षण भी चलाए विकल्प, और अंतर नगण्य थे।)
उस ने कहा, यह जरूरी नहीं कि *सभी* कर्सर के लिए सही हो। इस मामले में, मैं केवल कर्सर के बारे में बात कर रहा हूं जहां आप केवल आगे की दिशा में कर्सर से डेटा पढ़ रहे हैं, और आप अंतर्निहित डेटा को अपडेट नहीं कर रहे हैं (या तो कुंजी द्वारा या WHERE CURRENT OF<का उपयोग करके) /कोड> ) वे एक और दिन के लिए परीक्षण हैं।