Tại sao toán tử concatenation ước tính ít hàng hơn đầu vào của nó?


20

Trong đoạn mã kế hoạch truy vấn sau đây, có vẻ như rõ ràng rằng ước tính hàng cho Concatenationtoán tử phải là ~4.3 billion rowshoặc tổng các ước tính hàng cho hai đầu vào của nó.

Tuy nhiên, một ước tính ~238 million rowsđược tạo ra, dẫn đến một chiến lược Sort/ tối ưu phụ Stream Aggregatelàm tràn hàng trăm GB dữ liệu sang tempdb. Một ước tính thống nhất về mặt logic trong trường hợp này sẽ tạo ra một Hash Aggregate, loại bỏ sự cố tràn và cải thiện đáng kể hiệu năng truy vấn.

Đây có phải là một lỗi trong SQL Server 2014 không? Có bất kỳ trường hợp hợp lệ nào trong đó ước tính thấp hơn đầu vào có thể hợp lý không? Cách giải quyết nào có thể có sẵn?

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

Đây là kế hoạch truy vấn đầy đủ (ẩn danh). Tôi không có quyền truy cập sysadmin vào máy chủ này để cung cấp đầu ra từ QUERYTRACEON 2363hoặc các cờ theo dõi tương tự, nhưng có thể có được các đầu ra này từ quản trị viên nếu chúng hữu ích.

Cơ sở dữ liệu ở mức tương thích 120 và do đó đang sử dụng Công cụ ước tính Cardinality SQL Server 2014 mới.

Số liệu thống kê được cập nhật thủ công mỗi khi dữ liệu được tải. Với khối lượng dữ liệu, chúng tôi hiện đang sử dụng tỷ lệ lấy mẫu mặc định. Có thể tỷ lệ lấy mẫu cao hơn (hoặc FULLSCAN) có thể có tác động.

Câu trả lời:


21

Để trích dẫn Campbell Fraser về mục Kết nối này :

Những "mâu thuẫn về tim mạch" này có thể phát sinh trong một số tình huống, bao gồm cả khi sử dụng concat. Chúng có thể phát sinh bởi vì ước tính của một cây con cụ thể trong kế hoạch cuối cùng có thể đã được thực hiện trên một cây con có cấu trúc khác nhau nhưng tương đương logic. Do tính chất thống kê của ước tính cardinality, ước tính trên các cây khác nhau nhưng tương đương về mặt logic không được đảm bảo để có cùng ước tính. Vì vậy, tổng thể không có đảm bảo về tính nhất quán dự kiến ​​được cung cấp.

Để mở rộng thêm một chút: Cách tôi muốn giải thích là nói rằng ước tính cardinality ban đầu (được thực hiện trước khi bắt đầu tối ưu hóa dựa trên chi phí) tạo ra các ước tính cardinality "nhất quán" hơn, vì toàn bộ cây ban đầu được xử lý, với mỗi cây tiếp theo ước tính phụ thuộc trực tiếp vào cái trước.

Trong quá trình tối ưu hóa dựa trên chi phí, các phần của cây kế hoạch (một hoặc nhiều toán tử) có thể được khám phá và thay thế bằng các lựa chọn thay thế, mỗi phần có thể yêu cầu ước tính số lượng thẻ mới. Không có cách chung nào để nói ước tính nào sẽ tốt hơn so với ước tính khác, vì vậy hoàn toàn có thể kết thúc với một kế hoạch cuối cùng có vẻ "không nhất quán". Đây chỉ đơn giản là kết quả của việc ghép các "bit của kế hoạch" lại với nhau để tạo thành sự sắp xếp cuối cùng.

Tất cả những gì đã nói, đã có một số thay đổi chi tiết để các ước lượng mới cardinality (CE) giới thiệu trong SQL Server 2014 mà làm này hơi ít phổ biến hơn là trường hợp với CE gốc.

Ngoài việc nâng cấp lên Cập nhật tích lũy mới nhất và kiểm tra xem có sửa lỗi tối ưu hóa với 4199 hay không, các tùy chọn chính của bạn là thử thay đổi chỉ số / chỉ số (lưu ý các cảnh báo cho các chỉ mục bị thiếu) và cập nhật hoặc thể hiện truy vấn khác nhau. Mục tiêu là có được một kế hoạch hiển thị hành vi bạn yêu cầu. Điều này sau đó có thể được đóng băng với một hướng dẫn kế hoạch, ví dụ.

Kế hoạch ẩn danh làm cho việc đánh giá chi tiết trở nên khó khăn, nhưng tôi cũng sẽ xem xét kỹ các bitmap để xem liệu chúng có thuộc loại 'tối ưu hóa' (Opt_Bitmap) hoặc tối ưu hóa sau (Bitmap) hay không. Tôi cũng nghi ngờ về Bộ lọc.

Nếu số lượng hàng là bất cứ thứ gì giống như chính xác, thì đây có vẻ như là một truy vấn có thể được hưởng lợi từ cột cửa hàng. Ngoài các lợi ích thông thường, bạn có thể tận dụng việc cấp bộ nhớ động cho các toán tử chế độ hàng loạt ( có thể cần có cờ theo dõi 9389 ).


7

Xây dựng một giường thử nghiệm khá đơn giản được thừa nhận trên SQL Server 2012 (11.0.6020) cho phép tôi tạo lại một kế hoạch với hai truy vấn khớp băm được nối thông qua a UNION ALL. Giường thử nghiệm của tôi không hiển thị ước tính không chính xác mà bạn nhìn thấy. Có lẽ đây một vấn đề SQL Server 2014 CE.

Tôi nhận được ước tính 133.785 hàng cho một truy vấn thực sự trả về 280 hàng, tuy nhiên đó là điều được mong đợi vì chúng ta sẽ thấy tiếp theo:

IF OBJECT_ID('dbo.Union1') IS NOT NULL
DROP TABLE dbo.Union1;
CREATE TABLE dbo.Union1
(
    Union1_ID INT NOT NULL
        CONSTRAINT PK_Union1
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , Union1_Text VARCHAR(255) NOT NULL
    , Union1_ObjectID INT NOT NULL
);

IF OBJECT_ID('dbo.Union2') IS NOT NULL
DROP TABLE dbo.Union2;
CREATE TABLE dbo.Union2
(
    Union2_ID INT NOT NULL
        CONSTRAINT PK_Union2
        PRIMARY KEY CLUSTERED
        IDENTITY(2,2)
    , Union2_Text VARCHAR(255) NOT NULL
    , Union2_ObjectID INT NOT NULL
);

INSERT INTO dbo.Union1 (Union1_Text, Union1_ObjectID)
SELECT o.name, o.object_id
FROM sys.objects o;

INSERT INTO dbo.Union2 (Union2_Text, Union2_ObjectID)
SELECT o.name, o.object_id
FROM sys.objects o;
GO

SELECT *
FROM dbo.Union1 u1
    INNER HASH JOIN sys.objects o ON u1.Union1_ObjectID = o.object_id
UNION ALL
SELECT *
FROM dbo.Union2 u2
    INNER HASH JOIN sys.objects o ON u2.Union2_ObjectID = o.object_id;

Tôi nghĩ lý do là xung quanh việc thiếu số liệu thống kê cho hai kết quả tham gia được UNIONed. SQL Server cần đưa ra những phỏng đoán có giáo dục trong hầu hết các trường hợp xung quanh tính chọn lọc của các cột khi phải đối mặt với việc thiếu số liệu thống kê.

Joe Sack có một bài đọc thú vị về điều đó ở đây .

Đối với a UNION ALL, thật an toàn khi nói rằng chúng ta sẽ thấy chính xác tổng số hàng được trả về bởi mỗi thành phần của liên minh, tuy nhiên vì SQL Server đang sử dụng ước tính hàng cho hai thành phần của UNION ALL, chúng tôi thấy nó thêm tổng số hàng ước tính từ cả hai các truy vấn để đưa ra ước tính cho toán tử ghép.

Trong ví dụ của tôi ở trên, số lượng hàng ước tính cho mỗi phần của UNION ALLlà 66,8927, khi tổng của nó bằng 133,785, chúng ta thấy số lượng hàng ước tính cho toán tử ghép.

Kế hoạch thực hiện thực tế cho truy vấn công đoàn ở trên trông giống như:

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

Bạn có thể thấy số lượng hàng "ước tính" so với "thực tế". Trong trường hợp của tôi, việc thêm số lượng hàng "ước tính" được trả về bởi hai toán tử khớp băm chính xác bằng với số lượng được hiển thị bởi toán tử ghép.

Tôi sẽ cố gắng để có được đầu ra từ dấu vết 2363, v.v. như khuyến nghị trong bài đăng của Paul White mà bạn thể hiện trong câu hỏi của mình. Thay phiên, bạn có thể thử sử dụng OPTION (QUERYTRACEON 9481)trong truy vấn để trở lại phiên bản 70 CE để xem điều đó có "khắc phục" sự cố không.


1
Cảm ơn. Tôi chắc chắn đã thấy "lý do là xung quanh việc thiếu số liệu thống kê cho hai kết quả được UNIONed" có tác động lớn đến các lần tham gia hoặc tập hợp tiếp theo (xảy ra sau UNION). SQL 2014 thực sự xử lý việc này tốt hơn SQL 2012 theo kinh nghiệm của tôi. Đây là một kịch bản thử nghiệm đơn giản mà tôi đã sử dụng trước đây, ví dụ: gist.github.com/anonymous/1497112d8b25ab8fb782a04569959c68 Tuy nhiên, tôi không nghĩ rằng một toán tử Ghép nối sẽ cần cùng loại thông tin về phân phối các giá trị mà tham gia. có thể cần.
Geoff Patterson

Tôi đồng ý với bạn rằng việc ghép nối không cần thống kê để thực hiện chính xác. Đơn giản là nó có thể đáng tin cậy để thêm các ước tính hàng đến để hiểu rõ hơn về số lượng hàng sẽ xuất. Như @PaulWhite cho thấy trong câu trả lời của mình, điều đáng ngạc nhiên là không phải lúc nào cũng như vậy. Đối với tôi, việc mang đi ở đây có vẻ đơn giản, nhưng thực tế có thể không phải vậy. Tôi thực sự rất vui vì bạn đã hỏi câu hỏi theo cách bạn đã làm, tôi chỉ ước bạn không phải ẩn danh kế hoạch - thật thú vị khi xem truy vấn thực tế.
Max Vernon
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.