Database
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Database

Hai đặc điểm phân vùng

Phân vùng bảng trong SQL Server về cơ bản là một cách làm cho nhiều bảng vật lý (tập hợp hàng) trông giống như một bảng. Sự trừu tượng hóa này được thực hiện hoàn toàn bởi bộ xử lý truy vấn, một thiết kế giúp mọi thứ đơn giản hơn cho người dùng, nhưng lại tạo ra những yêu cầu phức tạp của trình tối ưu hóa truy vấn. Bài đăng này xem xét hai ví dụ vượt quá khả năng của trình tối ưu hóa trong SQL Server 2008 trở đi.

Tham gia các Vấn đề Thứ tự Cột

Ví dụ đầu tiên này cho thấy cách sắp xếp văn bản của ON điều kiện mệnh đề có thể ảnh hưởng đến kế hoạch truy vấn được tạo ra khi tham gia các bảng được phân vùng. Để bắt đầu, chúng ta cần một lược đồ phân vùng, một hàm phân vùng và hai bảng:

CREATE PARTITION FUNCTION PF (integer) 
AS RANGE RIGHT
FOR VALUES 
	(
	10000, 20000, 30000, 40000, 50000,
	60000, 70000, 80000, 90000, 100000,
	110000, 120000, 130000, 140000, 150000
	);
 
CREATE PARTITION SCHEME PS 
AS PARTITION PF 
ALL TO ([PRIMARY]);
GO
CREATE TABLE dbo.T1
(
    c1 integer NOT NULL,
    c2 integer NOT NULL,
    c3 integer NOT NULL,
 
    CONSTRAINT PK_T1
    PRIMARY KEY CLUSTERED (c1, c2, c3)
    ON PS (c1)
);
 
CREATE TABLE dbo.T2
(
    c1 integer NOT NULL,
    c2 integer NOT NULL,
    c3 integer NOT NULL,
 
    CONSTRAINT PK_T2
    PRIMARY KEY CLUSTERED (c1, c2, c3)
    ON PS (c1)
);

Tiếp theo, chúng tôi tải cả hai bảng với 150.000 hàng. Dữ liệu không quan trọng lắm; ví dụ này sử dụng bảng Numbers tiêu chuẩn chứa tất cả các giá trị số nguyên từ 1 đến 150.000 làm nguồn dữ liệu. Cả hai bảng đều được tải với cùng một dữ liệu.

INSERT dbo.T1 WITH (TABLOCKX)
    (c1, c2, c3)
SELECT
    N.n * 1,
    N.n * 2,
    N.n * 3
FROM dbo.Numbers AS N
WHERE
    N.n BETWEEN 1 AND 150000;
 
INSERT dbo.T2 WITH (TABLOCKX)
    (c1, c2, c3)
SELECT
    N.n * 1,
    N.n * 2,
    N.n * 3
FROM dbo.Numbers AS N
WHERE
    N.n BETWEEN 1 AND 150000;

Truy vấn thử nghiệm của chúng tôi thực hiện một phép nối bên trong đơn giản của hai bảng này. Một lần nữa, truy vấn không quan trọng hoặc có ý định đặc biệt thực tế, nó được sử dụng để chứng minh một hiệu ứng kỳ lạ khi tham gia các bảng được phân vùng. Dạng đầu tiên của truy vấn sử dụng ON mệnh đề được viết theo thứ tự cột c3, c2, c1:

SELECT *
FROM dbo.T1 AS T1
JOIN dbo.T2 AS T2
    ON t1.c3 = t2.c3 
    AND t1.c2 = t2.c2 
    AND t1.c1 = t2.c1;

Kế hoạch thực thi được tạo cho truy vấn này (trên SQL Server 2008 trở lên) có tính năng kết hợp băm song song, với chi phí ước tính là 2.6953 :

Điều này hơi bất ngờ. Cả hai bảng đều có chỉ mục được nhóm theo thứ tự (c1, c2, c3), được phân vùng bởi c1, vì vậy chúng tôi mong đợi một phép nối hợp nhất, tận dụng thứ tự chỉ mục. Hãy thử viết ON thay vào đó mệnh đề trong (c1, c2, c3):

SELECT *
FROM dbo.T1 AS T1
JOIN dbo.T2 AS T2
    ON t1.c1 = t2.c1
    AND t1.c2 = t2.c2
    AND t1.c3 = t2.c3;

Kế hoạch thực thi hiện sử dụng liên kết hợp nhất dự kiến, với chi phí ước tính là 1,64119 (giảm từ 2.6953 ). Trình tối ưu hóa cũng quyết định rằng không nên sử dụng thực thi song song:

Lưu ý rằng kế hoạch liên kết hợp nhất rõ ràng là hiệu quả hơn, chúng tôi có thể cố gắng buộc một liên kết hợp nhất cho ON ban đầu thứ tự mệnh đề sử dụng gợi ý truy vấn:

SELECT *
FROM dbo.T1 AS T1
JOIN dbo.T2 AS T2
    ON t1.c3 = t2.c3 
    AND t1.c2 = t2.c2 
    AND t1.c1 = t2.c1
OPTION (MERGE JOIN);

Kế hoạch kết quả không sử dụng kết hợp hợp nhất như được yêu cầu, nhưng nó cũng có tính năng sắp xếp trên cả hai đầu vào và quay trở lại sử dụng song song. Chi phí ước tính của kế hoạch này là một con số khổng lồ 8.71063 :

Cả hai toán tử sắp xếp đều có cùng thuộc tính:

Trình tối ưu hóa cho rằng phép liên kết hợp nhất cần các đầu vào của nó được sắp xếp theo thứ tự được viết chặt chẽ là ON kết quả là giới thiệu các loại rõ ràng. Trình tối ưu hóa nhận thức được rằng liên kết hợp nhất yêu cầu các đầu vào của nó được sắp xếp theo cùng một cách, nhưng nó cũng biết rằng thứ tự cột không quan trọng. Phép kết hợp trên (c1, c2, c3) cũng hài lòng với các đầu vào được sắp xếp trên (c3, c2, c1) cũng như với các đầu vào được sắp xếp trên (c2, c1, c3) hoặc bất kỳ kết hợp nào khác.

Thật không may, suy luận này bị hỏng trong trình tối ưu hóa truy vấn khi liên quan đến phân vùng. Đây là một lỗi trình tối ưu hóa đã được sửa trong SQL Server 2008 R2 trở lên, mặc dù cờ theo dõi 4199 được yêu cầu để kích hoạt bản sửa lỗi:

SELECT *
FROM dbo.T1 AS T1
JOIN dbo.T2 AS T2
    ON t1.c3 = t2.c3 
    AND t1.c2 = t2.c2 
    AND t1.c1 = t2.c1
OPTION (QUERYTRACEON 4199);

Bạn thường bật cờ theo dõi này bằng cách sử dụng DBCC TRACEON hoặc như một tùy chọn khởi động, vì QUERYTRACEON gợi ý không được ghi lại để sử dụng với 4199. Cờ theo dõi là bắt buộc trong SQL Server 2008 R2, SQL Server 2012 và SQL Server 2014 CTP1.

Dù sao, bao giờ cờ được bật, truy vấn hiện tạo ra phép kết hợp tối ưu bất kể ON điều khoản đặt hàng:

Không có không có bản sửa lỗi nào cho SQL Server 2008 , cách giải quyết là ghi ON mệnh đề theo thứ tự ‘đúng’! Nếu bạn gặp một truy vấn như thế này trên SQL Server 2008, hãy thử buộc một liên kết hợp nhất và xem xét các loại để xác định cách 'đúng' để viết ON cho truy vấn của bạn mệnh đề.

Sự cố này không phát sinh trong SQL Server 2005 vì bản phát hành đó đã triển khai các truy vấn phân vùng bằng cách sử dụng APPLY mô hình:

Kế hoạch truy vấn SQL Server 2005 kết hợp một phân vùng từ mỗi bảng tại một thời điểm, sử dụng bảng trong bộ nhớ (Quét liên tục) có chứa số phân vùng để xử lý. Mỗi phân vùng được hợp nhất được kết hợp riêng biệt ở phía bên trong của phép nối và trình tối ưu hóa 2005 đủ thông minh để thấy rằng ON thứ tự cột mệnh đề không quan trọng.

Kế hoạch mới nhất này là một ví dụ về liên kết hợp nhất sắp xếp theo thứ tự , một cơ sở đã bị mất khi chuyển từ SQL Server 2005 sang triển khai phân vùng mới trong SQL Server 2008. Một đề xuất về Kết nối để khôi phục các phép nối hợp nhất được sắp xếp đã bị đóng là Không khắc phục được.

Nhóm theo các vấn đề đặt hàng

Điểm đặc biệt thứ hai mà tôi muốn xem xét theo một chủ đề tương tự, nhưng liên quan đến thứ tự của các cột trong GROUP BY thay vì mệnh đề ON mệnh đề của một phép nối bên trong. Chúng tôi sẽ cần một bảng mới để chứng minh:

CREATE TABLE dbo.T3
(
    RowID       integer IDENTITY NOT NULL,
    UserID      integer NOT NULL,
    SessionID   integer NOT NULL,
    LocationID  integer NOT NULL,
 
    CONSTRAINT PK_T3
    PRIMARY KEY CLUSTERED (RowID)
    ON PS (RowID)
);
 
INSERT dbo.T3 WITH (TABLOCKX)
    (UserID, SessionID, LocationID)
SELECT
    ABS(CHECKSUM(NEWID())) % 50,
    ABS(CHECKSUM(NEWID())) % 30,
    ABS(CHECKSUM(NEWID())) % 10
FROM dbo.Numbers AS N
WHERE
    N.n BETWEEN 1 AND 150000;

Bảng có chỉ mục không phân tán được căn chỉnh, trong đó 'căn chỉnh' chỉ đơn giản là nó được phân vùng theo cách giống như chỉ mục được phân nhóm (hoặc đống):

CREATE NONCLUSTERED INDEX nc1
ON dbo.T3 (UserID, SessionID, LocationID)
ON PS (RowID);

Truy vấn thử nghiệm của chúng tôi nhóm dữ liệu trên ba cột chỉ mục không phân biệt và trả về số lượng cho mỗi nhóm:

SELECT LocationID, UserID, SessionID, COUNT_BIG(*)
FROM dbo.T3
GROUP BY LocationID, UserID, SessionID;

Kế hoạch truy vấn quét chỉ mục không phân biệt và sử dụng Tổng hợp đối sánh băm để đếm các hàng trong mỗi nhóm:

Có hai vấn đề với Hash Aggregate:

  1. Nó là một toán tử chặn. Không có hàng nào được trả lại cho khách hàng cho đến khi tất cả các hàng đã được tổng hợp.
  2. Nó yêu cầu cấp bộ nhớ để giữ bảng băm.

Trong nhiều trường hợp thực tế, chúng tôi muốn có một Tổng hợp luồng ở đây vì nhà điều hành đó chỉ chặn mỗi nhóm và không yêu cầu cấp bộ nhớ. Sử dụng tùy chọn này, ứng dụng khách sẽ bắt đầu nhận dữ liệu sớm hơn, không phải đợi cấp bộ nhớ và SQL Server có thể sử dụng bộ nhớ cho các mục đích khác.

Chúng tôi có thể yêu cầu trình tối ưu hóa truy vấn sử dụng Tổng hợp Luồng cho truy vấn này bằng cách thêm OPTION (ORDER GROUP) gợi ý truy vấn. Điều này dẫn đến kế hoạch thực hiện sau:

Toán tử Sắp xếp đang chặn hoàn toàn và cũng yêu cầu cấp bộ nhớ, vì vậy kế hoạch này có vẻ tồi tệ hơn so với chỉ sử dụng tổng hợp băm. Nhưng tại sao lại cần phân loại? Các thuộc tính cho thấy rằng các hàng đang được sắp xếp theo thứ tự được chỉ định bởi GROUP BY của chúng tôi mệnh đề:

Loại này được mong đợi bởi vì việc căn chỉnh phân vùng chỉ mục (trong SQL Server 2008 trở đi) có nghĩa là số phân vùng được thêm vào như một cột hàng đầu của chỉ mục. Trên thực tế, các khóa chỉ mục không phân biệt là (phân vùng, người dùng, phiên, vị trí) do phân vùng. Các hàng trong chỉ mục vẫn được sắp xếp theo người dùng, phiên và vị trí, nhưng chỉ trong mỗi phân vùng.

Nếu chúng tôi giới hạn truy vấn trong một phân vùng duy nhất, trình tối ưu hóa phải có thể sử dụng chỉ mục để cung cấp một Tổng hợp Luồng mà không cần sắp xếp. Trong trường hợp cần một số lời giải thích, việc chỉ định một phân vùng duy nhất có nghĩa là kế hoạch truy vấn có thể loại bỏ tất cả các phân vùng khác khỏi quá trình quét chỉ mục không phân biệt, dẫn đến một luồng các hàng được sắp xếp theo (người dùng, phiên, vị trí).

Chúng ta có thể loại bỏ phân vùng này một cách rõ ràng bằng cách sử dụng $PARTITION chức năng:

SELECT LocationID, UserID, SessionID, COUNT_BIG(*)
FROM dbo.T3
WHERE $PARTITION.PF(RowID) = 1
GROUP BY LocationID, UserID, SessionID;

Rất tiếc, truy vấn này vẫn sử dụng Tổng hợp băm, với chi phí gói ước tính là 0,287878 :

Quá trình quét hiện chỉ trên một phân vùng, nhưng thứ tự (người dùng, phiên, vị trí) đã không giúp trình tối ưu hóa sử dụng Tổng hợp Luồng. Bạn có thể phản đối rằng việc đặt hàng (người dùng, phiên, vị trí) không hữu ích vì GROUP BY mệnh đề là (vị trí, người dùng, phiên), nhưng thứ tự khóa không quan trọng đối với hoạt động nhóm.

Hãy thêm một ORDER BY mệnh đề theo thứ tự của các khóa chỉ mục để chứng minh quan điểm:

SELECT LocationID, UserID, SessionID, COUNT_BIG(*)
FROM dbo.T3
WHERE $PARTITION.PF(RowID) = 1
GROUP BY LocationID, UserID, SessionID
ORDER BY UserID, SessionID, LocationID;

Lưu ý rằng ORDER BY mệnh đề khớp với thứ tự khóa chỉ mục không phân biệt, mặc dù GROUP BY mệnh đề không. Kế hoạch thực thi cho truy vấn này là:

Giờ đây, chúng tôi có Tổng số luồng mà chúng tôi đang theo đuổi, với chi phí gói ước tính là 0,0423925 (so với 0,287878 cho kế hoạch Hash Aggregate - gần gấp 7 lần).

Cách khác để đạt được Tổng hợp luồng ở đây là sắp xếp lại GROUP BY để khớp với các khóa chỉ mục không phân biệt:

SELECT LocationID, UserID, SessionID, COUNT_BIG(*)
FROM dbo.T3 AS T1
WHERE $PARTITION.PF(RowID) = 1
GROUP BY UserID, SessionID, LocationID;

Truy vấn này tạo ra cùng một kế hoạch Tổng hợp Luồng được hiển thị ngay bên trên, với cùng một mức chi phí. Độ nhạy này đối với GROUP BY thứ tự cột dành riêng cho các truy vấn bảng được phân vùng trong SQL Server 2008 trở lên.

Bạn có thể nhận ra rằng nguyên nhân gốc rễ của vấn đề ở đây tương tự như trường hợp trước đó liên quan đến Kết hợp hợp nhất. Cả Tham gia Hợp nhất và Tổng hợp Luồng đều yêu cầu đầu vào được sắp xếp trên các khóa kết hợp hoặc tổng hợp, nhưng không quan tâm đến thứ tự của các khóa đó. Kết hợp Hợp nhất trên (x, y, z) cũng giống như việc nhận các hàng được sắp xếp theo thứ tự (y, z, x) hoặc (z, y, x) và điều này cũng đúng với Tổng hợp luồng.

Giới hạn của trình tối ưu hóa này cũng áp dụng cho DISTINCT trong những hoàn cảnh giống nhau. Truy vấn sau dẫn đến kế hoạch Hash Aggregate với chi phí ước tính là 0,286539 :

SELECT DISTINCT LocationID, UserID, SessionID
FROM dbo.T3 AS T1
WHERE $PARTITION.PF(RowID) = 1;

Nếu chúng ta viết DISTINCT các cột theo thứ tự của các khóa chỉ mục không phân biệt…

SELECT DISTINCT UserID, SessionID, LocationID
FROM dbo.T3 AS T1
WHERE $PARTITION.PF(RowID) = 1;

… Chúng tôi được thưởng bằng gói Tổng hợp luồng với chi phí là 0,041455 :

Tóm lại, đây là hạn chế của trình tối ưu hóa truy vấn trong SQL Server 2008 trở lên (bao gồm SQL Server 2014 CTP 1) không được giải quyết bằng cách sử dụng cờ theo dõi 4199 như trường hợp của ví dụ Merge Join. Sự cố chỉ xảy ra với các bảng được phân vùng bằng GROUP BY hoặc DISTINCT trên ba hoặc nhiều cột bằng cách sử dụng chỉ mục được phân vùng căn chỉnh, nơi một phân vùng duy nhất được xử lý.

Như với ví dụ về Merge Join, điều này thể hiện một bước lùi so với hành vi SQL Server 2005. SQL Server 2005 đã không thêm khóa hàng đầu ngụ ý vào các chỉ mục được phân vùng, bằng cách sử dụng APPLY kỹ thuật thay thế. Trong SQL Server 2005, tất cả các truy vấn được trình bày ở đây bằng cách sử dụng $PARTITION để chỉ định một kết quả phân vùng duy nhất trong kế hoạch truy vấn thực hiện loại bỏ phân vùng và sử dụng Tổng hợp luồng mà không cần sắp xếp lại văn bản truy vấn.

Những thay đổi đối với xử lý bảng được phân vùng trong SQL Server 2008 đã cải thiện hiệu suất trong một số lĩnh vực quan trọng, chủ yếu liên quan đến việc xử lý song song hiệu quả các phân vùng. Thật không may, những thay đổi này có tác dụng phụ mà không phải tất cả đã được giải quyết trong các bản phát hành sau này.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Mọi thứ bạn cần biết về toán tử LIKE trong SQL

  2. Di chuyển DB với Trình hướng dẫn Đa bảng NextForm

  3. Xuân Hội nhập là gì?

  4. Hiểu về triển khai Amazon Auroras Multi-AZ

  5. SQL MIN () cho người mới bắt đầu