CHỌN TOP 1 từ một bảng rất lớn trên cột chỉ mục rất chậm, nhưng không theo thứ tự ngược lại


16

Chúng tôi có một cơ sở dữ liệu lớn, khoảng 1TB, chạy SQL Server 2014 trên một máy chủ mạnh mẽ. Mọi thứ hoạt động tốt trong một vài năm. Khoảng 2 tuần trước, chúng tôi đã bảo trì đầy đủ, bao gồm: Cài đặt tất cả các bản cập nhật phần mềm; xây dựng lại tất cả các chỉ mục và tập tin DB nhỏ gọn. Tuy nhiên, chúng tôi không mong đợi rằng ở giai đoạn nhất định, việc sử dụng CPU của DB tăng hơn 100% đến 150% khi tải thực tế là như nhau.

Sau rất nhiều lần khắc phục sự cố, chúng tôi đã thu hẹp nó thành một truy vấn rất đơn giản, nhưng chúng tôi không thể tìm ra giải pháp. Truy vấn cực kỳ đơn giản:

select top 1 EventID from EventLog with (nolock) order by EventID

Nó luôn mất khoảng 1,5 giây! Tuy nhiên, một truy vấn tương tự với "desc" luôn mất khoảng 0 ms:

select top 1 EventID from EventLog with (nolock) order by EventID desc

PTable có khoảng 500 triệu hàng; EventIDlà cột chỉ mục cụm chính (được đặt hàng ASC) với kiểu dữ liệu của bigint (cột Danh tính). Có nhiều luồng chèn dữ liệu vào bảng ở trên cùng (EventID lớn hơn) và có 1 luồng xóa dữ liệu từ phía dưới (EventID nhỏ hơn).

Trong SMSS, chúng tôi đã xác minh rằng hai truy vấn luôn sử dụng cùng một kế hoạch thực hiện:

  • Quét chỉ mục cụm;

  • Số hàng ước tính và thực tế là cả 1;

  • Ước tính và số lần thực hiện thực tế là cả 1;

  • Ước tính chi phí I / O là 8500 (Có vẻ là cao)

  • Nếu chạy liên tiếp, chi phí Truy vấn là 50% cho cả hai.

Tôi cập nhật chỉ số thống kê with fullscan, vấn đề vẫn tồn tại; Tôi xây dựng lại chỉ mục một lần nữa, và vấn đề dường như đã biến mất trong nửa ngày, nhưng đã trở lại.

Tôi đã bật thống kê IO với:

set statistics io on

sau đó chạy hai truy vấn liên tiếp và tìm thấy thông tin sau:

(Đối với truy vấn đầu tiên, truy vấn chậm)

Bảng 'PTable'. Quét số 1, đọc logic 407670, đọc vật lý 0, đọc trước 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc 0, đọc trước 0.

(Đối với truy vấn thứ hai, truy vấn nhanh)

Bảng 'PTable'. Quét số 1, đọc logic 4, đọc vật lý 0, đọc trước đọc 0, đọc logic 0, đọc vật lý lob 0, đọc trước đọc 0, đọc trước 0.

Lưu ý sự khác biệt rất lớn trong việc đọc logic. Chỉ số được sử dụng trong cả hai trường hợp.

Phân mảnh chỉ số có thể giải thích một chút, nhưng tôi tin rằng tác động là rất nhỏ; và vấn đề chưa từng xảy ra trước đây. Một bằng chứng khác là nếu tôi chạy một truy vấn như:

select * from EventLog with (nolock) where EventID=xxxx   

Ngay cả khi tôi đặt xxxx thành các EventID nhỏ nhất trong bảng, truy vấn luôn nhanh như chớp.

Chúng tôi đã kiểm tra và không có vấn đề khóa / chặn.

Lưu ý: Tôi chỉ cố gắng đơn giản hóa vấn đề trên. "PTable" thực sự là "EventLog"; những PIDEventID.

Tôi nhận được thử nghiệm kết quả tương tự mà không có NOLOCKgợi ý.

Ai có thể giúp đỡ?

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

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

Các kế hoạch thực hiện truy vấn chi tiết hơn trong XML như sau:

https://www.brentozar.com/pastetheplan/?id=SJ3eiVnob

https://www.brentozar.com/pastetheplan/?id=r1rOjVhoZ

Tôi không nghĩ rằng nó quan trọng để cung cấp các tuyên bố tạo bảng. Nó là một cơ sở dữ liệu cũ và đã chạy hoàn toàn tốt trong một thời gian dài cho đến khi bảo trì. Chúng tôi đã thực hiện rất nhiều nghiên cứu và thu hẹp nó vào thông tin được cung cấp trong câu hỏi của tôi.

Bảng được tạo bình thường với EventIDcột là khóa chính, là identitycột kiểu bigint. Tại thời điểm này, tôi đoán vấn đề là với sự phân mảnh chỉ số. Ngay sau khi xây dựng lại chỉ số, vấn đề dường như đã biến mất trong nửa ngày; Nhưng tại sao nó lại quay lại nhanh như vậy ...?

Câu trả lời:


17

Quét chỉ mục cụm cho thấy 423.723 lần đọc logic để trả về hàng đầu tiên, mất 1926 ms:

QUẢ HẠCH

Điều này có vẻ khá nhiều để xác định hàng đầu tiên theo thứ tự chỉ mục.

Nhiều khả năng nhiệm vụ dọn dẹp ma của bạn đang chạy một chặng đường dài phía sau, hoặc đã dừng lại. Bạn nên kiểm tra ghost_record_countchỉ số được nhóm sys.dm_db_index_physical_statsvà theo dõi các thay đổi theo thời gian.

Quá trình quét theo thứ tự từ cuối chỉ mục đang thấy hoạt động xóa liên tục phải quét qua rất nhiều bản ghi bị ma trước khi nó tìm thấy hàng 'còn sống' đầu tiên quay trở lại. Điều này giải thích các lần đọc logic thêm. Việc tìm kiếm cây b xuống giá trị thấp nhất của chỉ mục sẽ gặp các bản ghi ma ít hơn nhiều.

Một yếu tố ảnh hưởng đến hiệu suất khác là bản thân quá trình quét trở thành trách nhiệm xóa các bản ghi ma như được đề cập trong Inside the Storage Engine: Ghost dọn dẹp theo chiều sâu của Paul Randal.

Bạn nên kiểm tra xem cờ theo dõi 661 (vô hiệu hóa dọn dẹp ma) không hoạt động.

Các giải pháp

Nếu quá trình dọn dẹp ma đã dừng hoàn toàn, giải pháp hiệu quả nhất thường là khởi động lại phiên bản SQL Server. Bạn cũng nên đảm bảo rằng Máy chủ SQL đang chạy một trong các Cập nhật tích lũy mới nhất. Đã có nhiều lỗi dọn dẹp ma trong những năm qua.

Trong trường hợp cụ thể của bạn:

Hóa ra vấn đề là do một cơ sở dữ liệu thử nghiệm khác trên cùng một máy chủ. Cơ sở dữ liệu kiểm tra đó đã được khôi phục với "mất dữ liệu" và bị hỏng. Đáng ngạc nhiên, quá trình dọn dẹp ma rõ ràng đã bị mắc kẹt trong cơ sở dữ liệu đó. Khi chúng tôi xóa cơ sở dữ liệu bị hỏng đó khỏi SMSS, sự cố đã tự khắc phục (mất một thời gian dài và có thể khiến DB bị khóa trong một thời gian ngắn).

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.