Ước tính sai về truy vấn trên các bảng được phân đoạn


7

Tôi tự hỏi tại sao SQL Server đưa ra các ước tính sai trong trường hợp đơn giản như vậy. Có một kịch bản.

CREATE PARTITION FUNCTION PF_Test (int) AS RANGE RIGHT 
FOR VALUES (20140801, 20140802, 20140803)

CREATE PARTITION SCHEME PS_Test AS PARTITION PF_Test ALL TO ([Primary])

CREATE TABLE A
(
  DateKey int not null,
  Type int not null,
  constraint PK_A primary key (DateKey, Type) on PS_Test(DateKey)
)

INSERT INTO A (DateKey, Type)
SELECT
  DateKey = N1.n  + 20140801,
  Type = N2.n + 1
FROM dbo.Numbers N1
  cross join dbo.Numbers N2
WHERE N1.n BETWEEN 0 AND 2
  and N2.n BETWEEN 0 AND 10000 - 1

UPDATE STATISTICS A (PK_A) WITH FULLSCAN, INCREMENTAL = ON

CREATE TABLE B
(
  DateKey int not null,
  SubType int not null,
  Type int not null,
  constraint PK_B primary key (DateKey, SubType) on PS_Test(DateKey)
)

INSERT INTO B (DateKey, SubType, Type)
SELECT
  DateKey,
  SubType = Type * 10000 + N.n,
  Type
FROM A
  cross join dbo.Numbers N
WHERE N.n BETWEEN 1 AND 10

UPDATE STATISTICS B (PK_B) WITH FULLSCAN, INCREMENTAL = ON

Vì vậy, việc thiết lập khá đơn giản, thống kê được đưa ra và SQL Server có thể đưa ra các ước tính chính xác khi chúng tôi truy vấn một bảng.

select COUNT(*) from A where DateKey = 20140802
--10000
select COUNT(*) from B where DateKey = 20140802
--100000

Nhưng trong ước tính chọn đơn giản này là cách, và tôi không thấy giải thích tại sao.

SELECT a.DateKey, a.Type
FROM A
  JOIN B
    ON b.DateKey = a.DateKey
    AND b.Type = a.Type
WHERE a.DateKey = 20140802

Kế hoạch thực hiện

Ngay sau khi ước tính Tìm kiếm chỉ số cụm là 57% so với thực tế! Truy vấn trong thế giới thực thậm chí còn tồi tệ hơn, ước tính là 2% so với thực tế.

Bảng số PS để tái tạo thiết lập

DECLARE @UpperBound INT = 1000000;

;WITH cteN(Number) AS
(
  SELECT ROW_NUMBER() OVER (ORDER BY s1.[object_id]) - 1
  FROM sys.all_columns AS s1
  CROSS JOIN sys.all_columns AS s2
)
SELECT n = [Number] INTO dbo.Numbers
FROM cteN WHERE [Number] <= @UpperBound;

CREATE UNIQUE CLUSTERED INDEX CIX_Number ON dbo.Numbers(n)
WITH 
(
  FILLFACTOR = 100,      -- in the event server default has been changed
  DATA_COMPRESSION = ROW -- if Enterprise & table large enough to matter
);

PPS Kịch bản tương tự nhưng không phân vùng hoạt động hoàn hảo.


Mặc dù có số liệu thống kê trên mỗi phân vùng, trình tối ưu hóa vẫn chỉ nhìn vào biểu đồ đơn trên toàn bộ bảng. Vì vậy, nếu các phân vùng bị sai lệch nhiều, điều đó sẽ được làm mịn ở mức độ lớn. Xem: sqlperformance.com/2015/05/sql-statistic/ Từ
Aaron Bertrand

@AaronBertrand Có, nhưng biểu đồ đơn có hình dạng hoàn hảo! Tất cả 3 giá trị là các bước. Khi các bảng không được phân vùng, cùng một truy vấn cho ước tính hoàn hảo! SQL Server chỉ tạo ra lỗi này khi kết hợp điều kiện và tham chiếu đến phân vùng và không rõ tại sao.
Alsin

Câu trả lời:


9

Các ước tính (với công cụ ước tính cardinality mới) tốt cho một phép nối bình thường, nhưng kém chính xác hơn khi trình tối ưu hóa xem xét tùy chọn của phép nối được tạo ra .

Một tham gia được tạo ra (còn gọi là tham gia trên mỗi phân vùng) có sẵn khi tham gia hai bảng được phân vùng theo cùng một cách. Ý tưởng là tham gia một phân vùng tại một thời điểm, sử dụng các vòng lặp lồng nhau được áp dụng bởi các id phân vùng được cung cấp bởi quá trình quét không đổi (bảng giá trị trong bộ nhớ).

Tham gia thường xuyên

Vì phép nối colocated liên quan đến một vòng lặp lồng nhau được áp dụng, bạn có thể buộc trình tối ưu hóa tránh điều này bằng cách chỉ định OPTION (HASH JOIN)ví dụ:

kế hoạch với băm tham gia bắt buộc

Hai tìm kiếm trong kế hoạch đó là:

Seek Keys[1]: Prefix:
    PtnId1000, [dbo].[A].DateKey = Scalar Operator((3)), Scalar Operator((20140802))
Seek Keys[1]: Prefix:
    PtnId1003, [dbo].[B].DateKey = Scalar Operator((3)), Scalar Operator((20140802))

Trình tối ưu hóa đã áp dụng loại bỏ phân vùng tĩnh trong cả hai trường hợp, đưa ra ước tính chính xác cho cả hai lần tìm kiếm và tham gia sau đây.

Tham gia tham gia

Khi trình tối ưu hóa xem xét tham gia colocated (như được hiển thị trong câu hỏi), các tìm kiếm là:

kế hoạch tham gia

Seek Keys[1]: Prefix:
    PtnId1000, [dbo].[A].DateKey = Scalar Operator([Expr1006]), Scalar Operator((20140802))
Seek Keys[1]: Prefix:
    PtnId1003, [dbo].[B].DateKey = Scalar Operator([Expr1006]), Scalar Operator((20140802))

... Đâu [Expr1006]là giá trị được trả về bởi toán tử Constant Scan.

Công cụ ước tính cardinality bây giờ không thể thấy rằng DateKeygiá trị và id phân vùng phụ thuộc lẫn nhau, như có thể khi các hằng số bằng chữ được sử dụng. Nói cách khác, người ước tính không rõ ràng rằng giá trị bên trong [Expr1006]chỉ định phân vùng giống như DateKey = 20140802.

Do đó, CE chọn (theo mặc định) để ước tính độ chọn lọc của hai vị từ (dường như độc lập) bằng cách sử dụng phương pháp dự phòng theo cấp số nhân thông thường .

Điều này giải thích các ước tính cardinality giảm cho ăn tham gia. Chi phí rõ ràng thấp hơn của tùy chọn này (do sai lệch) có nghĩa là trình tối ưu hóa chọn tham gia colocated thay vì tham gia thông thường, mặc dù rõ ràng (với con người) rằng nó không mang lại giá trị.

Có một số cách để khắc phục khoảng trống này trong logic, bao gồm sử dụng gợi ý truy vấn USE HINT ('ASSUME_MIN_SELECTIVITY_FOR_FILTER_ESTIMATES'), nhưng điều này sẽ ảnh hưởng đến toàn bộ truy vấn, không chỉ thay thế tham gia được kết hợp có vấn đề. Như Erik lưu ý trong câu trả lời của anh ấy, bạn cũng có thể gợi ý việc sử dụng CE kế thừa.

Để biết thêm thông tin về các phép nối được tạo, hãy xem bài viết của tôi Cải thiện hiệu suất Bảng được phân vùng


Cảm ơn bạn đã trả lời chi tiết như vậy, @ paul-trắng! Bạn đã xác nhận nỗi sợ của tôi, SQL Server coi các vị từ này là các vị từ độc lập. Một lưu ý cho điều này, tôi nhận được cùng một kế hoạch thực hiện 'colocated jo' ngay cả khi các bảng này sử dụng các hàm phân vùng khác nhau. Các hàm khác nhau nhưng giống hệt nhau, vì vậy chúng trả về cùng một số phân vùng.
Alsin

Nếu hai hàm phân vùng không giống nhau, kịch bản này hoạt động như mong đợi. Tôi đã bắt đầu một chức năng một ngày trước đó so với chức năng khác và kế hoạch thực hiện là một Hash Tham gia hoàn hảo với các ước tính phù hợp. Đó là một cách giải quyết ngu ngốc nhưng đó là cách khắc phục nó cho chúng tôi.
Alsin

5

Điều này dường như là do công cụ ước tính cardinality mới được giới thiệu trong SQL Server 2014.

Nếu bạn hướng dẫn truy vấn sử dụng cái cũ, bạn sẽ có một kế hoạch khác và ước tính chính xác.

SELECT a.DateKey, a.Type
FROM A AS a
  JOIN B AS b
    ON b.DateKey = a.DateKey
    AND b.Type = a.Type
WHERE a.DateKey = 20140802
OPTION(USE HINT('FORCE_LEGACY_CARDINALITY_ESTIMATION'));

QUẢ HẠCH

Xem các liên kết này để biết thêm thông tin:

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.