जवाबों:
यह इस बात पर निर्भर करता है कि आप गणना किए गए कॉलम को कैसे परिभाषित करते हैं। एक PERSISTED
गणना किए गए कॉलम की गणना की जाएगी और फिर तालिका के अंदर डेटा के रूप में संग्रहीत किया जाएगा। यदि आप कॉलम को परिभाषित नहीं करते हैं PERSISTED
, तो यह गणना की जाएगी कि आपकी क्वेरी कब चलती है।
कृपया महान व्याख्या और प्रमाण के लिए हारून का जवाब देखें ।
मीनल दवे ने इसका भी विस्तार से वर्णन किया है और उनकी श्रृंखला में भंडारण का प्रमाण दिखाया है:
अपने आप को साबित करना बहुत आसान है। हम एक गणना किए गए कॉलम के साथ एक तालिका बना सकते हैं जो एक स्केलर उपयोगकर्ता-परिभाषित फ़ंक्शन का उपयोग करता है, और फिर एक अद्यतन और चयन से पहले और बाद में योजनाओं और फ़ंक्शन के आँकड़ों की जाँच करें और देखें कि कब एक निष्पादन रिकॉर्ड किया जाता है।
मान लें कि हमारे पास यह फ़ंक्शन है:
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 सर्वर ने सोचा कि लुकअप करने की तुलना में मूल्यों को फिर से गणना करना सस्ता होगा। यह कई कारकों के कारण बदल सकता है, इसलिए इस पर भरोसा न करें। और यह किसी भी दिशा में हो सकता है या नहीं, उपयोगकर्ता द्वारा परिभाषित फ़ंक्शन का उपयोग किया जाता है या नहीं; मैंने केवल इसका उपयोग यहां किया क्योंकि इसने इसे चित्रित करने में बहुत आसान बना दिया।
इस प्रश्न का उत्तर सही मायने में "यह निर्भर करता है।" मैं अभी एक उदाहरण भर में चला आया हूं, जहां SQL सर्वर लगातार गणना किए गए कॉलम पर सूचकांक का उपयोग कर रहा है, लेकिन यह अभी भी फ़ंक्शन कर रहा है, जैसे कि मानों को कभी भी शुरू करने के लिए जारी नहीं किया गया था। इसे स्तंभ के डेटा प्रकार ( nvarchar(37)
) या संभवतः तालिका के आकार (लगभग 7 मिलियन पंक्तियों) के साथ करना पड़ सकता है , लेकिन SQL सर्वर ने persisted
कीवर्ड को अनदेखा करने का निर्णय लिया , यह इस विशेष उदाहरण में प्रकट होता है।
इस मामले में, मेज पर प्राथमिक कुंजी ट्रांज़ैक्शन है जो एक संगणित और निरंतर कॉलम है। निष्पादन योजना एक सूचकांक स्कैन उत्पन्न कर रही है और केवल 7 मिलियन पंक्तियों के साथ एक तालिका में इस सरल क्वेरी को चलाने के लिए 2-3 मिनट से अधिक समय लग रहा है क्योंकि फ़ंक्शन हर पंक्ति पर फिर से चलाया जाता है और मानों में बने रहने के लिए प्रकट नहीं होता है अनुक्रमणिका।