Tại sao sử dụng biến bảng nhanh hơn gấp đôi so với bảng #temp trong trường hợp cụ thể này?


37

Tôi đã xem bài viết ở đây Bảng tạm thời so với biến bảng và ảnh hưởng của chúng đối với hiệu suất của máy chủ SQL và trên SQL Server 2008 có thể tái tạo kết quả tương tự với kết quả được hiển thị ở đó cho năm 2005.

Khi thực hiện các thủ tục được lưu trữ (định nghĩa bên dưới) chỉ với 10 hàng, phiên bản biến bảng sẽ thực hiện phiên bản bảng tạm thời hơn hai lần.

Tôi đã xóa bộ đệm thủ tục và chạy cả hai thủ tục được lưu trữ 10.000 lần sau đó lặp lại quy trình cho 4 lần chạy khác. Kết quả bên dưới (thời gian tính bằng ms trên mỗi đợt)

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

Câu hỏi của tôi là: lý do cho hiệu suất tốt hơn của phiên bản biến bảng là gì?

Tôi đã thực hiện một số điều tra. ví dụ: Nhìn vào các quầy hiệu suất với

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

xác nhận rằng trong cả hai trường hợp, các đối tượng tạm thời đang được lưu trữ sau lần chạy đầu tiên như mong đợi thay vì được tạo lại từ đầu cho mỗi lần gọi.

Tương tự truy tìm các Auto Stats, SP:Recompile, SQL:StmtRecompilesự kiện trong Profiler (ảnh chụp màn hình dưới đây) cho thấy rằng những sự kiện chỉ xảy ra một lần (trên gọi đầu tiên của #tempthủ tục lưu trữ bảng) và 9.999 hành khác không tăng bất kỳ của những sự kiện này. (Phiên bản biến của bảng không nhận được bất kỳ sự kiện nào trong số này)

Dấu vết

Tuy nhiên, chi phí lớn hơn một chút trong lần chạy đầu tiên của thủ tục được lưu trữ có thể không gây ra sự khác biệt lớn về tổng thể, tuy nhiên, chỉ mất vài ms để xóa bộ đệm thủ tục và chạy cả hai thủ tục một lần nên tôi không tin thống kê hoặc biên dịch lại có thể là nguyên nhân.

Tạo các đối tượng cơ sở dữ liệu cần thiết

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

Kiểm tra tập lệnh

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

Theo dõi hồ sơ chỉ ra rằng số liệu thống kê chỉ được tạo trên #tempbảng một lần mặc dù nó bị xóa và được điền lại 9,999 lần sau đó.
Martin Smith

Câu trả lời:


31

Đầu ra của SET STATISTICS IO ONcả hai trông giống nhau

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

Tặng

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

Và như Aaron chỉ ra trong các ý kiến kế hoạch cho các phiên bản biến bảng thực sự là kém hiệu quả như khi cả hai đều có một vòng lặp lồng nhau kế hoạch công dẫn dắt bởi một chỉ mục tìm kiếm trên dbo.NUMcác #tempThực hiện phiên bản bảng một tìm kiếm vào chỉ số trên [#T].n = [dbo].[NUM].[n]với vị còn lại [#T].[n]<=[@total]trong khi các biến bảng phiên bản thực hiện tìm kiếm chỉ mục @V.n <= [@total]với biến vị ngữ còn lại @V.[n]=[dbo].[NUM].[n]và do đó xử lý nhiều hàng hơn (đó là lý do tại sao kế hoạch này thực hiện rất kém đối với số lượng hàng lớn hơn)

Sử dụng các sự kiện mở rộng để xem xét các loại chờ cho spid cụ thể mang lại những kết quả này cho 10.000 lần thực hiệnEXEC 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              |
+---------------------+------------+----------------+----------------+----------------+

và những kết quả này cho 10.000 lần thực hiện 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              |
+---------------------+------------+----------------+----------------+----------------+

Vì vậy, rõ ràng là số lượng PAGELATCH_SHchờ đợi cao hơn nhiều trong #temptrường hợp bảng. Tôi không biết bất kỳ cách nào để thêm tài nguyên chờ vào theo dõi các sự kiện mở rộng vì vậy để điều tra thêm về vấn đề này, tôi đã chạy

WHILE 1=1
EXEC dbo.T2 10

Trong khi bỏ phiếu kết nối khác 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'

Sau khi rời khỏi đó trong khoảng 15 giây, nó đã thu thập các kết quả sau

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

Cả hai trang này được chốt đều thuộc về các chỉ mục không phân cụm (khác nhau) trên tempdb.sys.sysschobjsbảng cơ sở có tên 'nc1''nc2'.

Truy vấn tempdb.sys.fn_dblogtrong quá trình chạy chỉ ra rằng số lượng bản ghi nhật ký được thêm vào bởi lần thực hiện đầu tiên của mỗi thủ tục được lưu trữ có phần thay đổi nhưng đối với các lần thực hiện tiếp theo, số được thêm bởi mỗi lần lặp là rất phù hợp và có thể dự đoán được. Khi các gói thủ tục được lưu vào bộ nhớ cache, số lượng mục nhật ký là khoảng một nửa số mục cần thiết cho #tempphiên bản.

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

Nhìn vào các mục nhật ký giao dịch chi tiết hơn cho #tempphiên bản bảng của SP, mỗi lần gọi tiếp theo của thủ tục được lưu trữ sẽ tạo ra ba giao dịch và biến bảng chỉ có một.

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

Các INSERT/ TVQUERYgiao dịch là giống hệt nhau ngoại trừ tên. Điều này chứa các bản ghi nhật ký cho mỗi trong số 10 hàng được chèn vào bảng tạm thời hoặc biến bảng cộng với LOP_BEGIN_XACT/ LOP_COMMIT_XACTmục.

Các CREATE TABLEgiao dịch chỉ xuất hiện trong các #Tempphiên bản và trông như sau.

+-----------------+-------------------+---------------------+
|    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          |                     |
+-----------------+-------------------+---------------------+

Các FCheckAndCleanupCachedTempTablegiao dịch xuất hiện trong cả hai nhưng có 6 mục bổ sung trong #tempphiên bản. Đây là 6 hàng đề cập đến sys.sysschobjsvà chúng có cùng một mẫu như trên.

+-----------------+-------------------+----------------------------------------------+
|    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          |                                              |
+-----------------+-------------------+----------------------------------------------+

Nhìn vào 6 hàng này trong cả hai giao dịch, chúng tương ứng với cùng một hoạt động. Đầu tiên LOP_MODIFY_ROW, LCX_CLUSTEREDlà một bản cập nhật cho modify_datecột trong sys.objects. Năm hàng còn lại đều liên quan đến việc đổi tên đối tượng. Bởi vì namelà một cột chính của cả NCI bị ảnh hưởng ( nc1nc2), điều này được thực hiện dưới dạng xóa / chèn cho những người sau đó nó quay trở lại chỉ mục được nhóm và cập nhật.

Có vẻ như đối với #tempphiên bản bảng khi thủ tục được lưu trữ kết thúc một phần của việc dọn dẹp được thực hiện bởi FCheckAndCleanupCachedTempTablegiao dịch là đổi tên bảng tạm thời từ một tên giống như #T__________________________________________________________________________________________________________________00000000E316một tên nội bộ khác như #2F4A0079khi được nhập vào CREATE TABLEgiao dịch sẽ đổi tên lại. Tên lật này có thể được nhìn thấy bằng một kết nối thực hiện dbo.T2trong một vòng lặp trong khi ở một kết nối khác

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

Kết quả ví dụ

Ảnh chụp màn hình

Vì vậy, một lời giải thích tiềm năng cho sự khác biệt hiệu suất quan sát được Alex ám chỉ là công việc bổ sung này duy trì các bảng hệ thống tempdbcó trách nhiệm.


Chạy cả hai thủ tục trong một vòng lặp, trình lược tả Visual Studio Code cho thấy những điều sau đây

+-------------------------------+--------------------+-------+-----------+
|           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      |
+-------------------------------+--------------------+-------+-----------+

Phiên bản biến bảng dành khoảng 60% thời gian để thực hiện câu lệnh chèn và lựa chọn tiếp theo trong khi bảng tạm thời ít hơn một nửa. Đây là nội tuyến với thời gian được hiển thị trong OP và với kết luận ở trên rằng sự khác biệt về hiệu suất là do thời gian thực hiện công việc phụ trợ không phải do thời gian thực hiện truy vấn.

Các chức năng quan trọng nhất đóng góp vào 75% "mất tích" trong phiên bản bảng tạm thời là

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

Trong cả hai chức năng tạo và phát hành, chức năng CMEDProxyObject::SetNameđược hiển thị với giá trị mẫu bao gồm 19.6%. Từ đó tôi suy ra rằng 39,2% thời gian trong trường hợp bảng tạm thời được thực hiện với việc đổi tên được mô tả trước đó.

Và những cái lớn nhất trong phiên bản biến bảng đóng góp cho 40% còn lại là

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

Hồ sơ bảng tạm thời

nhập mô tả hình ảnh ở đây

Bảng biến hồ sơ

nhập mô tả hình ảnh ở đây


10

Disco inferno

Vì đây là một câu hỏi cũ hơn, tôi đã quyết định xem xét lại vấn đề trên các phiên bản SQL Server mới hơn để xem liệu cấu hình hiệu suất tương tự có còn tồn tại hay không, nếu các đặc điểm đã thay đổi.

Cụ thể, việc bổ sung các bảng hệ thống trong bộ nhớ cho SQL Server 2019 dường như là một dịp đáng để kiểm tra lại.

Tôi đang sử dụng một khai thác thử nghiệm hơi khác nhau, vì tôi gặp phải vấn đề này trong khi làm việc với một cái gì đó khác.

Thử nghiệm

Sử dụng phiên bản 2013 của Stack Overflow , tôi có chỉ mục này và hai quy trình sau:

Mục lục:

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

Bảng tạm thời:

    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 

Bảng biến:

    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 

Để ngăn chặn bất kỳ ASYNC_NETWORK_IO tiềm năng nào đang chờ , tôi đang sử dụng các quy trình bao bọc.

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

Máy chủ SQL 2017

Kể từ năm 2014 và 2016 về cơ bản là TIN CẬY vào thời điểm này, tôi đang bắt đầu thử nghiệm vào năm 2017. Ngoài ra, để cho ngắn gọn, tôi sẽ nhảy ngay vào hồ sơ mã với Perfview . Trong cuộc sống thực, tôi đã nhìn vào sự chờ đợi, chốt, vòng xoay, cờ theo dõi điên rồ và những thứ khác.

Hồ sơ mã là điều duy nhất tiết lộ bất cứ điều gì quan tâm.

Thời gian khác biệt:

  • Bảng tạm thời: 17891 ms
  • Bảng biến: 5891 ms

Vẫn là một sự khác biệt rất rõ ràng, eh? Nhưng SQL Server đang tấn công cái gì bây giờ?

QUẢ HẠCH

Nhìn vào hai mức tăng hàng đầu trong các mẫu khác nhau, chúng tôi thấy sqlminsqlsqllang!TCacheStore<CacheClockAlgorithm>::GetNextUserDataInHashBucketlà hai tội phạm lớn nhất.

QUẢ HẠCH

Đánh giá theo tên trong ngăn xếp cuộc gọi, dọn dẹp và đổi tên bên trong các bảng tạm thời dường như là thời gian lớn nhất trong cuộc gọi bảng tạm thời so với cuộc gọi biến bảng.

Mặc dù các biến bảng được hỗ trợ nội bộ bởi các bảng tạm thời, nhưng điều này dường như không phải là một vấn đề.

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

Bảng '# B98CE339'. Quét số 1

Nhìn qua ngăn xếp cuộc gọi để kiểm tra biến bảng không thể hiện một trong những người vi phạm chính:

QUẢ HẠCH

Máy chủ SQL 2019 (Vanilla)

Được rồi, vì vậy đây vẫn là một vấn đề trong SQL Server 2017, có gì khác trong năm 2019 không?

Đầu tiên, để hiển thị không có gì lên tay áo của tôi:

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

QUẢ HẠCH

Thời gian khác biệt:

  • Bảng nhiệt độ: 15765 ms
  • Bảng biến: 7250 ms

Cả hai thủ tục đều khác nhau. Cuộc gọi bảng tạm thời nhanh hơn một vài giây và cuộc gọi biến bảng chậm hơn khoảng 1,5 giây. Biến bảng chậm lại có thể được giải thích một phần bằng cách biên dịch hoãn lại biến bảng , một lựa chọn tối ưu hóa mới trong năm 2019.

Nhìn vào sự khác biệt trong Perfview, nó đã thay đổi một chút - sqlmin không còn ở đó nữa - nhưng sqllang!TCacheStore<CacheClockAlgorithm>::GetNextUserDataInHashBucketlà vậy.

QUẢ HẠCH

SQL Server 2019 (Bảng hệ thống Tempdb trong bộ nhớ)

Điều gì mới này trong bảng hệ thống bộ nhớ điều? Hửm Sup với điều đó?

Hãy bật nó lên!

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

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

Lưu ý rằng điều này yêu cầu khởi động lại SQL Server để khởi động, vì vậy xin lỗi tôi trong khi tôi khởi động lại SQL vào chiều thứ sáu đáng yêu này.

Bây giờ mọi thứ trông khác:

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;

QUẢ HẠCH

Thời gian khác biệt:

  • Bảng tạm thời: 11638 ms
  • Biến bảng: 7403 ms

Các bảng tạm thời đã làm tốt hơn khoảng 4 giây! Đó là một cái gì đó.

Tôi thích một cái gì đó

Lần này, Perfview diff không thú vị lắm. Bên cạnh, thật thú vị khi lưu ý khoảng thời gian trên bảng:

QUẢ HẠCH

Một điểm thú vị trong khác biệt là các cuộc gọi đến hkengine!, điều này có vẻ hiển nhiên vì các tính năng của hekaton-ish hiện đang được sử dụng.

QUẢ HẠCH

Theo như hai mục hàng đầu trong khác biệt, tôi không thể thực hiện nhiều ntoskrnl!?:

QUẢ HẠCH

Hoặc sqltses!CSqlSortManager_80::GetSortKey, nhưng họ ở đây để Smrtr Ppl ™ xem xét:

QUẢ HẠCH

Lưu ý rằng có một tài liệu không có giấy tờ và chắc chắn không an toàn cho sản xuất, vì vậy vui lòng không sử dụng cờ theo dõi khởi động mà bạn có thể sử dụng để có thêm các đối tượng hệ thống bảng tạm thời (sysrowets, sysallocunits và sysseobjvalues) trong tính năng trong bộ nhớ, nhưng nó đã không tạo ra sự khác biệt đáng chú ý về thời gian thực hiện trong trường hợp này.

Làm tròn

Ngay cả trong các phiên bản mới hơn của máy chủ SQL, các cuộc gọi tần số cao đến các biến bảng nhanh hơn nhiều so với các cuộc gọi tần số cao đến các bảng tạm thời.

Mặc dù thật đáng trách khi đổ lỗi cho các phần tổng hợp, biên dịch lại, chỉ số tự động, chốt, spinlocks, bộ nhớ đệm hoặc các vấn đề khác, vấn đề rõ ràng vẫn xoay quanh việc quản lý dọn dẹp bảng tạm thời.

Đó là một cuộc gọi gần hơn trong SQL Server 2019 với các bảng hệ thống trong bộ nhớ được bật, nhưng các biến bảng vẫn hoạt động tốt hơn khi tần số cuộc gọi cao.

Tất nhiên, như một nhà hiền triết vaping đã từng trầm ngâm: "sử dụng biến bảng khi lựa chọn kế hoạch không phải là vấn đề".


Rất vui - xin lỗi tôi đã bỏ lỡ rằng bạn đã thêm câu trả lời cho đến khi chỉ cần theo liên kết trong bài đăng trên blog "gỡ lỗi" của bạn
Martin Smith
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.