Tại sao một truy vấn tổng hợp nhanh hơn đáng kể với mệnh đề GROUP BY hơn là không có?


12

Tôi chỉ tò mò tại sao một truy vấn tổng hợp chạy nhanh hơn nhiều với một GROUP BYmệnh đề hơn là không có một truy vấn .

Ví dụ: truy vấn này mất gần 10 giây để chạy

SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1

Trong khi cái này mất ít hơn một giây

SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1
GROUP BY CreatedDate

Trong CreatedDatetrường hợp này chỉ có một , vì vậy truy vấn được nhóm trả về kết quả giống như truy vấn chưa được nhóm.

Tôi nhận thấy các kế hoạch thực hiện cho hai truy vấn là khác nhau - Truy vấn thứ hai sử dụng Parallelism trong khi truy vấn đầu tiên thì không.

Kế hoạch thực hiện Query1 Kế hoạch thực hiện Query2

Có phải bình thường máy chủ SQL sẽ đánh giá một truy vấn tổng hợp khác nhau nếu nó không có mệnh đề GROUP BY? Và tôi có thể làm gì để cải thiện hiệu năng của truy vấn thứ 1 mà không cần sử dụng GROUP BYmệnh đề không?

Biên tập

Tôi vừa học được rằng tôi có thể sử dụng OPTION(querytraceon 8649)để đặt chi phí chung của song song thành 0, điều này làm cho truy vấn sử dụng một số song song và giảm thời gian chạy xuống còn 2 giây, mặc dù tôi không biết liệu có bất kỳ nhược điểm nào khi sử dụng gợi ý truy vấn này không.

SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1
OPTION(querytraceon 8649)

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

Tôi vẫn thích thời gian chạy ngắn hơn vì truy vấn có nghĩa là đưa ra một giá trị theo lựa chọn của người dùng, vì vậy lý tưởng nhất là ngay lập tức giống như truy vấn được nhóm. Ngay bây giờ tôi chỉ gói gọn truy vấn của mình, nhưng tôi biết đó không thực sự là một giải pháp lý tưởng.

SELECT Min(CreatedDate)
FROM
(
    SELECT Min(CreatedDate) as CreatedDate
    FROM MyTable WITH (NOLOCK) 
    WHERE SomeIndexedValue = 1
    GROUP BY CreatedDate
) as T

Chỉnh sửa # 2

Đáp lại yêu cầu của Martin để biết thêm thông tin :

Cả hai CreatedDateSomeIndexedValuecó một chỉ mục không duy nhất, không phân cụm trên chúng. SomeIndexedValuethực sự là một trường varchar (7), mặc dù nó lưu một giá trị số trỏ đến PK (int) của một bảng khác. Mối quan hệ giữa hai bảng không được xác định trong cơ sở dữ liệu. Tôi hoàn toàn không phải thay đổi cơ sở dữ liệu và chỉ có thể viết các truy vấn truy vấn dữ liệu đó.

MyTablechứa hơn 3 triệu bản ghi và mỗi bản ghi được gán một nhóm thuộc về ( SomeIndexedValue). Các nhóm có thể là bất cứ nơi nào từ 1 đến 200.000 hồ sơ

Câu trả lời:


8

Có vẻ như nó có thể đang theo một chỉ số theo CreatedDatethứ tự từ thấp nhất đến cao nhất và thực hiện tra cứu để đánh giá SomeIndexedValue = 1vị ngữ.

Khi tìm thấy hàng khớp đầu tiên, nó được thực hiện, nhưng nó có thể thực hiện nhiều lần tra cứu hơn mong đợi trước khi tìm thấy một hàng như vậy (nó giả sử các hàng khớp với vị ngữ được phân phối ngẫu nhiên theo ngày.)

Xem câu trả lời của tôi ở đây cho một vấn đề tương tự

Chỉ số lý tưởng cho truy vấn này sẽ là một SomeIndexedValue, CreatedDate. Giả sử rằng bạn không thể thêm điều đó hoặc ít nhất là làm cho chỉ mục hiện tại của bạn được SomeIndexedValueche đậy CreatedDatedưới dạng một cột được bao gồm thì bạn có thể thử viết lại truy vấn như sau

SELECT MIN(DATEADD(DAY, 0, CreatedDate)) AS CreatedDate
FROM MyTable
WHERE SomeIndexedValue = 1

để ngăn chặn nó sử dụng kế hoạch cụ thể đó.


2

Chúng tôi có thể kiểm soát MAXDOP và chọn một bảng đã biết, ví dụ: AdventureWorks. Producttion.TransactionHistory không?

Khi tôi lặp lại thiết lập của bạn bằng cách sử dụng

--#1
SELECT MIN(TransactionDate) 
FROM AdventureWorks.Production.TransactionHistory
WHERE TransactionID = 100001 
OPTION( MAXDOP 1) ;

--#2
SELECT MIN(TransactionDate) 
FROM AdventureWorks.Production.TransactionHistory
WHERE TransactionID = 100001 
GROUP BY TransactionDate
OPTION( MAXDOP 1) ;
GO 

các chi phí là như nhau.

Ở một khía cạnh khác, tôi sẽ mong đợi (làm cho nó xảy ra) một chỉ mục tìm kiếm trên giá trị được lập chỉ mục của bạn; nếu không, bạn có thể sẽ thấy các kết quả băm thay vì tổng hợp luồng. Bạn có thể cải thiện hiệu suất với các chỉ mục không được nhóm bao gồm các giá trị mà bạn đang tổng hợp và hoặc tạo chế độ xem được lập chỉ mục xác định tổng hợp của bạn dưới dạng cột. Sau đó, bạn sẽ nhấn một chỉ mục được nhóm, trong đó có các tập hợp của bạn, bằng Id được lập chỉ mục. Trong SQL Standard, bạn chỉ có thể tạo chế độ xem và sử dụng gợi ý VỚI (NOEXPAND).

Một ví dụ (tôi không sử dụng MIN, vì nó không hoạt động trong các chế độ xem được lập chỉ mục):

USE AdventureWorks ;
GO

-- Covering Index with Include
CREATE INDEX IX_CoverAndInclude
ON Production.TransactionHistory(TransactionDate) 
INCLUDE (Quantity) ;
GO

-- Indexed View
CREATE VIEW dbo.SumofQtyByTransDate
    WITH SCHEMABINDING
AS
SELECT 
      TransactionDate 
    , COUNT_BIG(*) AS NumberOfTransactions
    , SUM(Quantity) AS TotalTransactions
FROM Production.TransactionHistory
GROUP BY TransactionDate ;
GO

CREATE UNIQUE CLUSTERED INDEX SumofAllChargesIndex 
    ON dbo.SumofQtyByTransDate (TransactionDate) ;  
GO


--#1
SELECT SUM(Quantity) 
FROM AdventureWorks.Production.TransactionHistory 
WITH (INDEX(0))
WHERE TransactionID = 100001 
OPTION( MAXDOP 1) ;

--#2
SELECT SUM(Quantity)  
FROM AdventureWorks.Production.TransactionHistory 
WITH (INDEX(IX_CoverAndInclude))
WHERE TransactionID = 100001 
GROUP BY TransactionDate
OPTION( MAXDOP 1) ;
GO 

--#3
SELECT SUM(Quantity)  
FROM AdventureWorks.Production.TransactionHistory
WHERE TransactionID = 100001 
GROUP BY TransactionDate
OPTION( MAXDOP 1) ;
GO

MAXDOPđặt mức độ song song tối đa, giới hạn số lượng bộ xử lý mà truy vấn có thể sử dụng. Điều này về cơ bản sẽ làm cho truy vấn thứ 2 chạy chậm như truy vấn thứ nhất, vì nó loại bỏ khả năng sử dụng song song, đó không phải là điều tôi muốn.
Rachel

@Rachel Tôi đồng ý; nhưng chúng ta không thể so sánh bất cứ điều gì trừ khi chúng ta đặt ra một số quy tắc cơ bản. Tôi không thể dễ dàng so sánh một quá trình song song chạy trên 64 lõi với một luồng duy nhất chạy trên một. Cuối cùng, tôi hy vọng tất cả các máy của chúng tôi có ít nhất một CPU logic = -)
ooutwire 20/03/2016

0

Theo tôi, lý do của vấn đề là trình tối ưu hóa máy chủ sql không tìm kiếm kế hoạch TỐT NHẤT mà là tìm kiếm một kế hoạch tốt, vì rõ ràng là sau khi buộc song song truy vấn thực thi nhanh hơn nhiều, điều mà trình tối ưu hóa đã thực hiện không được thực hiện trên chính nó.

Tôi cũng đã thấy nhiều tình huống viết lại truy vấn theo định dạng khác nhau là sự khác biệt giữa song song hóa (ví dụ: mặc dù hầu hết các bài viết về SQL đều đề xuất tham số hóa, tôi đã tìm thấy nó đôi khi không thực hiện song song ngay cả khi các tham số đánh hơi giống như không - song song một hoặc kết hợp hai truy vấn với UNION ALL đôi khi có thể loại bỏ song song hóa).

Như vậy, giải pháp chính xác có thể là bằng cách thử các cách viết truy vấn khác nhau, chẳng hạn như thử các bảng tạm thời, biến bảng, cte, bảng dẫn xuất, tham số hóa, v.v. và cũng chơi với các chỉ mục, chế độ xem được lập chỉ mục hoặc chỉ mục được lọc trong để có được kế hoạch tốt nhất.

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.