Tôi có một câu hỏi SQL tiên tiến cho SQL của bạn Perf guru ngoài kia :-)SQL Server truy vấn - không hoạt động như mong đợi, không hành xử như tôi nghĩ rằng nó sẽ
Tôi hiện đang cố gắng tìm hiểu một số hành vi trong một ứng dụng lớn hơn, nhưng nó nắm tới một truy vấn đối với hai bảng sau đây:
Users
bảng - khoảng 750 mục,UserId
(varchar(50)
) như nhóm PKActionLog
bảng - hàng triệu mục, bao gồmUserId
- nhưng không có mối quan hệ FK
Đối với lưới trong ứng dụng ASP.NET của tôi, tôi đang cố gắng để có được tất cả người dùng cộng với ngày nhập nhật ký cuối cùng của họ.
Các câu lệnh SQL mà hiện đang được sử dụng trông giống như sau:
SELECT
UserId, (other columns),
LastLogDate = (SELECT TOP (1) [Timestamp] FROM dbo.ActionLog a WHERE a.UserId = u.UserId ORDER BY [Timestamp] DESC)
FROM
dbo.Users u;
và nó sẽ trả về các hàng để hiển thị - nhưng nó khá chậm (khoảng 20 giây.).
Suy nghĩ đầu tiên của tôi là để thêm một chỉ mục trên bảng ActionLog
trên UserId
và để bao gồm các Timestamp
cột trong nó:
CREATE NONCLUSTERED INDEX [IDX_UserId]
ON [dbo].[ActionLog]([UserId] ASC)
INCLUDE ([Timestamp])
Các hàng đang trở lại rất nhanh - dưới 2 giây, với 350'000 các mục nhập trong bảng ActionLog
và chỉ mục của tôi đang được sử dụng tốt, vì kế hoạch thực hiện hiển thị cho tôi. Tất cả có vẻ ổn. Bây giờ, để xấp xỉ kịch bản sản xuất, chúng tôi đã tải khoảng 2 triệu hàng vào bảng ActionLog
, 95% hoặc hơn trong số đó đề cập đến người dùng không tồn tại (tức là các hàng này có một số UserId
không tồn tại trong Users
bảng).
Bỗng nhiên, truy vấn trở thành cực kỳ chậm (24 phút!) Và chỉ mục không còn được sử dụng nữa.
Tôi cho rằng kể từ khi đại đa số các mục trong bảng ActionLog
không thẳng hàng với một người dùng hiện, tôi sẽ thấy tăng hiệu suất nếu tôi sử dụng một chỉ số lọc - để "lọc bỏ" tất cả những lộn xộn mục mà không có một người sử dụng tương ứng - vì vậy tôi tạo ra chỉ số này (thay thế một trong những khác đã tồn tại trước đó):
CREATE NONCLUSTERED INDEX [IDX_UserId]
ON [dbo].[Log]([UserId] ASC)
INCLUDE ([Timestamp])
WHERE UserId <> 'user' -- that's the fixed, non-existing "UserId" I wanted to avoid
Nhưng để mất tinh thần của tôi - truy vấn vẫn về cùng là - mất hơn 20 phút để hoàn thành. Tôi cập nhật số liệu thống kê - không thay đổi - vẫn cực kỳ chậm.
Điều thú vị (đối với tôi) là: khi tôi xóa chỉ mục và tạo lại nó -> bây giờ truy vấn thực sự nhanh chóng trở lại (một lần nữa ít hơn 3 giây). WOW!
Nhưng ngay sau khi tôi bắt đầu thêm các mục nhập khác một lần nữa, truy vấn "nghiêng" và trở nên thực sự thực sự chậm .......
Tôi không hiểu tại sao điều này xảy ra - tôi đã nghĩ rằng với chỉ mục được lọc loại bỏ tất cả các mục "giả mạo" đó, tôi sẽ thấy hiệu suất tốt khi cố tìm mục nhập ActionLog
mới nhất cho người dùng hiện tại - nhưng đó không phải là trường hợp.
TẠI SAO KHÔNG?
Bất kỳ ý tưởng nào? Suy nghĩ? Những điều cần thử ??
Bạn có thể gửi hoặc mô tả kế hoạch thực hiện khi bạn thả và tạo lại chỉ mục so với khi bạn bắt đầu thêm nhiều mục nhập hơn và nó bị hỏng? Là nó chỉ quyết định không sử dụng chỉ mục sau khi hàng được thêm vào? – jimdrang
Thử thêm biểu thức lọc vào truy vấn phụ tương quan của bạn 'a.UserId <> 'user''. Tôi nghĩ rằng trình tối ưu hóa cần nó để xem xét chỉ số đã lọc. –
Có một số mẹo về cách tạo và sử dụng chỉ mục được lọc trên MSDN. Bạn có thể thử chỉ định 'WITH (INDEX (IDX_UserId))' ở cuối mệnh đề 'SELECT'. Tham khảo: [Tạo chỉ mục lọc] (http://msdn.microsoft.com/en-us/library/cc280372.aspx) –