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

वर्चुअल कॉलम और फंक्शनल इंडेक्स

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

प्रश्नों की जटिलता

आइए समस्याग्रस्त प्रश्नों को करीब से देखें। उनमें से कई जटिल हैं। यह कई कारणों से हो सकता है:

  1. डेटा के लिए चुना गया डेटाटाइप;
  2. डेटाबेस में डेटा का संगठन और भंडारण;
  3. वांछित परिणाम सेट प्राप्त करने के लिए डेटा को क्वेरी में बदलना और जोड़ना।

आपको इन तीन प्रमुख कारकों पर ठीक से विचार करने और प्रश्नों को बेहतर ढंग से निष्पादित करने के लिए उन्हें सही ढंग से लागू करने की आवश्यकता है।

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

इस तरह के प्रश्नों में निम्नलिखित की तरह जटिल जोड़ शामिल हो सकते हैं:

  1. कई डेटा कॉलम के सबस्ट्रिंग और/या संयोजन का संयोजन;
  2. अंतर्निहित स्केलर फ़ंक्शन;
  3. अनुकूलित यूडीएफ;
  4. WHERE क्लॉज तुलना और खोज स्थितियों का कोई भी संयोजन।

जैसा कि पहले बताया गया है, क्वेरी में आमतौर पर जटिल पहुंच पथ होते हैं। इससे भी बुरी बात यह है कि उनके पास जॉइन या खोजों के ऐसे संयोजनों के साथ कई टेबल स्कैन और/या पूर्ण अनुक्रमणिका स्कैन हो सकते हैं।

डेटा परिवर्तन और प्रश्नों में हेरफेर

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

ज्यादातर मामलों में, जॉइन में किए गए परिवर्तन डेटा को पढ़ने और tempdb पर लोड करने के बाद होते हैं। डेटाबेस (एसक्यूएल सर्वर) या कार्यफ़ाइल डेटाबेस / अस्थायी-तालिका स्थान जैसा कि अन्य डेटाबेस सिस्टम में होता है।

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

तो, एक डेटाबेस डेवलपर या एक डीबीए उन प्रदर्शन बाधाओं को कैसे जल्दी से हल कर सकता है और खुद को फिर से इंजीनियर करने और इष्टतम प्रदर्शन के लिए प्रश्नों को फिर से लिखने के लिए और अधिक समय प्रदान कर सकता है?

ऐसी लगातार समस्याओं को प्रभावी ढंग से हल करने के दो तरीके हैं। उनमें से एक वर्चुअल कॉलम और/या कार्यात्मक अनुक्रमणिका का उपयोग करना है।

कार्यात्मक अनुक्रमणिका और क्वेरी

आम तौर पर, आप कॉलम पर इंडेक्स बनाते हैं जो या तो एक पंक्ति में कॉलम/मानों का एक अनूठा सेट (अद्वितीय इंडेक्स या प्राथमिक कुंजी) इंगित करता है या कॉलम/मानों के एक सेट का प्रतिनिधित्व करता है जो किसी क्वेरी की WHERE क्लॉज खोज स्थितियों में उपयोग किया जा सकता है या किया जा सकता है।

यदि आपके पास ऐसी अनुक्रमणिकाएँ नहीं हैं, और आपने पहले वर्णित जटिल प्रश्नों को विकसित किया है, तो आप निम्नलिखित पर ध्यान देंगे:

  1. व्याख्या . का उपयोग करते समय प्रदर्शन के स्तर में कमी क्वेरी और तालिका स्कैन या पूर्ण अनुक्रमणिका स्कैन देखना
  2. प्रश्नों के कारण बहुत अधिक CPU और संसाधन उपयोग;
  3. निष्पादन का लंबा समय।

समसामयिक डेटाबेस आमतौर पर आपको कार्यात्मक . बनाने की अनुमति देकर इन मुद्दों का समाधान करते हैं या कार्य-आधारित अनुक्रमणिका, जैसा कि SQLServer, Oracle, और MySQL (v 8.x) में नाम दिया गया है। या, यह अनुक्रमणिका चालू . हो सकता है अभिव्यक्ति/अभिव्यक्ति-आधारित अनुक्रमणिका, अन्य डेटाबेस की तरह (PostgreSQL और Db2)।

मान लें कि आपके पास खरीदारी_दिनांक कॉलम . है आपके आदेश . में डेटा प्रकार TIMESTAMP या DATETIME का तालिका, और उस स्तंभ को अनुक्रमित किया गया है। हम आदेश को क्वेरी करना शुरू करते हैं WHERE क्लॉज वाली टेबल:

SELECT ...
FROM Order
WHERE DATE(Purchase_Date) = '03.12.2020'

यह लेनदेन पूरे सूचकांक की स्कैनिंग का कारण बनेगा। हालांकि, यदि कॉलम को अनुक्रमित नहीं किया गया है, तो आपको एक टेबल स्कैन मिलता है।

संपूर्ण अनुक्रमणिका को स्कैन करने के बाद, वह अनुक्रमणिका tempdb / workfile . में चली जाती है (पूरी तालिका अगर आपको टेबल स्कैन . मिलता है ) मान से मेल खाने से पहले 03.12.2020

चूंकि एक बड़ी ऑर्डर तालिका बहुत सारे CPU और संसाधनों का उपयोग करती है, इसलिए आपको DATE अभिव्यक्ति (Purchase_Date) वाली एक कार्यात्मक अनुक्रमणिका बनानी चाहिए ) इंडेक्स कॉलम में से एक के रूप में और नीचे दिखाया गया है:

CREATE ix_DatePurchased on sales.Order(Date(Purchase_Date) desc, ... )

ऐसा करने पर, आप मिलान विधेय DATE (Purchase_Date) ='03.12.2020' बनाते हैं अनुक्रमणीय इस प्रकार, मूल्य के मिलान से पहले इंडेक्स या टेबल को tempdb / वर्कफाइल में ले जाने के बजाय, हम इंडेक्स को केवल आंशिक रूप से एक्सेस और/या स्कैन करते हैं। इसके परिणामस्वरूप कम CPU और संसाधन उपयोग होता है।

एक और उदाहरण देखिए। एक ग्राहक है कॉलम के साथ तालिका first_name, last_name . उन स्तंभों को इस प्रकार अनुक्रमित किया जाता है:

CREATE INDEX ix_custname on Customer(first_name asc, last_name asc),

इसके अलावा, आपके पास एक दृश्य है जो इन स्तंभों को customer_name . में संयोजित करता है कॉलम:

CREATE view v_CustomerInfo( customer_name, .... ) as
select first_name ||' '|| last_name as customer_name,.....
from Customer
where ...

आपके पास एक ईकामर्स सिस्टम से एक क्वेरी है जो पूरे ग्राहक नाम की खोज करती है:

select c.*
from v_CustomerInfo c
where c.customer_name = 'John Smith'
....

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

एक अन्य मामला एक कार्यात्मक सूचकांक बना रहा है जैसा कि नीचे दिखाया गया है:

CREATE ix_fullcustname on sales.Customer( first_name ||' '|| last_name desc, ... )

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

वर्चुअल (जेनरेट) कॉलम और क्वेरी

जेनरेट किए गए कॉलम (वर्चुअल कॉलम या कंप्यूटेड कॉलम) ऐसे कॉलम होते हैं जो फ्लाई पर जेनरेट किए गए डेटा को रखते हैं। डेटा को स्पष्ट रूप से किसी विशिष्ट मान पर सेट नहीं किया जा सकता है। यह डीएमएल क्वेरी में क्वेरी किए गए, सम्मिलित किए गए या अपडेट किए गए अन्य कॉलम में डेटा को संदर्भित करता है।

ऐसे स्तंभों का मान उत्पन्न करना एक व्यंजक के आधार पर स्वचालित होता है। ये भाव उत्पन्न हो सकते हैं:

  1. पूर्णांक मानों का एक क्रम;
  2. तालिका में अन्य स्तंभों के मूल्यों के आधार पर मान;
  3. यह बिल्ट-इन फंक्शन्स या यूज़र-डिफ़ाइंड फंक्शन्स (UDFs) को कॉल करके वैल्यू जेनरेट कर सकता है।

यह नोट करना भी उतना ही महत्वपूर्ण है कि कुछ डेटाबेस (SQLServer, Oracle, PostgreSQL, MySQL, और MariaDB) में इन कॉलमों को INSERT और UPDATE स्टेटमेंट निष्पादन के साथ डेटा को लगातार स्टोर करने के लिए कॉन्फ़िगर किया जा सकता है, या फ्लाई पर अंतर्निहित कॉलम एक्सप्रेशन निष्पादित किया जा सकता है। अगर हम स्टोरेज स्पेस को सेव करते हुए टेबल और कॉलम को क्वेरी करते हैं।

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

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

आइए एक उदाहरण देखें। हम तालिका घोषित करते हैं और इस प्रकार एक अनुक्रमणिका बनाते हैं:

CREATE TABLE Customer as (
  customerID Int GENERATED ALWAYS AS IDENTITY,
  first_name VARCHAR(50) NOT NULL,
  last_name VARCHAR(50) NOT NULL,
  customer_name as (first_name ||' '|| last_name) PERSISTED
  ...
  );
CREATE ix_fullcustname on sales.Customer( customer_name desc, ... )

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

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

कार्यात्मक अनुक्रमणिका, जनरेट किए गए स्तंभ और JSON

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

JSON डेटा संरचनाओं के बढ़ते उपयोग के कारण, रिलेशनल डेटाबेस में JSON स्टोरेज फॉर्मेट या तो BLOB डेटा टाइप या CLOB डेटा टाइप होता है। ये दोनों प्रकार ऐसे कॉलम में डेटा को अनइंडेक्स करने योग्य बनाते हैं।

इस कारण से, डेटाबेस विक्रेताओं ने JSON ऑब्जेक्ट्स को क्वेरी और संशोधित करने के लिए JSON फ़ंक्शन पेश किए, क्योंकि आप इन फ़ंक्शंस को SQL क्वेरी या अन्य DML कमांड में आसानी से एकीकृत कर सकते हैं। हालाँकि, ये प्रश्न JSON ऑब्जेक्ट की जटिलता पर निर्भर करते हैं। वे बहुत सीपीयू और संसाधन-खपत हैं, क्योंकि बीएलओबी और सीएलओबी ऑब्जेक्ट्स को मेमोरी में लोड करने की आवश्यकता होती है, या इससे भी बदतर, वर्कफाइल में पूछताछ और/या हेरफेर से पहले।

मान लें कि हमारे पास एक ग्राहक है ग्राहक विवरण . के साथ तालिका CustomerDetail . नामक कॉलम में JSON ऑब्जेक्ट के रूप में संग्रहीत डेटा . हम नीचे दी गई तालिका को क्वेरी करते हुए सेट करते हैं:

SELECT CustomerID,
  JSON_VALUE(CustomerDetail, '$.customer.Name') AS Name,
  JSON_VALUE(CustomerDetail, '$.customer.Surname') AS Surname,
  JSON_VALUE(CustomerDetail, '$.customer.address.PostCode') AS PostCode,
  JSON_VALUE(CustomerDetail, '$.customer.address."Address Line 1"') + ' '
  + JSON_VALUE(CustomerDetail, '$.customer.address."Address Line 2"') AS Address,
  JSON_QUERY(CustomerDetail, '$.customer.address.Country') AS Country
FROM Customer
WHERE ISJSON(CustomerDetail) > 0
  AND JSON_VALUE(CustomerDetail, '$.customer.address.Country') = 'Iceland'
  AND JSON_VALUE(CustomerDetail, '$.customer.address.PostCode') IN (101,102,110,210,220)
  AND Status = 'Active'
ORDER BY JSON_VALUE(CustomerDetail, '$.customer.address.PostCode')

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

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

हम जेनरेट किए गए कॉलम जोड़कर प्रदर्शन को बढ़ावा देते हैं। एक जेनरेट किया गया कॉलम JSON फ़ंक्शन का उपयोग करके कॉलम में दर्शाए गए विशिष्ट डेटा के लिए JSON दस्तावेज़ के माध्यम से खोज करेगा और मान को कॉलम में संग्रहीत करेगा।

हम नियमित एसक्यूएल का उपयोग करके इन जेनरेट किए गए कॉलम को इंडेक्स और क्वेरी कर सकते हैं जहां क्लॉज सर्च स्थितियां हैं। इसलिए, JSON ऑब्जेक्ट में विशेष डेटा खोजना बहुत तेज़ हो जाता है।

हम दो जेनरेट किए गए कॉलम जोड़ते हैं - देश और डाक कोड :

ALTER TABLE Customer
ADD Country as JSON_VALUE(CustomerDetail,'$.customer.address.Country');
ALTER TABLE Customer
ADD PostCode as JSON_VALUE(CustomerDetail,'$.customer.address.PostCode');

CREATE INDEX ix_CountryPostCode on Country(Country asc,PostCode asc);

साथ ही, हम विशिष्ट स्तंभों पर एक समग्र अनुक्रमणिका बनाते हैं। अब, हम क्वेरी को नीचे प्रदर्शित उदाहरण में बदल सकते हैं:

SELECT CustomerID,
  JSON_VALUE(CustomerDetail, '$.customer.customer.Name') AS Name,
  JSON_VALUE(CustomerDetail, '$.customer.customer.Surname') AS Surname,
  JSON_VALUE(CustomerDetail, '$.customer.address.PostCode') AS PostCode,
  JSON_VALUE(CustomerDetail, '$.customer.address."Address Line 1"') + ' '
  + JSON_VALUE(CustomerDetail, '$.customer.address."Address Line 2"') AS Address,
  JSON_QUERY(CustomerDetail, '$.customer.address.Country') AS Country
FROM Customer
WHERE ISJSON(CustomerDetail) > 0
  AND Country = 'Iceland'
  AND PostCode IN (101,102,110,210,220)
  AND Status = 'Active'
ORDER BY JSON_VALUE(CustomerDetail, '$.customer.address.PostCode')

यह केवल आइसलैंड राजधानी क्षेत्र के कुछ हिस्से में सक्रिय ग्राहकों के लिए डेटा पुनर्प्राप्ति को सीमित करता है। यह तरीका पिछली क्वेरी की तुलना में तेज़ और अधिक कुशल है।

निष्कर्ष

कुल मिलाकर, मुश्किलें पैदा करने वाली तालिकाओं (CPU, और संसाधन-भारी क्वेरी) पर वर्चुअल कॉलम या कार्यात्मक अनुक्रमणिका लागू करके, हम समस्याओं को बहुत जल्दी समाप्त कर सकते हैं।

वर्चुअल कॉलम और फंक्शनल इंडेक्स नियमित रिलेशनल टेबल में संग्रहीत जटिल JSON ऑब्जेक्ट्स को क्वेरी करने में मदद कर सकते हैं। हालाँकि, हमें पहले से ही समस्याओं का सावधानीपूर्वक आकलन करने और उसके अनुसार आवश्यक परिवर्तन करने की आवश्यकता है।

कुछ मामलों में, यदि क्वेरी और/या JSON डेटा संरचनाएं बहुत जटिल हैं, तो CPU और संसाधन उपयोग का एक हिस्सा क्वेरी से INSERT / UPDATE प्रक्रियाओं में स्थानांतरित हो सकता है। यह हमें अपेक्षा से कम समग्र CPU और संसाधन बचत देता है। यदि आप समान समस्याओं का अनुभव करते हैं, तो अधिक विस्तृत तालिकाएँ और क्वेरीज़ को फिर से डिज़ाइन करना अपरिहार्य हो सकता है।


  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. टी-एसक्यूएल सेट ऑपरेटर्स पार्ट 2:इंटरसेक्ट और एक्सेप्ट

  4. निष्पादन योजना गुणवत्ता के लिए दस सामान्य खतरे

  5. डेटा स्रोत को कॉन्फ़िगर किए बिना ODBC लिंक्ड सर्वर बनाना