it-swarm.asia

لماذا استخدام متغير جدول أسرع مرتين من جدول #temp في هذه الحالة المحددة؟

كنت أنظر إلى المقالة هنا الجداول المؤقتة في مقابل متغيرات الجدول وتأثيرها على أداء خادم SQL وفي SQL Server 2008 كان قادرًا على إعادة إنتاج نتائج مماثلة لتلك المعروضة لعام 2005.

عند تنفيذ الإجراءات المخزنة (التعريفات أدناه) بعشرة صفوف فقط ، يقوم إصدار متغير الجدول بتنفيذ إصدار الجدول المؤقت بأكثر من مرتين.

قمت بمسح ذاكرة التخزين المؤقت للإجراء وقمت بتشغيل كل من الإجراءات المخزنة 10000 مرة ثم كررت العملية لمدة 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_ الأحداث في Profiler (لقطة الشاشة أدناه) تظهر أن هذه الأحداث تحدث مرة واحدة فقط (عند الاستدعاء الأول لـ #temp الإجراء المخزن في الجدول) وعمليات الإعدام الأخرى البالغ عددها 9999 لا تثير أيًا من هذه الأحداث. (لا يحصل إصدار متغير الجدول على أي من هذه الأحداث)

Trace

لا يمكن للنفقات العامة الأكبر قليلاً من التشغيل الأول للإجراء المخزن أن تحسب بأي حال من الأحوال الاختلاف العام الكبير ، ومع ذلك ، لا يزال الأمر يستغرق بضع مللي ثانية فقط لمسح ذاكرة التخزين المؤقت للإجراء وتشغيل كلا الإجراءين مرة واحدة لذلك لا أعتقد أن أيًا من الإحصائيات أو يمكن أن يكون السبب 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
37
Martin Smith

يبدو ناتج 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] وبالتالي يعالج المزيد من الصفوف (وهذا هو السبب في أن أداء هذه الخطة ضعيف جدًا لعدد أكبر من الصفوف)

استخدام الأحداث الموسعة لإلقاء نظرة على أنواع الانتظار الخاصة بالشبكة المحددة يعطي هذه النتائج لـ 10000 عملية تنفيذ 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              |
+---------------------+------------+----------------+----------------+----------------+

وهذه النتائج لـ 10000 عملية إعدام 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 من SP كل استدعاء لاحق للإجراء المخزن ينشئ ثلاث معاملات ومتغير الجدول واحد فقط اثنين.

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

المعاملات INSERT/TVQUERY متطابقة باستثناء الاسم. يحتوي هذا على سجلات السجل لكل من الصفوف العشرة المدرجة في الجدول المؤقت أو متغير الجدول بالإضافة إلى إدخالات LOP_BEGIN_XACT/LOP_COMMIT_XACT.

تظهر المعاملة 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. هذه هي الصفوف الستة التي تشير إلى 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          |                                              |
+-----------------+-------------------+----------------------------------------------+

بالنظر إلى هذه الصفوف الستة في كلتا العمليتين ، فإنها تتوافق مع نفس العمليات. أول LOP_MODIFY_ROW, LCX_CLUSTERED هو تحديث لعمود modify_date في sys.objects. تتعلق الصفوف الخمسة المتبقية بإعادة تسمية الكائنات. لأن name هو عمود رئيسي لكل من NCIs المتأثرة (nc1 و nc2) يتم تنفيذ ذلك كحذف/إدراج لهؤلاء ثم العودة إلى فهرس المجموعة و بتحديث ذلك أيضًا.

يبدو أنه بالنسبة لإصدار الجدول #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 '#%'

نتائج المثال

Screenshot

لذا فإن أحد التفسيرات المحتملة لفرق الأداء الملحوظ كما ألمح إليه أليكس هو أن هذا العمل الإضافي الذي يحافظ على جداول النظام في tempdb هو المسؤول.


تشغيل كلا الإجراءين في حلقة يكشف المحلل البرمجي لـ Visual Studio ما يلي

+-------------------------------+--------------------+-------+-----------+
|           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٪ من الوقت في تنفيذ عبارة الإدراج والاختيار اللاحق في حين أن الجدول المؤقت أقل من نصف ذلك. هذا يتماشى مع التوقيت المبين في OP ومع الاستنتاج أعلاه أن الفرق في الأداء يرجع إلى الوقت الذي يقضيه في أداء عمل إضافي ليس بسبب الوقت الذي يقضيه في تنفيذ الاستعلام نفسه.

أهم الوظائف التي تساهم في "مفقود" 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%            |
+-----------------------------------+-------------------+

ملف تعريف الجدول المؤقت

enter image description here

ملف تعريف متغير الجدول

enter image description here

31
Martin Smith

ديسكو جحيم

نظرًا لأن هذا سؤال قديم ، فقد قررت إعادة النظر في المشكلة في الإصدارات الأحدث من SQL Server لمعرفة ما إذا كان نفس ملف تعريف الأداء لا يزال موجودًا ، أو إذا تغيرت الخصائص على الإطلاق.

على وجه التحديد ، تبدو إضافة جداول النظام في الذاكرة لـ SQL Server 2019 مناسبة جديرة بإعادة الاختبار.

أستخدم حزام اختبار مختلف قليلاً ، حيث واجهت هذه المشكلة أثناء العمل على شيء آخر.

اختبار اختبار

باستخدام إصدار 2013 من Stack Overflow ، لدي هذا الفهرس وهذان الإجراءان:

فهرس:

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 Server 2017

نظرًا لأن عامي 2014 و 2016 هما RELICS بشكل أساسي في هذه المرحلة ، فقد بدأت اختباري مع عام 2017. وأيضًا ، للإيجاز ، أقفز بشكل صحيح لتحديد ملف التعليمات البرمجية باستخدام Perfview . في الحياة الواقعية ، نظرت إلى الانتظار ، والمزالج ، و spinlocks ، وأعلام التتبع المجنونة ، وغيرها من الأشياء.

التنميط رمز هو الشيء الوحيد الذي كشف عن أي شيء من الفائدة.

فرق الوقت:

  • جدول درجة الحرارة: 17891 مللي ثانية
  • متغير الجدول: 5891 مللي ثانية

هل ما زال هناك فرق واضح جدا؟ ولكن ما هو ضرب خادم SQL الآن؟

NUTS

بالنظر إلى أكبر زيادات في العينات المختلفة ، نرى sqlmin و sqlsqllang!TCacheStore<CacheClockAlgorithm>::GetNextUserDataInHashBucket هما أكبر جناة.

NUTS

إذا حكمنا من خلال الأسماء في مكدسات المكالمات ، يبدو أن تنظيف الجداول المؤقتة وإعادة تسميتها داخليًا هو أكبر وقت تمتص فيه مكالمة الجدول المؤقت مقابل مكالمة متغير الجدول.

على الرغم من أن متغيرات الجدول مدعومة داخليًا بجداول مؤقتة ، لا يبدو أن هذه مشكلة.

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

جدول "# B98CE339". عدد المسح 1

البحث في مكدسات المكالمة لاختبار متغير الجدول لا يظهر أيًا من المخالفين الرئيسيين على الإطلاق:

NUTS

SQL Server 2019 (فانيلا)

حسنًا ، لا تزال هذه مشكلة في SQL Server 2017 ، هل هناك أي شيء مختلف في 2019 خارج الصندوق؟

أولاً ، لإظهار أنه لا يوجد شيء فوق كمّي:

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

NUTS

فرق الوقت:

  • جدول درجة الحرارة: 15765 مللي ثانية
  • متغير الجدول: 7250 مللي ثانية

كان الإجراءان مختلفين. كانت مكالمة الجدول المؤقت أسرع بضع ثوانٍ ، وكانت مكالمة المتغير الجدول أبطأ بحوالي 1.5 ثانية. يمكن تفسير متغير الجدول البطيء جزئيًا من خلال المتغير المؤجل جدول المتغير ، خيار محسن جديد في 2019.

بالنظر إلى الاختلاف في Perfview ، فقد تغير قليلاً - لم تعد sqlmin موجودة - ولكن sqllang!TCacheStore<CacheClockAlgorithm>::GetNextUserDataInHashBucket يكون.

NUTS

SQL Server 2019 (جداول نظام Tempdb في الذاكرة)

ماذا عن هذا الجديد في شيء جدول نظام الذاكرة؟ همم؟ سوب مع ذلك؟

دعونا تشغيله!

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

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

لاحظ أن هذا يتطلب إعادة تشغيل SQL Server لبدء تشغيله ، لذلك اعذرني أثناء إعادة تشغيل 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;

NUTS

فرق الوقت:

  • جدول مؤقت: 11638 مللي ثانية
  • متغير الجدول: 7403 مللي ثانية

فعلت الجداول الزمنية أفضل حوالي 4 ثوان! هذا شيء ما.

احب شيء.

هذه المرة ، لا يختلف تطبيق Perfview. جنبًا إلى جنب ، من المثير للاهتمام ملاحظة مدى قرب الأوقات عبر اللوحة:

NUTS

نقطة واحدة مثيرة للاهتمام في الفرق هي المكالمات إلى hkengine! ، والتي قد تبدو واضحة لأن ميزات hekaton-ish قيد الاستخدام الآن.

NUTS

بالنسبة إلى أهم عنصرين في الاختلاف ، لا يمكنني تحقيق الكثير من ntoskrnl!?:

NUTS

أو sqltses!CSqlSortManager_80::GetSortKey ، لكنهم هنا لـ Smrtr Ppl ™ لإلقاء نظرة على:

NUTS

لاحظ أن هناك وثائق غير موثقة وبالتأكيد ليست آمنة للإنتاج ، لذا يرجى عدم استخدامها علامة تتبع بدء التشغيل يمكنك استخدامها للحصول على كائنات نظام جدول مؤقت إضافية (مجموعات sysrowsets و sysallocunits و sysseobjvalues) مضمنة في ميزة في الذاكرة ، لكنها لم تحدث فرقًا ملحوظًا في أوقات التنفيذ في هذه الحالة.

جمع الشمل

حتى في الإصدارات الأحدث من خادم SQL ، تكون المكالمات عالية التردد لمتغيرات الجدول أسرع بكثير من المكالمات عالية التردد للجداول المؤقتة.

على الرغم من أنه من المغري إلقاء اللوم على التجميعات ، أو إعادة التركيب ، أو الإحصائيات التلقائية ، أو المزالج ، أو spinlocks ، أو التخزين المؤقت ، أو مشاكل أخرى ، إلا أن المشكلة لا تزال تدور حول إدارة تنظيف الجدول المؤقت.

إنها مكالمة أقرب في SQL Server 2019 مع تمكين جداول النظام في الذاكرة ، ولكن متغيرات الجدول لا تزال تعمل بشكل أفضل عندما يكون تكرار المكالمة مرتفعًا.

بالطبع ، كحكمة vaping ذات مرة تم تأملها: "استخدم متغيرات الجدول عندما لا يكون اختيار الخطة مشكلة".

10
Erik Darling