हर बैच एक संकलन का कारण बनता है


10

हमारे पास थर्ड पार्टी एप्लिकेशन है जो बैचों में टी-एसक्यूएल स्टेटमेंट भेजता है।

डेटाबेस को SQL Server 2016 एंटरप्राइज़ SP1 CU7, 16 कोर और 256GB मेमोरी पर होस्ट किया गया है। Ad-Hoc का अनुकूलन सक्षम है।

यह उन प्रश्नों का एक डमी उदाहरण है जिन्हें निष्पादित किया जा रहा है:

exec sp_executesql N'
IF @@TRANCOUNT = 0 SET TRANSACTION ISOLATION LEVEL SNAPSHOT

select field1, field2 from table1 where field1=@1
option(keep plan, keepfixed, loop join)

select field3, field4 from table2 where field3=@1
option(keep plan, keepfixed, loop join)', N'@1 nvarchar(6)',@1=N'test'

जब मैं डेटाबेस की निगरानी करता हूं और मैं बैचों / सेकंड और संकलन / सेकंड को देखता हूं, तो मुझे लगता है कि वे हमेशा समान हैं। भारी भार के तहत, यह 1000 बैच / सेकंड और 1000 संकलन / सेकंड हो सकता है। औसत लोड के तहत, 150 बैच / सेकंड हैं।

मैं हाल ही में संकलित योजनाओं के लिए क्वेरी कैश का विश्लेषण करता हूं:

SELECT TOP (1000) qs.creation_time
    , DatabaseName = DB_NAME(st.dbid)
    , qs.execution_count
    , st.text
    , qs.plan_handle
    , qs.sql_handle
    , qs.query_hash 
FROM sys.dm_exec_query_stats qs
    CROSS APPLY sys.dm_exec_sql_text(qs.plan_handle) AS st
ORDER BY creation_time DESC;

जब मैं क्वेरी के ऊपर चलता हूं तो मुझे केवल 10-20 नई क्वेरी योजनाएं / सेकंड दिखाई देते हैं।

यह ऐसा है जैसे हर sp_executesqlकॉल एक संकलन को ट्रिगर करता है लेकिन क्वेरीप्लेन को कैश नहीं किया जाता है।

संकलन / सेकंड के बराबर बैच / सेक का कारण क्या हो सकता है?

जवाबों:


12

यह ऐसा है जैसे हर sp_executesqlकॉल एक संकलन को ट्रिगर करता है लेकिन क्वेरी प्लान कैश नहीं किया जाता है।

SQL सर्वर केवल कॉल के साथ बैचों के लिए एक क्वेरी योजना कैश नहीं करता हैsp_executesql । कैश्ड प्लान के बिना, हर बार एक संकलन होता है। यह डिजाइन द्वारा, और अपेक्षित है।

SQL सर्वर संकलन करने के लिए कम लागत के साथ कैशिंग बैच से बचा जाता है। क्या है और कैश नहीं है का विवरण कई वर्षों में बदल गया है। ट्रेस ध्वज 2861 के लिए मेरा जवाब देखें और विवरण के लिए वास्तव में 'शून्य-लागत' योजना का क्या मतलब है।

संक्षेप में, पुन: उपयोग की संभावना (विशिष्ट पैरामीटर मान सहित) छोटी है, और sp_executesqlकॉल करने वाले तदर्थ पाठ को संकलित करने की लागत बहुत कम है। द्वारा उत्पादित आंतरिक पैरामीटर बैच sp_executesqlनिश्चित रूप से कैश और पुन: उपयोग किया जाता है - यह इसका मूल्य है। विस्तारित संग्रहीत प्रक्रिया sp_executesqlस्वयं भी कैश की जाती है।

कैश्ड और पुन: उपयोग किए जाने के लिए, sp_executesqlस्टेटमेंट को एक बड़े बैच का हिस्सा होना चाहिए जिसे कैशिंग के लायक माना जाता है। उदाहरण के लिए:

-- Show compilation counter
SELECT
    DOPC.[object_name],
    DOPC.cntr_value
FROM sys.dm_os_performance_counters AS DOPC
WHERE
    DOPC.counter_name = N'SQL Compilations/sec'
GO
-- This is only here to make the batch worth caching
DECLARE @TC integer =
(
    SELECT TOP (1) @@TRANCOUNT 
    FROM master.dbo.spt_values AS SV
);

-- Example call we are testing
-- (use anything for the inner query, this example uses the Stack Overflow database
EXECUTE sys.sp_executesql 
    N'SELECT LT.Type FROM dbo.LinkTypes AS LT WHERE LT.Id = @id;', 
    N'@id int', 
    @id = 1;
GO
-- Show compilation counter again
SELECT
    DOPC.[object_name],
    DOPC.cntr_value
FROM sys.dm_os_performance_counters AS DOPC
WHERE
    DOPC.counter_name = N'SQL Compilations/sec'

उस कोड को कई बार चलाएं। हालांकि, पहली बार कई संकलन अपेक्षित रूप से रिपोर्ट किए गए हैं। दूसरी बार, कोई संकलित रिपोर्ट नहीं की जाती है, जब तक optimize for ad hoc workloadsकि सक्षम नहीं किया जाता है (इसलिए केवल एक संकलित योजना स्टब को कैश किया जाता है)। तीसरी बार, किसी भी मामले में किसी भी संकलन की रिपोर्ट नहीं की जाती है, क्योंकि किसी भी ठूंठ को पूरी तरह से कैच किए गए तदर्थ योजना में पदोन्नत किया जाता है।

DECLARE @TCयह देखने के लिए कथन को हटा दें कि कथन को इसके sys.sp_executesqlबिना कभी भी कैश नहीं किया गया है, चाहे वह कितनी भी बार निष्पादित हो।

संबंधित योजना कैश प्रविष्टियों को देखें:

-- Show cached plans
SELECT
    DECP.refcounts,
    DECP.usecounts,
    DECP.size_in_bytes,
    DECP.cacheobjtype,
    DECP.objtype,
    DECP.plan_handle,
    DECP.parent_plan_handle,
    DEST.[text]
FROM sys.dm_exec_cached_plans AS DECP
CROSS APPLY sys.dm_exec_sql_text(DECP.plan_handle) AS DEST
WHERE 
    DEST.[text] LIKE N'%sp_executesql%'
    AND DEST.[text] NOT LIKE N'%dm_exec_cached_plans%';

संबंधित प्रश्नोत्तर: क्या प्रत्येक बार ट्रिगर संकलित होता है?


11

आप अनुमान लगा सकता है क्या आप के लिए प्रदर्शन मॉनिटर और गतिविधि मॉनिटर में देखते हैं SQL Compilations/secऔर Batch Requests/sec, एक परीक्षण के रूप में अलग क्वेरी विंडो में कुछ बैचों चलाते समय विवरण नीचे दिया गया।

क्वेरी विंडो 1:

DECLARE @t1 datetime;
DECLARE @t2 datetime;
DECLARE @CompVal1 int;
DECLARE @CompVal2 int;
DECLARE @ReCompVal1 int;
DECLARE @ReCompVal2 int;
DECLARE @BatchVal1 int;
DECLARE @BatchVal2 int;
DECLARE @ElapsedMS decimal(10,2);

SELECT @t1 = GETDATE()
    , @CompVal1 = (
        SELECT spi.cntr_value
        FROM sys.sysperfinfo spi
        WHERE spi.counter_name = 'SQL Compilations/sec                                                                                                            '
        )
    , @ReCompVal1 = (
        SELECT spi.cntr_value
        FROM sys.sysperfinfo spi
        WHERE spi.counter_name = 'SQL Re-Compilations/sec                                                                                                         '
        )
    , @BatchVal1 = (
        SELECT spi.cntr_value
        FROM sys.sysperfinfo spi
        WHERE spi.counter_name = 'Batch Requests/sec                                                                                                              '
        );

WAITFOR DELAY '00:00:10.000';

SELECT @t2 = GETDATE()
    , @CompVal2 = (
        SELECT spi.cntr_value
        FROM sys.sysperfinfo spi
        WHERE spi.counter_name = 'SQL Compilations/sec                                                                                                            '
        )
    , @ReCompVal2 = (
        SELECT spi.cntr_value
        FROM sys.sysperfinfo spi
        WHERE spi.counter_name = 'SQL Re-Compilations/sec                                                                                                         '
        )
    , @BatchVal2 = (
        SELECT spi.cntr_value
        FROM sys.sysperfinfo spi
        WHERE spi.counter_name = 'Batch Requests/sec                                                                                                              '
        );

SET @ElapsedMS = DATEDIFF(MILLISECOND, @t1, @t2);
SELECT  ElapsedTimeMS = @ElapsedMS
    , [SQL Compilations/sec] = (@CompVal2 - @CompVal1) / @ElapsedMS * 1000 
    , [SQL Recompilations/sec] = (@ReCompVal2 - @ReCompVal1) / @ElapsedMS * 1000
    , [Batch Requests/sec] = (@BatchVal2 - @BatchVal1) / @ElapsedMS * 1000;

क्वेरी विंडो 2 में, उपरोक्त कोड के चलने के दौरान निम्नलिखित को चलाएँ। कोड केवल 100 T-SQL बैच निष्पादित करता है:

EXEC sys.sp_executesql N'SELECT TOP(1) o.name FROM sys.objects o;';
GO 100

यदि आप क्वेरी विंडो 1 पर वापस जाते हैं तो आपको कुछ इस तरह दिखाई देगा:

╔═══════════════╦══════════════════════╦══════════ ══════════════╦════════════════════╗
Ations ElapsedTimeMS Comp एसक्यूएल संकलनों / सेकंड omp एसक्यूएल Recompilations / सेकंड atch बैच अनुरोध और सेकंड Time
╠═══════════════╬══════════════════════╬══════════ ══════════════╬════════════════════╣
║ 10020.00 79 10.07984031000 00000 0.00000000000 79 10.07984031000 ║
╚═══════════════╩══════════════════════╩══════════ ══════════════╩════════════════════╝

यदि हम इस प्रश्न को देखते हैं:

SELECT dest.text
    , deqs.execution_count
FROM sys.dm_exec_query_stats deqs
    CROSS APPLY sys.dm_exec_sql_text(deqs.plan_handle) dest
WHERE dest.text LIKE 'SELECT TOP(1)%'

हम पुष्टि कर सकते हैं कि परीक्षण क्वेरी के 100 निष्पादन थे।

उपरोक्त परिणामों में, आप देख सकते हैं कि जब भी sp_executesqlकथन निष्पादित होता है , तब हम संकलन कर रहे हैं । उस योजना को निश्चित रूप से कैश किया जा रहा है, फिर भी हम इसके लिए एक संकलन देखते हैं; क्या देता है?

माइक्रोसॉफ्ट डॉक्स के बारे में यह कहना sp_executesql:

sp_executesql में बैचों, नामों के दायरे और डेटाबेस के संदर्भ में EXECUTE जैसा ही व्यवहार होता है। Sp_executesql @stmt पैरामीटर में Transact-SQL स्टेटमेंट या बैच तब तक संकलित नहीं किया जाता है जब तक कि sp_executesql स्टेटमेंट निष्पादित न हो जाए। @Stmt की सामग्री तब संकलित की गई निष्पादन योजना के रूप में संकलित और निष्पादित की जाती है, जिसे sp_executesql कहा जाता है।

इसलिए, प्रत्येक बार चलने वाले समय में sp_executesql खुद को संकलित किया जा रहा है, भले ही कमांड पाठ की योजना पहले से ही योजना कैश में हो। @PaWWite अपने जवाब में दिखाती है कि sp_executesql के अधिकांश कॉल वास्तव में कैश नहीं होते हैं।

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