गणना किए गए कॉलम की गणना कब की जाती है?


29

गणना किए गए कॉलम के लिए मान कब निर्धारित किए जाते हैं?

  • मान कब प्राप्त किया जाता है?
  • मूल्य कब बदला जाता है?
  • फिर कभी?

मुझे लग रहा है कि यह एक नौसिखिया सवाल है क्योंकि मुझे अपनी खोजों में कुछ भी नहीं मिल रहा है।

जवाबों:


19

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

कृपया महान व्याख्या और प्रमाण के लिए हारून का जवाब देखें ।

मीनल दवे ने इसका भी विस्तार से वर्णन किया है और उनकी श्रृंखला में भंडारण का प्रमाण दिखाया है:

एसक्यूएल सर्वर - कम्प्यूटेड कॉलम - निजीकृत और भंडारण


6
अगर वे कायम हैं तो क्या होगा लेकिन क्वेरी प्लान एक इंडेक्स का उपयोग करता है जो उस कॉलम को कवर नहीं करता है? मुझे यकीन नहीं है कि क्या आपको एक लुक मिलेगा या यदि यह सिर्फ मक्खी पर गणना करेगा और वर्तमान में इसका परीक्षण नहीं कर सकता है।
मार्टिन स्मिथ

1
@ मेरीटीन आप सही हैं, मेरे परीक्षण में SQL सर्वर ने एक लुकअप पर फिर से कंप्यूटिंग को चुना।
हारून बर्ट्रेंड

34

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

मान लें कि हमारे पास यह फ़ंक्शन है:

CREATE FUNCTION dbo.mask(@x varchar(32))
RETURNS varchar(32) WITH SCHEMABINDING
AS
BEGIN
  RETURN (SELECT 'XX' + SUBSTRING(@x, 3, LEN(@x)-4) + 'XXXX');
END
GO

और यह तालिका:

CREATE TABLE dbo.Floobs
(
  FloobID int IDENTITY(1,1),
  Name varchar(32),
  MaskedName AS CONVERT(varchar(32), dbo.mask(Name)),
  CONSTRAINT pk_Floobs PRIMARY KEY(FloobID),
  CONSTRAINT ck_Name CHECK (LEN(Name)>=8)
);
GO

आइए sys.dm_exec_function_stats, सम्मिलित करने से पहले और बाद में (और फिर SQL SQL Server 2016 और Azure SQL डेटाबेस में नया) चेक करें:

SELECT o.name, s.execution_count
FROM sys.dm_exec_function_stats AS s
INNER JOIN sys.objects AS o
ON o.[object_id] = s.[object_id]
WHERE s.database_id = DB_ID();

INSERT dbo.Floobs(Name) VALUES('FrankieC');

SELECT o.name, s.execution_count
FROM sys.dm_exec_function_stats AS s
INNER JOIN sys.objects AS o
ON o.[object_id] = s.[object_id]
WHERE s.database_id = DB_ID();

SELECT * FROM dbo.Floobs;

SELECT o.name, s.execution_count
FROM sys.dm_exec_function_stats AS s
INNER JOIN sys.objects AS o
ON o.[object_id] = s.[object_id]
WHERE s.database_id = DB_ID();

मुझे सम्मिलित होने पर कोई फ़ंक्शन कॉल नहीं दिखता, केवल चयन पर।

अब, टेबल्स को छोड़ें और इसे फिर से करें, इस बार कॉलम को बदलकर PERSISTED:

DROP TABLE dbo.Floobs;
GO
DROP FUNCTION dbo.mask;
GO

...
  MaskedName AS CONVERT(varchar(32), dbo.mask(Name)) PERSISTED,
...

और मैं इसके विपरीत होता हुआ देखता हूं: मुझे प्रविष्टि पर लॉग ऑन मिला है, लेकिन चयन पर नहीं।

उपयोग करने के लिए SQL सर्वर का एक आधुनिक पर्याप्त संस्करण नहीं है sys.dm_exec_function_stats? कोई चिंता नहीं, यह निष्पादन योजनाओं में भी कब्जा कर लिया है

गैर-जारी संस्करण के लिए, हम केवल संदर्भित फ़ंक्शन को चुन सकते हैं:

यहां छवि विवरण दर्ज करें

यहां छवि विवरण दर्ज करें

जबकि जारी संस्करण केवल डालने पर होने वाली गणना दर्शाता है:

यहां छवि विवरण दर्ज करें

यहां छवि विवरण दर्ज करें

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

CREATE INDEX x ON dbo.Floobs(Name);
GO

INSERT dbo.Floobs(name) 
  SELECT LEFT(name, 32) 
  FROM sys.all_columns 
  WHERE LEN(name) >= 8;

अब, हम एक क्वेरी चलाएंगे जो सूचकांक का उपयोग करता है (वास्तव में यह इस विशेष मामले में डिफ़ॉल्ट रूप से सूचकांक का उपयोग करता है, यहां तक ​​कि जहां भी एक खंड के बिना):

SELECT * FROM dbo.Floobs WITH (INDEX(x))
  WHERE Name LIKE 'S%';

मैं फ़ंक्शन आँकड़ों में अतिरिक्त निष्पादन देखता हूँ, और योजना झूठ नहीं बोलती है:

यहां छवि विवरण दर्ज करें

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


बहुत सराहना की, मैंने कंप्यूटिंग परिणामों में इंजन के व्यवहार पर कभी सवाल नहीं उठाया।
आर्थर डी

8
@AththurD यह प्रत्येक विकल्प की अनुमानित लागतों पर आधारित एक आशावादी निर्णय है (अधिकतर), एक अन्य प्रश्न का मेरा उत्तर यहां देखें।
पॉल व्हाइट GoFundMonica कहते

-1

इस प्रश्न का उत्तर सही मायने में "यह निर्भर करता है।" मैं अभी एक उदाहरण भर में चला आया हूं, जहां SQL सर्वर लगातार गणना किए गए कॉलम पर सूचकांक का उपयोग कर रहा है, लेकिन यह अभी भी फ़ंक्शन कर रहा है, जैसे कि मानों को कभी भी शुरू करने के लिए जारी नहीं किया गया था। इसे स्तंभ के डेटा प्रकार ( nvarchar(37)) या संभवतः तालिका के आकार (लगभग 7 मिलियन पंक्तियों) के साथ करना पड़ सकता है , लेकिन SQL सर्वर ने persistedकीवर्ड को अनदेखा करने का निर्णय लिया , यह इस विशेष उदाहरण में प्रकट होता है।

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

लगातार स्तंभ के साथ तालिका बनाना फंक्शन प्लान फंक्शन दिखा रहा है

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