2009-09-08 19 views
10

Tôi đang chọn một số hàng từ hàm bảng có giá trị nhưng đã tìm thấy sự khác biệt hiệu suất lớn không thể giải thích bằng cách đặt SELECT TOP trong truy vấn.Sự khác biệt hiệu năng lớn của SQL bằng cách sử dụng SELECT TOP x ngay cả khi x cao hơn nhiều hàng đã chọn

SELECT col1, col2, col3 etc 
FROM  dbo.some_table_function 
WHERE col1 = @parameter 
--ORDER BY col1 

mất tối đa 5 hoặc 6 phút để hoàn thành.

Tuy nhiên

SELECT TOP 6000 col1, col2, col3 etc 
FROM  dbo.some_table_function 
WHERE col1 = @parameter 
--ORDER BY col1 

hoàn thành trong khoảng 4 hoặc 5 giây.

Điều này sẽ không làm tôi ngạc nhiên nếu tập hợp dữ liệu được trả lại là rất lớn, nhưng truy vấn cụ thể liên quan đến trả về ~ 5000 hàng trong số 200.000.

Vì vậy, trong cả hai trường hợp, toàn bộ bảng được xử lý, khi SQL Server tiếp tục kết thúc để tìm kiếm 6000 hàng mà nó sẽ không bao giờ nhận được. Tại sao sự khác biệt lớn sau đó? Đây có phải là một cái gì đó để làm với cách SQL Server phân bổ không gian với dự đoán kích thước thiết lập kết quả (TOP 6000 do đó cho nó một yêu cầu thấp được phân bổ dễ dàng hơn trong bộ nhớ)? Có ai khác đã chứng kiến ​​một cái gì đó như thế này?

Cảm ơn

+0

Bạn đã xem các kế hoạch truy vấn chưa? Có sự khác biệt nào không? –

+2

Chỉ cần tò mò, điều gì xảy ra với hiệu suất nếu bạn nói SELECT TOP 100 PERCENT ....? –

+0

Tôi đoán bạn có một số thống kê đưa trình tối ưu hóa truy vấn ra khỏi kelter. Trình tối ưu hóa có thể, ví dụ, quyết định sử dụng quét bảng thay vì chỉ mục tìm kiếm nếu nó tin rằng có rất ít hàng trong một bảng. Tại sao điều này không ảnh hưởng đến truy vấn TOP tôi dunno, nhưng kiểm tra các kế hoạch thực hiện. Những điều này cho bạn thấy những gì máy chủ làm, và điều đó sẽ giải thích lý do tại sao một máy chủ chậm. Nó cũng sẽ hiển thị cho bạn số lượng hàng được ước tính và thực tế. Nếu một số ước tính là cách tắt, hãy cập nhật số liệu thống kê và thử lại. :) –

Trả lời

6

Các hàm có giá trị bảng có thể có thời gian thực hiện phi tuyến tính.

Hãy xem xét chức năng tương đương cho truy vấn này:

SELECT (
     SELECT SUM(mi.value) 
     FROM mytable mi 
     WHERE mi.id <= mo.id 
     ) 
FROM mytable mo 
ORDER BY 
     mo.value 

Truy vấn này (cho phép tính chạy SUM) là nhanh ngay từ đầu và chậm ở cuối, vì trên mỗi hàng từ mo nó nên tổng hợp tất cả các các giá trị trước đó đòi hỏi phải tua lại các rowsource.

Thời gian thực hiện để tính SUM cho mỗi hàng tăng khi số hàng tăng lên.

Nếu bạn thực hiện mytable đủ lớn (ví dụ: 100,000 hàng, như trong ví dụ của bạn) và chạy truy vấn này, bạn sẽ thấy rằng phải mất nhiều thời gian.

Tuy nhiên, nếu bạn áp dụng TOP 5000 cho truy vấn này, bạn sẽ thấy rằng nó hoàn thành nhanh hơn nhiều so với 1/20 thời gian cần thiết cho toàn bộ bảng.

Rất có thể, điều gì đó tương tự cũng xảy ra trong trường hợp của bạn.

Để nói điều gì đó chắc chắn hơn, tôi cần xem định nghĩa hàm.

Cập nhật:

SQL Server có thể đẩy các vị từ vào hàm.

Ví dụ, tôi vừa tạo TVF này:

CREATE FUNCTION fn_test() 
RETURNS TABLE 
AS 
RETURN (
     SELECT * 
     FROM master 
     ); 

Các truy vấn này: quét

SELECT * 
FROM fn_test() 
WHERE name = @name 

SELECT TOP 1000 * 
FROM fn_test() 
WHERE name = @name 

năng suất khác nhau kế hoạch thực hiện (một trong những đầu tiên sử dụng cụm, điều thứ hai sử dụng một chỉ mục tìm kiếm với a TOP)

+0

'Sợ không trong trường hợp này. Điểm của truy vấn của tôi là các hàng _same_ được trả về bất kể mệnh đề TOP được sử dụng hay không (TOP 6000 lớn hơn tập kết quả). Do đó, nó không thể liên quan đến việc tính toán các hàng đó. – Ray

+0

'@ Arj': bạn có thể vui lòng đăng định nghĩa chức năng của mình không? – Quassnoi

+0

@Quassnoi: TVF nội tuyến đơn giản là một macro. – gbn

1

Không nhất thiết phải là toàn bộ bảng được xử lý nếu col1 có chỉ mục.

Tối ưu hóa SQL sẽ chọn có sử dụng chỉ mục hay không. Có lẽ "TOP" của bạn đang buộc nó sử dụng chỉ mục.

Nếu bạn đang sử dụng Trình phân tích truy vấn MSSQL (Tên thoát tôi) nhấn Ctrl-K. Điều này sẽ hiển thị kế hoạch thực hiện cho truy vấn thay vì thực hiện nó. Di chuyển qua các biểu tượng sẽ hiển thị mức sử dụng IO/CPU, tôi tin.

Tôi đặt cược một người đang sử dụng tìm kiếm chỉ mục, trong khi người khác thì không.

Nếu bạn có khách hàng chung: SET SHOWPLAN_ALL ON; GO chọn ...; go

xem http://msdn.microsoft.com/en-us/library/ms187735.aspx để biết chi tiết.

+0

Vâng - Tôi đang xem kế hoạch ngay bây giờ. Mặc dù tôi đã thay đổi truy vấn để đăng. Trong thực tế nó đang làm SELECT *. Tôi không thể thấy cách sử dụng TOP sẽ nhắc sử dụng chỉ mục như thế nào? – Ray

+0

Trình tối ưu hóa SQL sẽ quyết định có sử dụng chỉ mục hay không. Tôi đã thực hiện các truy vấn trong đó mệnh đề where gây ra một "điểm bùng phát", nơi trình tối ưu hóa quyết định thực hiện quét toàn bộ bảng thay vì sử dụng một chỉ mục. – ericp

1

Bạn có thể chạy vào một cái gì đó đơn giản như bộ nhớ đệm ở đây - có lẽ (vì lý do gì) truy vấn "TOP" được lưu trong bộ nhớ cache? Sử dụng một chỉ số mà người khác không phải là?

Trong mọi trường hợp, cách tốt nhất để làm dịu sự tò mò của bạn là kiểm tra toàn bộ kế hoạch thực hiện cho cả hai truy vấn. Bạn có thể làm điều này ngay trong SQL Management Console và nó sẽ cho bạn biết chính xác những gì các hoạt động đang được hoàn thành và bao lâu mỗi dự đoán sẽ thực hiện.

Tất cả triển khai SQL đều kỳ quặc theo cách riêng của chúng - SQL Server cũng không ngoại lệ. Những loại "whaaaaaa ?!" những khoảnh khắc khá phổ biến. ; ^)

3

TOP của bạn không có ORDER BY, vì vậy nó đơn giản giống như SET ROWCOUNT 6000 trước. Một ORDER BY sẽ yêu cầu tất cả các hàng được đánh giá đầu tiên và sẽ mất nhiều thời gian hơn.

Nếu dbo.some_table_function là bảng nội tuyến có giá trị udf, thì nó chỉ đơn giản là macro được mở rộng để trả về 6000 hàng đầu tiên được đề cập không theo thứ tự cụ thể.

Nếu udf có giá trị đa, thì đó là hộp đen và sẽ luôn lấy toàn bộ tập dữ liệu trước khi lọc. Tôi không nghĩ rằng điều này đang xảy ra.

Không liên quan trực tiếp, nhưng another SO question on TVFs

1

Tôi nghĩ Quassnois' gợi ý có vẻ rất đáng tin cậy. Bằng cách thêm TOP 6000, bạn đang ngầm đưa cho trình tối ưu hóa một gợi ý rằng một tập hợp con nhỏ 200.000 hàng sẽ được trả về. Trình tối ưu hóa sau đó sử dụng chỉ mục tìm kiếm thay vì quét chỉ mục nhóm hoặc quét bảng.

Một giải thích có thể khác có thể lưu vào bộ nhớ cache, như Jim davis gợi ý. Điều này khá dễ dàng để loại trừ bằng cách chạy lại các truy vấn. Hãy thử chạy một với TOP 6000 đầu tiên.

2

Tôi đã có cùng một vấn đề, một truy vấn đơn giản tham gia năm bảng trở về 1000 hàng mất hai phút để hoàn thành. Khi tôi thêm "TOP 10000" vào nó, nó hoàn thành trong chưa đầy một giây. Hóa ra chỉ số nhóm trên một trong các bảng bị phân mảnh nhiều.

Sau khi tạo lại chỉ mục, truy vấn hiện đã hoàn tất sau chưa đầy một giây.

Các vấn đề liên quan