इस विशिष्ट मामले में #temp तालिका के रूप में दो बार से अधिक तालिका चर का उपयोग क्यों किया जा रहा है?


38

मैं यहाँ लेख देख रहा था अस्थाई सारणी बनाम सारणी चर और SQL सर्वर प्रदर्शन पर उनके प्रभाव और SQL सर्वर 2008 पर 2005 के लिए वहाँ दिखाए गए लोगों के लिए इसी तरह के परिणाम को पुन: पेश करने में सक्षम था।

केवल 10 पंक्तियों के साथ संग्रहीत प्रक्रियाओं (नीचे परिभाषाओं) को निष्पादित करते समय, तालिका चर संस्करण बाहर दो बार से अधिक अस्थायी तालिका संस्करण निष्पादित करता है।

मैंने प्रक्रिया कैश को मंजूरी दे दी और दोनों संग्रहीत प्रक्रियाओं को 10,000 बार चलाया और फिर एक और 4 रन के लिए प्रक्रिया को दोहराया। नीचे परिणाम (एमएस प्रति बैच में समय)

T2_Time     V2_Time
----------- -----------
8578        2718      
6641        2781    
6469        2813   
6766        2797
6156        2719

मेरा सवाल है: टेबल चर संस्करण के बेहतर प्रदर्शन का कारण क्या है?

मैंने कुछ जांच की है। उदाहरण के साथ प्रदर्शन काउंटरों को देखते हुए

SELECT cntr_value
from sys.dm_os_performance_counters
where counter_name = 'Temp Tables Creation Rate';

पुष्टि की है कि दोनों ही मामलों में अस्थायी वस्तुओं पहली बार चलाने के बाद कैश्ड किया जा रहा है के रूप में उम्मीद के बजाय हर मंगलाचरण के लिए फिर से खरोंच से बनाया।

इसी तरह का पता लगाने Auto Stats, SP:Recompile, SQL:StmtRecompileप्रोफाइलर में घटनाओं (नीचे स्क्रीनशॉट) से पता चलता है कि इन घटनाओं को केवल एक बार (के पहले मंगलाचरण पर होते हैं #tempतालिका संग्रहीत प्रक्रिया) और अन्य 9,999 फांसी इन घटनाओं में से किसी भी उठाना नहीं है। (तालिका चर संस्करण को इनमें से कोई भी घटना नहीं मिलती है)

निशान

संग्रहीत कार्यविधि के पहले रन का थोड़ा बड़ा ओवरहेड किसी भी तरह से बड़े समग्र अंतर के लिए नहीं कर सकता है, हालांकि यह अभी भी प्रक्रिया कैश को खाली करने और दोनों प्रक्रियाओं को एक बार चलाने के लिए कुछ एमएस लेता है ताकि मुझे या तो आंकड़ों पर विश्वास न हो या recompiles इसका कारण हो सकता है।

आवश्यक डेटाबेस ऑब्जेक्ट बनाएँ

CREATE DATABASE TESTDB_18Feb2012;

GO

USE TESTDB_18Feb2012;

CREATE TABLE NUM 
  ( 
     n INT PRIMARY KEY, 
     s VARCHAR(128) 
  ); 

WITH NUMS(N) 
     AS (SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY $/0) 
         FROM   master..spt_values v1, 
                master..spt_values v2) 
INSERT INTO NUM 
SELECT N, 
       'Value: ' + CONVERT(VARCHAR, N) 
FROM   NUMS 

GO

CREATE PROCEDURE [dbo].[T2] @total INT 
AS 
  CREATE TABLE #T 
    ( 
       n INT PRIMARY KEY, 
       s VARCHAR(128) 
    ) 

  INSERT INTO #T 
  SELECT n, 
         s 
  FROM   NUM 
  WHERE  n%100 > 0 
         AND n <= @total 

  DECLARE @res VARCHAR(128) 

  SELECT @res = MAX(s) 
  FROM   NUM 
  WHERE  n <= @total 
         AND NOT EXISTS(SELECT * 
                        FROM   #T 
                        WHERE  #T.n = NUM.n) 
GO

CREATE PROCEDURE [dbo].[V2] @total INT 
AS 
  DECLARE @V TABLE ( 
    n INT PRIMARY KEY, 
    s VARCHAR(128)) 

  INSERT INTO @V 
  SELECT n, 
         s 
  FROM   NUM 
  WHERE  n%100 > 0 
         AND n <= @total 

  DECLARE @res VARCHAR(128) 

  SELECT @res = MAX(s) 
  FROM   NUM 
  WHERE  n <= @total 
         AND NOT EXISTS(SELECT * 
                        FROM   @V V 
                        WHERE  V.n = NUM.n) 


GO

टेस्ट स्क्रिप्ट

SET NOCOUNT ON;

DECLARE @T1 DATETIME2,
        @T2 DATETIME2,
        @T3 DATETIME2,  
        @Counter INT = 0

SET @T1 = SYSDATETIME()

WHILE ( @Counter < 10000)
BEGIN
EXEC dbo.T2 10
SET @Counter += 1
END

SET @T2 = SYSDATETIME()
SET @Counter = 0

WHILE ( @Counter < 10000)
BEGIN
EXEC dbo.V2 10
SET @Counter += 1
END

SET @T3 = SYSDATETIME()

SELECT DATEDIFF(MILLISECOND,@T1,@T2) AS T2_Time,
       DATEDIFF(MILLISECOND,@T2,@T3) AS V2_Time

प्रोफाइलर ट्रेस इंगित करता है कि आँकड़े केवल #tempएक बार टेबल पर बनाए जाने के बावजूद साफ हो जाते हैं और उसके बाद एक और 9,999 बार फिर से आबाद होते हैं।
मार्टिन स्मिथ

जवाबों:


31

SET STATISTICS IO ONदोनों का आउटपुट समान दिखता है

SET STATISTICS IO ON;
PRINT 'V2'
EXEC dbo.V2 10
PRINT 'T2'
EXEC dbo.T2 10

देता है

V2
Table '#58B62A60'. Scan count 0, logical reads 20
Table 'NUM'. Scan count 1, logical reads 3

Table '#58B62A60'. Scan count 10, logical reads 20
Table 'NUM'. Scan count 1, logical reads 3

T2
Table '#T__ ... __00000000E2FE'. Scan count 0, logical reads 20
Table 'NUM'. Scan count 1, logical reads 3

Table '#T__ ... __00000000E2FE'. Scan count 0, logical reads 20
Table 'NUM'. Scan count 1, logical reads 3

जैसा कि आरोन टिप्पणियों में बताते हैं कि तालिका चर संस्करण के लिए योजना वास्तव में कम कुशल है, क्योंकि दोनों में एक नेस्टेड छोरों की योजना है, dbo.NUMजो #tempतालिका संस्करण पर सूचकांक की तलाश द्वारा संचालित है, जो [#T].n = [dbo].[NUM].[n]अवशिष्ट विधेय के साथ सूचकांक पर तलाश में प्रदर्शन करता है [#T].[n]<=[@total]जबकि तालिका चर। संस्करण @V.n <= [@total]अवशिष्ट विधेय के साथ एक सूचकांक की तलाश करता है @V.[n]=[dbo].[NUM].[n]और इसलिए अधिक पंक्तियों को संसाधित करता है (यही वजह है कि यह योजना बड़ी संख्या में पंक्तियों के लिए खराब प्रदर्शन करती है)

विशिष्ट स्पिड के लिए प्रतीक्षा प्रकारों को देखने के लिए विस्तारित ईवेंट का उपयोग करके इन परिणामों को 10,000 निष्पादन के लिए दिया जाता हैEXEC dbo.T2 10

+---------------------+------------+----------------+----------------+----------------+
|                     |            |     Total      | Total Resource |  Total Signal  |
| Wait Type           | Wait Count | Wait Time (ms) | Wait Time (ms) | Wait Time (ms) |
+---------------------+------------+----------------+----------------+----------------+
| SOS_SCHEDULER_YIELD | 16         | 19             | 19             | 0              |
| PAGELATCH_SH        | 39998      | 14             | 0              | 14             |
| PAGELATCH_EX        | 1          | 0              | 0              | 0              |
+---------------------+------------+----------------+----------------+----------------+

और इन परिणामों के 10,000 निष्पादन के लिए EXEC dbo.V2 10

+---------------------+------------+----------------+----------------+----------------+
|                     |            |     Total      | Total Resource |  Total Signal  |
| Wait Type           | Wait Count | Wait Time (ms) | Wait Time (ms) | Wait Time (ms) |
+---------------------+------------+----------------+----------------+----------------+
| PAGELATCH_EX        | 2          | 0              | 0              | 0              |
| PAGELATCH_SH        | 1          | 0              | 0              | 0              |
| SOS_SCHEDULER_YIELD | 676        | 0              | 0              | 0              |
+---------------------+------------+----------------+----------------+----------------+

तो यह स्पष्ट है कि टेबल मामले PAGELATCH_SHमें वेट की संख्या बहुत अधिक है #temp। मैं विस्तारित इवेंट ट्रेस में प्रतीक्षा संसाधन को जोड़ने के किसी भी तरीके से अवगत नहीं हूं, ताकि मैं आगे चलकर इसकी जांच कर सकूं

WHILE 1=1
EXEC dbo.T2 10

जबकि दूसरे कनेक्शन में मतदान sys.dm_os_waiting_tasks

CREATE TABLE #T(resource_description NVARCHAR(2048))

WHILE 1=1
INSERT INTO #T
SELECT resource_description
FROM sys.dm_os_waiting_tasks
WHERE session_id=<spid_of_other_session> and wait_type='PAGELATCH_SH'

लगभग 15 सेकंड तक चलने के बाद यह निम्नलिखित परिणामों को इकट्ठा कर चुका था

+-------+----------------------+
| Count | resource_description |
+-------+----------------------+
|  1098 | 2:1:150              |
|  1689 | 2:1:146              |
+-------+----------------------+

इन दोनों पेजों को लैच किया जा रहा है (अलग) गैर-संकुल अनुक्रमणिका के tempdb.sys.sysschobjsनाम तालिका 'nc1'और 'nc2'

tempdb.sys.fn_dblogरन के दौरान क्वेरी करना इंगित करता है कि प्रत्येक संग्रहीत कार्यविधि के पहले निष्पादन द्वारा जोड़े गए लॉग रिकॉर्ड की संख्या कुछ परिवर्तनशील थी, लेकिन बाद के निष्पादन के लिए प्रत्येक पुनरावृत्ति द्वारा जोड़ी गई संख्या बहुत सुसंगत और अनुमानित थी। एक बार प्रक्रिया की योजना को पूरा करने के बाद लॉग प्रविष्टियों की संख्या #tempसंस्करण के लिए आवश्यक लगभग आधी हो जाती है ।

+-----------------+----------------+------------+
|                 | Table Variable | Temp Table |
+-----------------+----------------+------------+
| First Run       |            126 | 72 or 136  |
| Subsequent Runs |             17 | 32         |
+-----------------+----------------+------------+

#tempएसपी के टेबल संस्करण के लिए अधिक विस्तार से लेनदेन लॉग प्रविष्टियों को देखते हुए संग्रहीत प्रक्रिया के प्रत्येक बाद के आह्वान में तीन लेनदेन और टेबल चर केवल एक दो का निर्माण होता है।

+---------------------------------+----+---------------------------------+----+
|           #Temp Table                |         @Table Variable              |
+---------------------------------+----+---------------------------------+----+
| CREATE TABLE                    |  9 |                                 |    |
| INSERT                          | 12 | TVQuery                         | 12 |
| FCheckAndCleanupCachedTempTable | 11 | FCheckAndCleanupCachedTempTable |  5 |
+---------------------------------+----+---------------------------------+----+

INSERT/ TVQUERYलेनदेन नाम को छोड़ कर एक कर रहे हैं। इसमें अस्थायी तालिका या तालिका चर प्लस LOP_BEGIN_XACT/ LOP_COMMIT_XACTप्रविष्टियों में सम्मिलित 10 पंक्तियों में से प्रत्येक के लिए लॉग रिकॉर्ड शामिल हैं।

CREATE TABLEलेन-देन ही में प्रकट होता है #Tempसंस्करण और इस प्रकार लग रहा है।

+-----------------+-------------------+---------------------+
|    Operation    |      Context      |    AllocUnitName    |
+-----------------+-------------------+---------------------+
| LOP_BEGIN_XACT  | LCX_NULL          |                     |
| LOP_SHRINK_NOOP | LCX_NULL          |                     |
| LOP_MODIFY_ROW  | LCX_CLUSTERED     | sys.sysschobjs.clst |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.sysschobjs.nc1  |
| LOP_INSERT_ROWS | LCX_INDEX_LEAF    | sys.sysschobjs.nc1  |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.sysschobjs.nc2  |
| LOP_INSERT_ROWS | LCX_INDEX_LEAF    | sys.sysschobjs.nc2  |
| LOP_MODIFY_ROW  | LCX_CLUSTERED     | sys.sysschobjs.clst |
| LOP_COMMIT_XACT | LCX_NULL          |                     |
+-----------------+-------------------+---------------------+

FCheckAndCleanupCachedTempTableलेन-देन दोनों में प्रकट होता है, लेकिन में 6 अतिरिक्त प्रविष्टियां हैं #tempसंस्करण। ये 6 पंक्तियाँ हैं, जिनका उल्लेख किया गया है sys.sysschobjsऔर उनके ऊपर बिल्कुल वैसा ही पैटर्न है।

+-----------------+-------------------+----------------------------------------------+
|    Operation    |      Context      |                AllocUnitName                 |
+-----------------+-------------------+----------------------------------------------+
| LOP_BEGIN_XACT  | LCX_NULL          |                                              |
| LOP_DELETE_ROWS | LCX_NONSYS_SPLIT  | dbo.#7240F239.PK__#T________3BD0199374293AAB |
| LOP_HOBT_DELTA  | LCX_NULL          |                                              |
| LOP_HOBT_DELTA  | LCX_NULL          |                                              |
| LOP_MODIFY_ROW  | LCX_CLUSTERED     | sys.sysschobjs.clst                          |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.sysschobjs.nc1                           |
| LOP_INSERT_ROWS | LCX_INDEX_LEAF    | sys.sysschobjs.nc1                           |
| LOP_DELETE_ROWS | LCX_MARK_AS_GHOST | sys.sysschobjs.nc2                           |
| LOP_INSERT_ROWS | LCX_INDEX_LEAF    | sys.sysschobjs.nc2                           |
| LOP_MODIFY_ROW  | LCX_CLUSTERED     | sys.sysschobjs.clst                          |
| LOP_COMMIT_XACT | LCX_NULL          |                                              |
+-----------------+-------------------+----------------------------------------------+

दोनों लेनदेन में इन 6 पंक्तियों को देखते हुए वे एक ही संचालन के अनुरूप हैं। पहला कॉलम में LOP_MODIFY_ROW, LCX_CLUSTEREDएक अपडेट है । शेष पाँच पंक्तियाँ ऑब्जेक्ट के नाम बदलने से संबंधित हैं। क्योंकि दोनों प्रभावित NCI ( और ) का एक प्रमुख स्तंभ है, यह उन लोगों के लिए डिलीट / इंसर्ट के रूप में किया जाता है, फिर यह क्लस्टर इंडेक्स पर वापस जाता है और अपडेट भी करता है।modify_datesys.objectsnamenc1nc2

ऐसा प्रतीत होता है कि #tempजब संग्रहीत कार्यविधि FCheckAndCleanupCachedTempTableलेन-देन समाप्त हो जाती है, तब टेबल संस्करण के लिए लेन-देन द्वारा किए गए क्लीन अप का हिस्सा कुछ #T__________________________________________________________________________________________________________________00000000E316अलग से आंतरिक नाम जैसे कुछ से अस्थायी तालिका का नाम बदलना #2F4A0079होता है और जब इसे दर्ज किया जाता है, तो CREATE TABLEइसे वापस नामांकित किया जाता है। यह फ्लिप फ़्लॉपिंग नाम एक कनेक्शन को dbo.T2लूप में निष्पादित करते हुए दूसरे में देखा जा सकता है

WHILE 1=1
SELECT name, object_id, create_date, modify_date
FROM tempdb.sys.objects 
WHERE name LIKE '#%'

उदाहरण के परिणाम

स्क्रीनशॉट

अलेक्स द्वारा अभिनीत प्रदर्शन प्रदर्शन अंतर के लिए एक संभावित व्याख्या यह है कि यह अतिरिक्त कार्य है जिसमें सिस्टम तालिकाओं को बनाए रखना tempdbजिम्मेदार है।


एक लूप में दोनों प्रक्रियाओं को चलाकर विजुअल स्टूडियो कोड प्रोफाइलर निम्नलिखित को प्रकट करता है

+-------------------------------+--------------------+-------+-----------+
|           Function            |    Explanation     | Temp  | Table Var |
+-------------------------------+--------------------+-------+-----------+
| CXStmtDML::XretExecute        | Insert ... Select  | 16.93 | 37.31     |
| CXStmtQuery::ErsqExecuteQuery | Select Max         | 8.77  | 23.19     |
+-------------------------------+--------------------+-------+-----------+
| Total                         |                    | 25.7  | 60.5      |
+-------------------------------+--------------------+-------+-----------+

तालिका चर संस्करण सम्मिलित विवरण और उसके बाद के चयन के समय का लगभग 60% खर्च करता है जबकि अस्थायी तालिका आधे से कम है। यह ओपी में दिखाए गए समय के साथ इनलाइन है और ऊपर के निष्कर्ष के साथ कि प्रदर्शन में अंतर समय-समय पर है, जो कार्य निष्पादन में समय व्यतीत होने के कारण सहायक कार्य नहीं कर रहा है।

अस्थायी तालिका संस्करण में "लापता" 75% की ओर योगदान देने वाले सबसे महत्वपूर्ण कार्य हैं

+------------------------------------+-------------------+
|              Function              | Inclusive Samples |
+------------------------------------+-------------------+
| CXStmtCreateTableDDL::XretExecute  | 26.26%            |
| CXStmtDDL::FinishNormalImp         | 4.17%             |
| TmpObject::Release                 | 27.77%            |
+------------------------------------+-------------------+
| Total                              | 58.20%            |
+------------------------------------+-------------------+

फ़ंक्शन को बनाने और जारी करने दोनों के तहत फ़ंक्शन CMEDProxyObject::SetNameको समावेशी नमूना मूल्य के साथ दिखाया गया है 19.6%। जिससे मैं अनुमान लगाता हूं कि अस्थायी तालिका मामले में 39.2% समय पहले वर्णित नामकरण के साथ लिया जाता है।

और टेबल चर संस्करण में सबसे बड़ा अन्य 40% के लिए योगदान कर रहे हैं

+-----------------------------------+-------------------+
|             Function              | Inclusive Samples |
+-----------------------------------+-------------------+
| CTableCreate::LCreate             | 7.41%             |
| TmpObject::Release                | 12.87%            |
+-----------------------------------+-------------------+
| Total                             | 20.28%            |
+-----------------------------------+-------------------+

अस्थायी तालिका प्रोफ़ाइल

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

तालिका चर प्रोफ़ाइल

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


10

डिस्को की आग

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

विशेष रूप से, SQL Server 2019 के लिए इन-मेमोरी सिस्टम टेबल्स को जोड़ने पर पुन: परीक्षण करने का एक सार्थक अवसर लगता है।

मैं कुछ अलग परीक्षण हार्नेस का उपयोग कर रहा हूं, क्योंकि मैं इस मुद्दे पर कुछ और काम करते हुए भाग गया।

परीक्षण, परीक्षण

स्टैक ओवरफ्लो के 2013 संस्करण का उपयोग करना , मेरे पास यह सूचकांक और ये दो प्रक्रियाएं हैं:

सूचकांक:

CREATE INDEX ix_whatever 
    ON dbo.Posts(OwnerUserId) INCLUDE(Score);
GO

अस्थायी तालिका:

    CREATE OR ALTER PROCEDURE dbo.TempTableTest(@Id INT)
    AS
    BEGIN
    SET NOCOUNT ON;

        CREATE TABLE #t(i INT NOT NULL);
        DECLARE @i INT;

        INSERT #t ( i )
        SELECT p.Score
        FROM dbo.Posts AS p
        WHERE p.OwnerUserId = @Id;

        SELECT @i = AVG(t.i)
        FROM #t AS t;

    END;
    GO 

तालिका चर:

    CREATE OR ALTER PROCEDURE dbo.TableVariableTest(@Id INT)
    AS
    BEGIN
    SET NOCOUNT ON;

        DECLARE @t TABLE (i INT NOT NULL);
        DECLARE @i INT;

        INSERT @t ( i )
        SELECT p.Score
        FROM dbo.Posts AS p
        WHERE p.OwnerUserId = @Id;

        SELECT @i = AVG(t.i)
        FROM @t AS t;

    END;
    GO 

किसी भी संभावित ASYNC_NETWORK_IO प्रतीक्षा करने से रोकने के लिए , मैं आवरण प्रक्रियाओं का उपयोग कर रहा हूं।

CREATE PROCEDURE #TT AS
SET NOCOUNT ON;
    DECLARE @i INT = 1;
    DECLARE @StartDate DATETIME2(7) = SYSDATETIME();

    WHILE @i <= 50000
        BEGIN
            EXEC dbo.TempTableTest @Id = @i;
            SET @i += 1;
        END;
    SELECT DATEDIFF(MILLISECOND, @StartDate, SYSDATETIME()) AS [ElapsedTimeMilliseconds];
GO

CREATE PROCEDURE #TV AS
SET NOCOUNT ON;
    DECLARE @i INT = 1;
    DECLARE @StartDate DATETIME2(7) = SYSDATETIME();

    WHILE @i <= 50000
        BEGIN
            EXEC dbo.TableVariableTest @Id = @i;
            SET @i += 1;
        END;
    SELECT DATEDIFF(MILLISECOND, @StartDate, SYSDATETIME()) AS [ElapsedTimeMilliseconds];
GO

SQL सर्वर 2017

2014 और 2016 के बाद से मूल रूप से इस बिंदु पर RELICS हैं, मैं 2017 के साथ अपना परीक्षण शुरू कर रहा हूं। इसके अलावा, संक्षिप्तता के लिए, मैं परफ्यूव के साथ कोड को प्रोफाइल करने के लिए सही कूद रहा हूं । वास्तविक जीवन में, मैंने वेट, लैच, स्पिनलॉक, क्रेजी ट्रेस झंडे और अन्य सामान को देखा।

कोड को प्रोफाइल करना एकमात्र ऐसी चीज है जिसने ब्याज के बारे में कुछ भी बताया।

समय का अंतर:

  • अस्थायी तालिका: 17891 एमएस
  • टेबल चर: 5891 एमएस

अभी भी एक बहुत स्पष्ट अंतर, एह? लेकिन अब SQL सर्वर क्या मार रहा है?

पागल

अलग नमूनों में शीर्ष दो को देखते हुए, हम देखते हैं sqlminऔर sqlsqllang!TCacheStore<CacheClockAlgorithm>::GetNextUserDataInHashBucketदो सबसे बड़े अपराधी हैं।

पागल

कॉल स्टैक्स में नामों को देखते हुए, सफाई और आंतरिक रूप से नाम बदलने वाली टेम्‍प टेबल को टेम्‍पर्ड टेबल कॉल बनाम टेबल टेबल कॉल में सबसे बड़ा समय बेकार लगता है।

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

SET STATISTICS IO ON;
DECLARE @t TABLE(id INT);
SELECT * FROM @t AS t;

तालिका '# B98CE339'। स्कैन गिनती 1

टेबल वैरिएबल टेस्ट के लिए कॉल स्टैक्स के माध्यम से देखना मुख्य अपराधियों में से किसी को भी नहीं दिखाता है:

पागल

SQL सर्वर 2019 (वेनिला)

ठीक है, इसलिए यह अभी भी SQL सर्वर 2017 में एक समस्या है, क्या 2019 में कुछ भी अलग है?

सबसे पहले, यह दिखाने के लिए कि मेरी आस्तीन में कुछ नहीं है:

SELECT c.name,
       c.value_in_use,
       c.description
FROM sys.configurations AS c
WHERE c.name = 'tempdb metadata memory-optimized';

पागल

समय का अंतर:

  • अस्थायी तालिका: 15765 एमएस
  • टेबल चर: 7250 एमएस

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

परफ्यूव में अंतर को देखते हुए, यह थोड़ा बदल गया है - sqlmin अब नहीं है - लेकिन sqllang!TCacheStore<CacheClockAlgorithm>::GetNextUserDataInHashBucketहै।

पागल

SQL सर्वर 2019 (इन-मेमोरी टेम्पेडब सिस्टम टेबल)

मेमोरी सिस्टम टेबल चीज में इस नए के बारे में क्या? हम्म? इसके साथ ही सुपर?

चलो इसे चालू करें!

EXEC sys.sp_configure @configname = 'advanced', 
                      @configvalue = 1  
RECONFIGURE;

EXEC sys.sp_configure @configname = 'tempdb metadata memory-optimized', 
                      @configvalue = 1 
RECONFIGURE;

ध्यान दें कि इसमें एक SQL सर्वर को किक करने की आवश्यकता होती है, इसलिए मुझे इस प्यारे शुक्रवार दोपहर में SQL को रीबूट करते समय क्षमा करें।

अब चीजें अलग दिखती हैं:

SELECT c.name,
       c.value_in_use,
       c.description
FROM sys.configurations AS c
WHERE c.name = 'tempdb metadata memory-optimized';

SELECT *, 
       OBJECT_NAME(object_id) AS object_name, 
       @@VERSION AS sql_server_version
FROM tempdb.sys.memory_optimized_tables_internal_attributes;

पागल

समय का अंतर:

  • अस्थायी तालिका: 11638 एमएस
  • टेबल चर: 7403 एमएस

अस्थायी तालिकाओं ने लगभग 4 सेकंड बेहतर किया! यह कुछ है।

मुझे कुछ पसंद है।

इस बार, परफ़ेक्ट फ़र्क बहुत दिलचस्प नहीं है। कंधे से कंधा मिलाकर, यह ध्यान रखना दिलचस्प है कि बोर्ड कितने समय के करीब है:

पागल

इस अंतर में एक दिलचस्प बिंदु कॉल हैं hkengine!, जो स्पष्ट हो सकता है क्योंकि हेकोटन-ईश विशेषताएं अब उपयोग में हैं।

पागल

जहां तक ​​अंतर में शीर्ष दो वस्तुओं की बात है, मैं इसमें से बहुत कुछ नहीं कर सकता ntoskrnl!?:

पागल

या sqltses!CSqlSortManager_80::GetSortKey, लेकिन वे यहाँ देखने के लिए Smrtr Ppl ™ के लिए हैं:

पागल

ध्यान दें कि एक अनिर्दिष्ट है और निश्चित रूप से उत्पादन के लिए सुरक्षित नहीं है, इसलिए कृपया इसका उपयोग न करें स्टार्टअप ट्रेस फ्लैग का उपयोग आप अतिरिक्त टेम्पल टेबल सिस्टम ऑब्जेक्ट (sysrowsets, sysallocunits, और sysseobjvalues) इन-मेमोरी सुविधा में शामिल कर सकते हैं, लेकिन यह इस मामले में निष्पादन समय में ध्यान देने योग्य अंतर नहीं आया।

बढ़ाना

यहां तक ​​कि SQL सर्वर के नए संस्करणों में, टेबल वेरिएबल्स के लिए उच्च आवृत्ति कॉल टेम्प टेबल के लिए उच्च आवृत्ति कॉल की तुलना में बहुत तेज है।

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

यह SQL Server 2019 में इन-मेमोरी सिस्टम टेबल सक्षम के साथ एक निकट कॉल है, लेकिन कॉल आवृत्ति अधिक होने पर टेबल चर अभी भी बेहतर प्रदर्शन करते हैं।

बेशक, वपिंग ऋषि एक बार पेशी के रूप में: "जब योजना पसंद नहीं होती है तो टेबल चर का उपयोग करें"।


नाइस - क्षमा करें, मुझे याद आया कि आपने अपने "डिबगिंग" ब्लॉग पोस्ट में लिंक का अनुसरण करने तक इसका उत्तर जोड़ा
मार्टिन स्मिथ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.