XÁC NHẬN hiệu quả VÀO một bảng với chỉ mục được nhóm


28

Tôi có một câu lệnh SQL chèn các hàng vào một bảng có chỉ mục được nhóm trên cột TRACKING_NUMBER.

VÍ DỤ:

INSERT INTO TABL_NAME (TRACKING_NUMBER, COLB, COLC) 
SELECT TRACKING_NUMBER, COL_B, COL_C 
FROM STAGING_TABLE

Câu hỏi của tôi là - nó có giúp sử dụng mệnh đề ORDER BY trong câu lệnh SELECT cho cột chỉ mục được nhóm không, hoặc bất kỳ mức tăng nào đạt được sẽ bị phủ định bởi loại sắp xếp bổ sung cần thiết cho mệnh đề ORDER BY?

Câu trả lời:


18

Vì các câu trả lời khác đã chỉ ra SQL Server có thể hoặc không thể đảm bảo rõ ràng rằng các hàng được sắp xếp theo thứ tự chỉ mục được nhóm trước insert.

Điều này phụ thuộc vào việc toán tử chỉ mục được nhóm trong kế hoạch có tập thuộc DMLRequestSorttính hay không (điều này phụ thuộc vào số lượng hàng được ước tính được chèn).

Nếu bạn thấy rằng SQL Server đang đánh giá thấp điều này vì bất kỳ lý do gì bạn có thể hưởng lợi từ việc thêm một tường minh ORDER BYvào SELECTtruy vấn để giảm thiểu phân tách trang và đảm bảo phân mảnh từ INSERThoạt động

Thí dụ:

use tempdb;

GO

CREATE TABLE T(N INT PRIMARY KEY,Filler char(2000))

CREATE TABLE T2(N INT PRIMARY KEY,Filler char(2000))

GO

DECLARE @T TABLE (U UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID(),N int)

INSERT INTO @T(N)
SELECT number 
FROM master..spt_values
WHERE type = 'P' AND number BETWEEN 0 AND 499

/*Estimated row count wrong as inserting from table variable*/
INSERT INTO T(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2

/*Same operation using explicit sort*/    
INSERT INTO T2(N)
SELECT T1.N*1000 + T2.N
FROM @T T1, @T T2
ORDER BY T1.N*1000 + T2.N


SELECT avg_fragmentation_in_percent,
       fragment_count,
       page_count,
       avg_page_space_used_in_percent,
       record_count
FROM   sys.dm_db_index_physical_stats(2, OBJECT_ID('T'), NULL, NULL, 'DETAILED')
;  


SELECT avg_fragmentation_in_percent,
       fragment_count,
       page_count,
       avg_page_space_used_in_percent,
       record_count
FROM   sys.dm_db_index_physical_stats(2, OBJECT_ID('T2'), NULL, NULL, 'DETAILED')
;  

Cho thấy đó Tlà phân mảnh lớn

avg_fragmentation_in_percent fragment_count       page_count           avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
99.3116118225536             92535                92535                67.1668272794663               250000
99.5                         200                  200                  74.2868173956017               92535
0                            1                    1                    32.0978502594514               200

Nhưng đối với T2sự phân mảnh là tối thiểu

avg_fragmentation_in_percent fragment_count       page_count           avg_page_space_used_in_percent record_count
---------------------------- -------------------- -------------------- ------------------------------ --------------------
0.376                        262                  62500                99.456387447492                250000
2.1551724137931              232                  232                  43.2438349394613               62500
0                            1                    1                    37.2374598468001               232

Ngược lại, đôi khi bạn có thể muốn buộc SQL Server đánh giá thấp số lượng hàng khi bạn biết dữ liệu đã được sắp xếp trước và muốn tránh sắp xếp không cần thiết. Một ví dụ đáng chú ý là khi chèn một số lượng lớn các hàng vào một bảng có newsequentialidkhóa chỉ mục được nhóm. Trong các phiên bản SQL Server trước Denali SQL Server, thêm một hoạt động sắp xếp không cần thiết và có thể tốn kém . Điều này có thể tránh được bởi

DECLARE @var INT =2147483647

INSERT INTO Foo
SELECT TOP (@var) *
FROM Bar

SQL Server sau đó sẽ ước tính rằng 100 hàng sẽ được chèn bất kể kích thước Barnằm dưới ngưỡng mà một loại được thêm vào kế hoạch. Tuy nhiên, như đã chỉ ra trong các bình luận bên dưới, điều này không có nghĩa là chèn sẽ không may tận dụng việc ghi nhật ký tối thiểu.



12

Trình tối ưu hóa quyết định việc sắp xếp dữ liệu trước khi chèn sẽ hiệu quả hơn, nó sẽ thực hiện ở đâu đó ngược dòng của toán tử chèn. Nếu bạn giới thiệu một loại như là một phần của truy vấn của bạn, trình tối ưu hóa sẽ nhận ra rằng dữ liệu đã được sắp xếp và bỏ qua làm lại. Lưu ý kế hoạch thực hiện được chọn có thể thay đổi từ chạy sang chạy tùy thuộc vào số lượng hàng được chèn từ bảng phân tầng của bạn.

Nếu bạn có thể nắm bắt các kế hoạch thực hiện của quy trình có và không có sắp xếp rõ ràng, hãy đính kèm chúng vào câu hỏi của bạn để nhận xét.

Chỉnh sửa: 2011-10-28 17:00

Câu trả lời của @ Gonsalu dường như cho thấy rằng một hoạt động sắp xếp luôn xảy ra, đây không phải là trường hợp. Kịch bản demo yêu cầu!

Vì các kịch bản đang trở nên khá lớn, tôi đã chuyển chúng sang Gist . Để dễ thử nghiệm, các tập lệnh sử dụng chế độ SQLCMD. Các thử nghiệm chạy trên 2K5SP3, lõi kép, 8GB.

Các bài kiểm tra chèn bao gồm ba kịch bản:

  1. Phân đoạn dữ liệu phân cụm chỉ mục theo thứ tự như mục tiêu.
  2. Phân đoạn dữ liệu cụm chỉ mục theo thứ tự ngược lại.
  3. Dữ liệu dàn được nhóm bởi col2 chứa INT ngẫu nhiên.

Lần chạy đầu tiên, chèn 25 hàng.

Lần chạy đầu tiên, 25 hàng

Tất cả ba kế hoạch thực hiện đều giống nhau, không có loại nào xảy ra ở bất kỳ đâu trong kế hoạch và quét chỉ mục được nhóm là "order = false".

Lần chạy thứ hai, chèn 26 hàng.

Lần chạy thứ 2, 26 hàng

Lần này các kế hoạch khác nhau.

  • Đầu tiên hiển thị quét chỉ mục cụm theo thứ tự = false. Không có sắp xếp nào xảy ra vì dữ liệu nguồn được sắp xếp phù hợp.
  • Trong lần thứ hai, quét chỉ mục cụm theo thứ tự = true, lạc hậu. Vì vậy, chúng tôi không có thao tác sắp xếp nhưng nhu cầu sắp xếp dữ liệu được trình tối ưu hóa nhận ra và nó quét theo thứ tự ngược lại.
  • Thứ ba cho thấy một toán tử sắp xếp.

Vì vậy, có một điểm bùng phát trong đó trình tối ưu hóa coi là một loại cần thiết. Như @MartinSmith chỉ ra, điều này dường như được dựa trên các hàng ước tính được chèn. Trong thử nghiệm của tôi, 25 không yêu cầu sắp xếp, 26 không (2K5SP3, lõi kép, 8GB)

Tập lệnh SQLCMD bao gồm các biến cho phép kích thước của các hàng trong bảng thay đổi (thay đổi mật độ trang) và số lượng hàng trong dbo.MyTable trước khi chèn thêm. Từ thử nghiệm của tôi, không có bất kỳ ảnh hưởng nào đến điểm tới hạn.

Nếu bất kỳ độc giả nào có khuynh hướng như vậy, xin vui lòng chạy các tập lệnh và thêm điểm bùng phát của bạn dưới dạng một nhận xét. Quan tâm để nghe nếu nó thay đổi trên các giàn thử nghiệm và / hoặc phiên bản.

Chỉnh sửa: 2011-10-28 20:15

Thử nghiệm lặp lại trên cùng một giàn nhưng với 2K8R2. Lần này điểm tới hạn là 251 hàng. Một lần nữa, việc thay đổi mật độ trang và số lượng hàng hiện có không có hiệu lực.


8

Các ORDER BYđiều khoản trong SELECTtuyên bố là dư thừa.

Nó là dư thừa bởi vì các hàng sẽ được chèn, nếu chúng cần được sắp xếp , dù sao cũng được sắp xếp.

Hãy để chúng tôi tạo ra một trường hợp thử nghiệm.

CREATE TABLE #Test (
    id INTEGER NOT NULL
);

CREATE UNIQUE CLUSTERED INDEX CL_Test_ID ON #Test (id);

CREATE TABLE #Sequence (
    number INTEGER NOT NULL
);

INSERT INTO #Sequence
SELECT number FROM master..spt_values WHERE name IS NULL;

Hãy cho phép hiển thị văn bản của các kế hoạch truy vấn thực tế, vì vậy chúng ta có thể thấy những nhiệm vụ nào được thực hiện bởi bộ xử lý truy vấn.

SET STATISTICS PROFILE ON;
GO

Bây giờ, hãy để INSERT2K hàng vào bảng mà không có ORDER BYmệnh đề.

INSERT INTO #Test
SELECT number
  FROM #Sequence

Kế hoạch thực hiện thực tế cho truy vấn này là như sau.

INSERT INTO #Test  SELECT number    FROM #Sequence
  |--Clustered Index Insert(OBJECT:([tempdb].[dbo].[#Test]), SET:([tempdb].[dbo].[#Test].[id] = [tempdb].[dbo].[#Sequence].[number]))
       |--Top(ROWCOUNT est 0)
            |--Sort(ORDER BY:([tempdb].[dbo].[#Sequence].[number] ASC))
                 |--Table Scan(OBJECT:([tempdb].[dbo].[#Sequence]))

Như bạn có thể thấy, có một toán tử Sắp xếp trước khi xảy ra INSERT thực tế.

Bây giờ, hãy xóa bảng và INSERT2k hàng vào bảng với ORDER BYmệnh đề.

TRUNCATE TABLE #Test;
GO

INSERT INTO #Test
SELECT number
  FROM #Sequence
 ORDER BY number

Kế hoạch thực hiện thực tế cho truy vấn này là như sau.

INSERT INTO #Test  SELECT number    FROM #Sequence   ORDER BY number
  |--Clustered Index Insert(OBJECT:([tempdb].[dbo].[#Test]), SET:([tempdb].[dbo].[#Test].[id] = [tempdb].[dbo].[#Sequence].[number]))
       |--Top(ROWCOUNT est 0)
            |--Sort(ORDER BY:([tempdb].[dbo].[#Sequence].[number] ASC))
                 |--Table Scan(OBJECT:([tempdb].[dbo].[#Sequence]))

Lưu ý rằng đó là cùng một kế hoạch thực hiện đã được sử dụng cho INSERTcâu lệnh mà không có ORDER BYmệnh đề.

Bây giờ, Sortthao tác không phải lúc nào cũng được yêu cầu, vì Mark Smith đã chỉ ra trong một câu trả lời khác (nếu số lượng hàng được chèn thấp), nhưng ORDER BYmệnh đề vẫn dư thừa trong trường hợp đó, vì ngay cả với một thao tác rõ ràng ORDER BY, không có Sortthao tác nào được tạo bởi bộ xử lý truy vấn.

Bạn có thể tối ưu hóa một INSERTcâu lệnh thành một bảng với một chỉ mục được nhóm, bằng cách sử dụng một bản ghi tối thiểu INSERT, nhưng điều đó nằm ngoài phạm vi của câu hỏi này.

Cập nhật 2011-11 / 02: Như Mark Smith đã chỉ ra , INSERTs vào một bảng có chỉ mục được nhóm có thể không phải lúc nào cũng cần phải được sắp xếp - ORDER BYmặc dù vậy, mệnh đề cũng không cần thiết trong trường hợp đó.

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.