ROW_NUMBER () QUÁ (THAM GIA B, A ĐẶT HÀNG B C) không sử dụng chỉ mục trên (A, B, C)


12

Hãy xem xét hai chức năng này:

ROW_NUMBER() OVER (PARTITION BY A,B ORDER BY C)

ROW_NUMBER() OVER (PARTITION BY B,A ORDER BY C)

Theo tôi hiểu, họ tạo ra kết quả chính xác như nhau. Nói cách khác, thứ tự mà bạn liệt kê các cột trong PARTITION BYmệnh đề không quan trọng.

Nếu có một chỉ số trên (A,B,C)tôi dự kiến ​​trình tối ưu hóa sẽ sử dụng chỉ số này trong cả hai biến thể.

Nhưng thật ngạc nhiên, trình tối ưu hóa đã quyết định thực hiện một Sắp xếp rõ ràng hơn trong biến thể thứ hai.

Tôi đã thấy nó trên SQL Server 2008 Standard và SQL Server 2014 Express.

Đây là một kịch bản đầy đủ mà tôi đã sử dụng để tái tạo nó.

Đã thử trên Microsoft SQL Server 2014 - 12.0.2000.8 (X64) 20 tháng 2 năm 2014 20:04:26 Bản quyền (c) Microsoft Corporation Express Edition (64-bit) trên Windows NT 6.1 (Build 7601: Gói dịch vụ 1)

và Microsoft SQL Server 2014 (SP1-CU7) (KB3162659) - 12.0.4459.0 (X64) 27 tháng 5 năm 2016 15:33:17 Bản quyền (c) Microsoft Corporation Express Edition (64-bit) trên Windows NT 6.1 (Bản dựng 7601: Dịch vụ Gói 1)

với cả Công cụ ước tính Cardinality cũ và mới bằng cách sử dụng OPTION (QUERYTRACEON 9481)OPTION (QUERYTRACEON 2312).

Thiết lập bảng, chỉ mục, dữ liệu mẫu

CREATE TABLE [dbo].[T](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [A] [int] NOT NULL,
    [B] [int] NOT NULL,
    [C] [int] NOT NULL,
    CONSTRAINT [PK_T] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, 
STATISTICS_NORECOMPUTE = OFF, 
IGNORE_DUP_KEY = OFF, 
ALLOW_ROW_LOCKS = ON, 
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

CREATE NONCLUSTERED INDEX [IX_ABC] ON [dbo].[T]
(
    [A] ASC,
    [B] ASC,
    [C] ASC
)WITH (PAD_INDEX = OFF, 
STATISTICS_NORECOMPUTE = OFF, 
SORT_IN_TEMPDB = OFF, 
DROP_EXISTING = OFF, 
ONLINE = OFF, 
ALLOW_ROW_LOCKS = ON, 
ALLOW_PAGE_LOCKS = ON)
GO

INSERT INTO [dbo].[T] ([A],[B],[C]) VALUES
(10, 20, 30),
(10, 21, 31),
(10, 21, 32),
(10, 21, 33),
(11, 20, 34),
(11, 21, 35),
(11, 21, 36),
(12, 20, 37),
(12, 21, 38),
(13, 21, 39);

Truy vấn

SELECT -- AB
    ID,A,B,C
    ,ROW_NUMBER() OVER (PARTITION BY A,B ORDER BY C) AS rnAB
FROM T
ORDER BY C
OPTION(RECOMPILE);

SELECT -- BA
    ID,A,B,C
    ,ROW_NUMBER() OVER (PARTITION BY B,A ORDER BY C) AS rnBA
FROM T
ORDER BY C
OPTION(RECOMPILE);

SELECT -- both
    ID,A,B,C
    ,ROW_NUMBER() OVER (PARTITION BY A,B ORDER BY C) AS rnAB
    ,ROW_NUMBER() OVER (PARTITION BY B,A ORDER BY C) AS rnBA
FROM T
ORDER BY C
OPTION(RECOMPILE);

Kế hoạch thực hiện

PHẦN THAM GIA A, B

AB

PHẦN THAM GIA B, A

ba

Cả hai

cả hai

Như bạn có thể thấy, kế hoạch thứ hai có thêm Sắp xếp. Nó đặt hàng bởi B, A, C. Trình tối ưu hóa, rõ ràng, không đủ thông minh để nhận ra đó PARTITION BY B,Alà giống PARTITION BY A,Bvà sắp xếp lại dữ liệu.

Thật thú vị, truy vấn thứ ba có cả hai biến thể ROW_NUMBERtrong đó và không có Sắp xếp thêm! Kế hoạch tương tự như đối với truy vấn đầu tiên. (Dự án tuần tự có biểu thức bổ sung trong Danh sách đầu ra cho cột thêm, nhưng không có Sắp xếp thêm). Vì vậy, trong trường hợp phức tạp hơn này, trình tối ưu hóa dường như đủ thông minh để nhận ra điều đó PARTITION BY B,Agiống như PARTITION BY A,B.

Trong các truy vấn thứ nhất và thứ ba, toán tử Index Scan có thuộc tính được đặt hàng: Đúng, trong truy vấn thứ hai, nó là Sai.

Thậm chí thú vị hơn, nếu tôi viết lại truy vấn thứ ba như thế này (hoán đổi hai cột):

SELECT -- both
    ID,A,B,C
    ,ROW_NUMBER() OVER (PARTITION BY B,A ORDER BY C) AS rnBA
    ,ROW_NUMBER() OVER (PARTITION BY A,B ORDER BY C) AS rnAB
FROM T
ORDER BY C
OPTION(RECOMPILE);

sau đó sắp xếp thêm xuất hiện một lần nữa!

Ai đó có thể làm sáng tỏ? Điều gì đang xảy ra trong trình tối ưu hóa ở đây?


Bình luận lưu trữ .
Paul White 9

Câu trả lời:


2

Dường như không có "câu trả lời" dứt khoát nào cho câu hỏi "chuyện gì đang xảy ra trong trình tối ưu hóa", trừ khi bạn là nhà phát triển của nó và biết nội bộ của nó.

Tôi sẽ tập hợp các ý kiến ​​ở đây.

Nhìn chung, có vẻ như sẽ quá khắc nghiệt để gọi nó là một lỗi, bởi vì kết quả cuối cùng của truy vấn là chính xác. Trong một số trường hợp, kế hoạch thực hiện đơn giản là không tối ưu. ypercubeᵀᴹ , Martin SmithAaron Bertrand gọi đó là "tối ưu hóa bị bỏ lỡ".

  • Có vẻ như GROUP BY a,bGROUP BY b,amang lại các kế hoạch giống hệt nhau nhưng PARTITION BYkhông thể sử dụng cùng một chuyển đổi

  • Ngoài ra còn có các tối ưu hóa bị thiếu khác trong đó các hàm cửa sổ có cùng đặc tả cửa sổ có thể có một thao tác sắp xếp bổ sung nếu được phân tách trong danh sách chọn với một đặc tả khác.

  • Vâng, điều này có vẻ như một tối ưu hóa bị bỏ lỡ khác, và có rất nhiều trong số đó. Trình tối ưu hóa được viết bởi con người và không hoàn hảo


Có một bài viết hơi liên quan Chỉ số giảm dần. Sắp xếp chỉ mục, tính song song và tính toán xếp hạng của Itzik Ben-Gan. Ở đó, Itzik thảo luận về các chỉ mục giảm dần và cũng đưa ra một ví dụ về cách định nghĩa chỉ mục ảnh hưởng đến các chức năng của cửa sổ với các phân vùng. Anh ta cho thấy các ví dụ về các truy vấn và các kế hoạch được tạo ra ROW_NUMBERcó toán tử sắp xếp bổ sung mà trình tối ưu hóa có thể tránh được.


Đối với tôi, kết quả thực tế sẽ là giữ cho tính đặc thù của người tối ưu này trong tâm trí. Khi sử dụng PARTITION BYtrong các chức năng của cửa sổ luôn cố gắng khớp với thứ tự mà bạn liệt kê các cột theo PARTITION BYthứ tự chúng được liệt kê trong chỉ mục. Mặc dù nó không quan trọng.

Một khía cạnh khác của biện pháp phòng ngừa này là khi bạn xem xét các chỉ mục của mình và quyết định hoán đổi một số cột xung quanh trong định nghĩa chỉ mục. Xin lưu ý rằng bạn có thể vô tình ảnh hưởng đến một số truy vấn hiện có mà dường như không bị ảnh hưởng. Đây thực sự là cách tôi nhận thấy tính đặc thù này của trình tối ưu hóa.

Nếu bạn không, trình tối ưu hóa có thể không thể sử dụng chỉ mục cho toàn bộ tiềm năng của nó. Ngay cả khi trình tối ưu hóa chọn một kế hoạch tối ưu, kế hoạch đó có thể thay đổi thành ít tối ưu hơn với một thay đổi vô tội nhỏ nhất đối với truy vấn, như thay đổi thứ tự các cột trong SELECTcâu lệnh.

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.