2009-11-04 8 views
7

Truy vấn đơn giản sau đây mất một thời gian rất dài (vài phút) để thực thi.cách cấu trúc chỉ mục cho nhóm theo trong Sql Server

Tôi có một chỉ số:

create index IX on [fctWMAUA] (SourceSystemKey, AsAtDateKey) 
SELECT MAX([t0].[AsAtDateKey]) AS [Date], [t0].[SourceSystemKey] AS [SourceSystem] 
FROM [fctWMAUA] (NOLOCK) AS [t0] 
WHERE SourceSystemKey in (1,2,3,4,5,6,7,8,9) 
GROUP BY [t0].[SourceSystemKey] 

Số liệu thống kê như sau:

  • logic đọc 1827978
  • vật lý lần đọc 1113
  • đọc aheads 1.806.459

Chụp cùng truy vấn chính xác và định dạng nó như sau mang lại cho tôi những thống kê này:

  • logic lần đọc 36
  • vật lý lần đọc 0
  • đọc aheads 0

Phải mất 31ms để thực thi.

SELECT MAX([t0].[AsAtDateKey]) AS [Date], [t0].[SourceSystemKey] AS [SourceSystem] 
FROM [fctWMAUA] (NOLOCK) AS [t0] 
WHERE SourceSystemKey = 1 
GROUP BY [t0].[SourceSystemKey] 
UNION 
SELECT MAX([t0].[AsAtDateKey]) AS [Date], [t0].[SourceSystemKey] AS [SourceSystem] 
FROM [fctWMAUA] (NOLOCK) AS [t0] 
WHERE SourceSystemKey = 2 
GROUP BY [t0].[SourceSystemKey] 
UNION 
SELECT MAX([t0].[AsAtDateKey]) AS [Date], [t0].[SourceSystemKey] AS [SourceSystem] 
FROM [fctWMAUA] (NOLOCK) AS [t0] 
WHERE SourceSystemKey = 3 
GROUP BY [t0].[SourceSystemKey] 
/* AND SO ON TO 9 */ 

Làm cách nào để tôi lập chỉ mục nhóm nhanh chóng?

+0

Bạn có chỉ mục trên SourceSystemKey không? Nếu không, tôi nghĩ bạn có thể đang thực hiện quét toàn bộ bảng. – heferav

+1

Showplan hiển thị những gì? và SourceSystemKey có thể lấy các giá trị nào? – Mark

Trả lời

1

Cố gắng nói với SQL Server để sử dụng các chỉ số:

... 
FROM [fctWMAUA] (NOLOCK, INDEX(IX)) AS [t0] 
... 

Hãy chắc chắn rằng số liệu thống kê cho bảng được cập nhật:

UPDATE STATISTICS [fctWMAUA] 

Đối với câu trả lời tốt hơn, bật SHOWPLAN cho cả truy vấn:

SET SHOWPLAN_TEXT ON 

và thêm kết quả vào câu hỏi của bạn.

Bạn cũng có thể viết truy vấn mà không có GROUP BY. Ví dụ: bạn có thể sử dụng LEFT JOIN độc quyền loại trừ các hàng có ngày cũ hơn:

select cur.SourceSystemKey, cur.date 
from fctWMAUA cur 
left join fctWMAUA next 
    on next.SourceSystemKey = next.SourceSystemKey 
    and next.date > cur.date 
where next.SourceSystemKey is null 
and cur.SourceSystemKey in (1,2,3,4,5,6,7,8,9) 

Điều này có thể nhanh đến đáng kinh ngạc, nhưng tôi không nghĩ rằng nó có thể đánh bại UNION.

+0

Đã thử tất cả các đề xuất của bạn. Vẫn còn rất chậm. Liên minh vẫn còn nhanh.

 |--Stream Aggregate(GROUP BY:([t0].[SourceSystemKey]) DEFINE:([Expr1003]=MAX([partialagg1004]))) |--Parallelism(Gather Streams, ORDER BY:([t0].[SourceSystemKey] ASC)) |--Stream Aggregate(GROUP BY:([t0].[SourceSystemKey]) DEFINE:([partialagg1004]=MAX([KITE].[dbo].[fctWMAUA].[AsAtDateKey] as [t0].[AsAtDateKey]))) |--Index Seek(OBJECT:([KITE].[dbo].[fctWMAUA].[IX_AsAtDateSourceSystem] AS [t0]), SEEK:([t0].[SourceSystemKey] >= (1) AND [t0].[SourceSystemKey] <= (9)) ORDERED FORWARD) 
Craig

+0

Tôi cũng sắp xếp lại các trường trong chỉ mục và không thay đổi. – Craig

+0

xem xét kế hoạch mà nó có ý nghĩa. Tìm kiếm ban đầu đó sẽ tìm tất cả các hồ sơ. Chỉ có chín hệ thống nguồn, và nó đang tìm kiếm rất nhiều. – Craig

0
WHERE SourceSystemKey = 3 
GROUP BY [t0].[SourceSystemKey] 

Bạn không cần nhóm theo trường cố định.

Bất kỳ cách nào tôi thích câu đầu tiên. Có thể tôi sẽ thay thế

WHERE SourceSystemKey in (1,2,3,4,5,6,7,8,9) 

cho một cái gì đó giống như

WHERE SourceSystemKey BETWEEN 1 AND 9 

hoặc

WHERE SourceSystemKey >= 1 AND SourceSystemKey <= 9 

nếu SourceSystemKey là một số nguyên.Nhưng tôi không nghĩ rằng nó sẽ gây ra một sự thay đổi lớn.

Những gì tôi sẽ kiểm tra đầu tiên là xây dựng lại số liệu thống kê và xây dựng lại tất cả các chỉ mục cho bảng và chờ một thời gian. Xây dựng lại không phải là ngay lập tức, nó sẽ phụ thuộc vào cách bận rộn là máy chủ nhưng câu này được cấu trúc tốt cho chỉ mục được sử dụng bởi trình tối ưu hóa.

Trân trọng.

+0

gì làm bạn có ý nghĩa bởi "Bạn không cần nhóm theo một trường cố định"? Anh ấy đang tìm ngày tối đa. – Andomar

+0

Tôi đã thử giữa và nó không thay đổi bất cứ điều gì. Nó đang sử dụng chỉ mục và chỉ mục ban đầu tìm kiếm trả về 665 triệu hàng. Sử dụng công đoàn, nó tìm kiếm một hàng (trên cùng 1) cho mỗi lệnh được đặt hàng chính xác và siêu nhanh. Nếu không có liên minh, nó tìm kiếm 665 triệu hàng và lặp lại rất nhiều. Thật điên rồ. Cả hai truy vấn chắc chắn sử dụng cùng các chỉ mục trong kế hoạch. – Craig

+0

Andomar: Tôi đã nói về GROUP BY bởi vì nếu bạn đặt "WHERE SourceSystemKey = 3" tôi có thể thấy không có ý nghĩa trong "GROUP BY SourceSystemKey" bởi vì chỉ có một SourceSystemKey. Không có gì để nhóm, bạn đang tìm kiếm giá trị MAX tuyệt đối vượt qua bộ lọc WHERE. Nhưng bất kỳ cách nào trình tối ưu hóa biết điều đó và không phải là vấn đề. (chỉnh sửa: Nói về lệnh thứ 2. Trong trường hợp đầu tiên GROUP BY là OK, rõ ràng) –

0

Bạn đã thử tạo một chỉ mục khác ngay trên cột SourceSystemKey chưa? Số lần đọc lôgic cao khi bạn sử dụng cột đó trong mệnh đề where của bạn làm cho tôi nghĩ rằng nó đang thực hiện quét chỉ mục/bảng. Bạn có thể chạy kế hoạch thực hiện về điều này và xem nếu đó là trường hợp? Kế hoạch thực hiện cũng có thể đưa ra gợi ý chỉ mục.

2

của nó khó có thể nói mà không nhìn vào một kế hoạch thực hiện, tuy nhiên bạn có thể muốn thử như sau:

SELECT * FROM 
(
    SELECT MAX(t0.AsAtDateKey) AS [Date], t0.SourceSystemKey AS SourceSystem 
    FROM fctWMAUA (NOLOCK) AS t0 
    GROUP BY t0.SourceSystemKey 
) 
WHERE SourceSystem in (1,2,3,4,5,6,7,8,9) 

nó khó để nói mà không nhìn vào một kế hoạch thực hiện, nhưng tôi nghĩ rằng whats xảy ra là Máy chủ SQL không đủ thông minh để nhận ra rằng mệnh đề WHERE được chỉ định là lọc ra các nhóm và không có bất kỳ ảnh hưởng nào đối với các bản ghi được bao gồm cho mỗi nhóm. Ngay khi máy chủ SQL nhận ra điều này miễn phí để sử dụng một số tra cứu chỉ mục inteligent để tìm ra các giá trị tối đa (đó là những gì đang xảy ra trong truy vấn thứ hai của bạn)

Chỉ là một lý thuyết, nhưng nó có thể đáng để thử.

1

Sử dụng HAVING thay vì đề WHERE, do đó việc lọc sẽ xảy ra sau khi nhóm đã xảy ra:

SELECT MAX(AsAtDateKey) AS [Date], SourceSystemKey AS SourceSystem 
FROM fctWMAUA (NOLOCK) 
GROUP BY SourceSystemKey 
HAVING SourceSystemKey in (1,2,3,4,5,6,7,8,9) 

Tôi cũng không đặc biệt quan tâm đến mệnh đề IN, đặc biệt là khi nó có thể được thay thế bằng "< 10" hoặc "Từ 1 đến 9", được sử dụng tốt hơn bởi các chỉ mục được sắp xếp.

3

Tôi nhận thấy rằng giải pháp tốt nhất là như sau. Nó bắt chước phiên bản kết hợp của truy vấn và chạy rất nhanh.

40 lần đọc logic và thời gian thực thi là 3ms.

SELECT [t3].[value] 
FROM [dimSourceSystem] AS [t0] 
OUTER APPLY (
    SELECT MAX([t2].[value]) AS [value] 
    FROM (
     SELECT [t1].[AsAtDateKey] AS [value], [t1].[SourceSystemKey] 
     FROM [fctWMAUA] AS [t1] 
     ) AS [t2] 
    WHERE [t2].[SourceSystemKey] = ([t0].[SourceSystemKey]) 
    ) AS [t3]