Tại sao SQL Server trả về một số hàng trong khi vẫn thực hiện truy vấn và đôi khi không?


33

Có những truy vấn khi chúng ta nhấn "thực thi", nó hiển thị một số hàng và nó tiếp tục phát triển, nhưng truy vấn vẫn chưa kết thúc. Tuy nhiên, đôi khi, nó chờ cho đến khi kết thúc truy vấn.

Lý do tại sao điều này xảy ra? Có cách nào để kiểm soát điều này?

Câu trả lời:


43

Câu trả lời, như thường lệ (ổn thôi, hầu hết thời gian), nằm trong kế hoạch thực hiện.

Có một số toán tử nhất định yêu cầu tất cả các hàng đến chúng trước khi chúng có thể bắt đầu xử lý các hàng đó và chuyển chúng xuống dưới, ví dụ:

  • Hash Tham gia (xây dựng bảng băm)
  • Trận đấu băm
  • Sắp xếp (Ngoại trừ Hash Flow riêng biệt)

Chúng được gọi là chặn hoặc dừng và đi các nhà khai thác vì điều này và chúng thường được chọn khi trình tối ưu hóa nghĩ rằng nó sẽ phải xử lý toàn bộ nhiều dữ liệu để tìm dữ liệu của bạn.

Có các toán tử khác có thể bắt đầu truyền phát hoặc chuyển bất kỳ hàng nào được tìm thấy ngay lập tức

  • Vòng lồng nhau
  • Chỉ số hỗ trợ hợp nhất
  • Tập hợp luồng

Khi các truy vấn bắt đầu trả về dữ liệu ngay lập tức, nhưng không kết thúc ngay lập tức, đó thường là dấu hiệu cho thấy trình tối ưu hóa đã chọn một kế hoạch để xác định vị trí và trả lại một số hàng một cách nhanh chóng bằng cách sử dụng các toán tử có chi phí khởi động thấp hơn.

Điều này có thể xảy ra do các mục tiêu hàng được giới thiệu bởi bạn hoặc bởi trình tối ưu hóa.

Nó cũng có thể xảy ra nếu một kế hoạch xấu được chọn vì một số lý do (thiếu SARGability, đánh hơi thông số, không đủ số liệu thống kê, v.v.), nhưng điều đó cần phải đào sâu hơn để tìm ra.

Để biết thêm thông tin, hãy xem blog của Rob Farley tại đây

Và loạt bài của Paul White về các mục tiêu hàng ở đây , đây , đâyđây .

Cũng cần lưu ý rằng, nếu bạn đang nói về SSMS, các hàng chỉ xuất hiện khi toàn bộ bộ đệm đã được lấp đầy, không chỉ là willy-nilly.


14

Nếu tôi hiểu những gì bạn đang quan sát, thì đây là cách Management Studio kết xuất các hàng và không liên quan gì đến cách SQL Server trả về các hàng. Trong thực tế thường khi bạn trả lại kết quả lớn cho SSMS và cố gắng hiển thị chúng trong một lưới, SSMS không thể theo kịp và SQL Server kết thúc chờ ứng dụng xử lý nhiều hàng hơn. Trong trường hợp này, bạn sẽ thấy SQL Server tích lũy ASYNC_NETWORK_IOchờ đợi.

Bạn có thể kiểm soát phần nào bằng cách sử dụng Kết quả thành Văn bản thay vì Kết quả thành Lưới, vì SSMS có thể vẽ văn bản nhanh hơn khả năng vẽ lưới, nhưng bạn có thể thấy điều này có thể ảnh hưởng đến khả năng đọc tùy thuộc vào số lượng cột và loại dữ liệu liên quan. Cả hai đều bị ảnh hưởng bởi khi SSMS quyết định thực sự ghi kết quả ra khung đó, điều này phụ thuộc vào mức độ đầy đủ của bộ đệm đầu ra.

Khi bạn có nhiều câu lệnh và bạn muốn buộc bộ đệm hiển thị kết quả đầu ra vào ngăn thông báo, bạn có thể sử dụng một mẹo in nhỏ ở giữa các câu lệnh:

RAISERROR('', 0, 1) WITH NOWAIT;

Nhưng điều này sẽ không hữu ích khi bạn đang cố gắng để SSMS hiển thị các hàng nhanh hơn khi tất cả đầu ra đến từ một câu lệnh.

Trực tiếp hơn, bạn có thể kiểm soát nó bằng cách giới hạn số lượng kết quả bạn đang hiển thị trong SSMS. Tôi thường thấy mọi người phàn nàn về việc mất bao lâu để trả lại một triệu hàng cho lưới. Bất cứ ai trên trái đất sẽ làm gì với một triệu hàng trong lưới SSMS, tôi không biết.

Có một số hack như OPTION (FAST 100), sẽ tối ưu hóa để lấy 100 hàng đầu tiên (hoặc 100 hàng bất kỳ nếu không có bên ngoài ORDER BY), nhưng điều này có thể phải trả giá khi truy xuất chậm hơn nhiều cho phần còn lại của hàng và kế hoạch nhiều hơn Nhìn chung không hiệu quả, vì vậy, đây không thực sự là một lựa chọn đi đến IMHO.


1

Câu hỏi của bạn không phải là về SQLServer mỗi se mà là:

  • Máy chủ SQL
  • mạng
  • SSMS là ứng dụng khách

Có cách nào để kiểm soát điều này?

Câu trả lời ngắn gọn :

  1. Hãy thử sqlcmdthay vì ssmshoặc sqlcmd-mode củassms
  2. Kiểm tra cài đặt kết nối và phiên của bạn

Câu trả lời dài :

Tất nhiên! Nhưng không phải là một - thăm dò

  1. Thực hiện truy vấn của bạn với sqlcmdhoặc trong sqlcmd-mode trong ssms.
  2. Nếu bạn muốn loại trừ vai trò của mạng - hãy chạy truy vấn của bạn trên máy chủ có kết nối Bộ nhớ chung.
  3. Nếu hiệu suất truy vấn không thỏa mãn ngay cả với kết nối Bộ nhớ được chia sẻ - hãy phân tích các kế hoạch thực hiện của bạn. Nếu truy vấn thực hiện không tốt qua mạng - hãy gọi cho quản trị viên mạng của bạn để được trợ giúp. Nếu truy vấn của bạn chỉ thực hiện xấu trong SSMS - hãy đọc thêm.
  4. Bây giờ chúng tôi chắc chắn rằng các vấn đề nằm ở phía khách hàng (ssms trong trường hợp này). Nhìn vào cài đặt kết nối và phiên trong SSMS. Đừng tin giao diện ssms và kiểm tra với SQL Profiler: tìm kết nối của bạn bằng cách spidvà bạn có được danh sách đầy đủ các cài đặt phiên. So sánh với các cài đặt của sqlcmdphiên. Nếu không có gì nhấp chuột - sao chép tất cả các cài đặt phiên từ trình lược tả vào tập lệnh truy vấn của bạn, hãy thực hiện trong sqlcmd-mode và chuyển dần cài đặt bạn sẽ tìm thấy thủ phạm của mình.

Chúc may mắn!


-2

Để thêm vào câu trả lời của sp_BlitzErik, hãy lấy ví dụ bằng cách sử dụng a NOT IN ()với phụ chọn. Để xác định xem một mục có nằm trong kết quả của truy vấn lồng nhau hay không, nói chung (cần) phải lấy toàn bộ kết quả.

Vì vậy, một cách dễ dàng mà tôi đã tìm thấy để cải thiện hiệu suất của các truy vấn đó là viết lại chúng như một LEFT OUTER JOINđiều kiện trong đó điều kiện cho RIGHTbên là null (tất nhiên bạn có thể lật nó, nhưng ai sử dụng RIGHT OUTER JOINS?). Điều này cho phép các kết quả bắt đầu trở lại ngay lập tức.


Tôi không nghĩ vậy. Nếu các cột được so sánh là không thể rỗng, thì kết quả sẽ giống nhau và các kế hoạch - thông thường - giống nhau, cho 3 phiên bản của một antijoin (KHÔNG IN, KHÔNG EXISTS, LEFT THAM GIA / LÀ NULL). Không cần thiết phải lấy toàn bộ kết quả.
ypercubeᵀᴹ

Nếu lựa chọn phụ là một truy vấn thực sự phức tạp mà truy vấn được tạo ra cần phải đánh giá toàn bộ lựa chọn phụ trước khi kiểm tra điều kiện KHÔNG IN, WHERE t.x IN (<complex SELECT subquery>)thì TRÁI LEFT JOIN (<complex SELECT subquery>) AS r ON r.x = t.x .... WHERE r.x IS NULLPHIẾU tương đương , thì cũng sẽ đánh giá truy vấn con (vì vậy cũng có kế hoạch phức tạp với KHÔNG Phiên bản IN).
ypercubeᵀᴹ

@ ypercubeᵀᴹ Nó đã làm việc cho tôi trong quá khứ. Tôi đã thấy các truy vấn đi từ mất vài phút để trở lại thứ hai.
JimmyJames

@ ypercubeᵀᴹ Tôi đã đưa ra một ví dụ đơn giản trong Oracle (xin lỗi hiện tại tôi không có quyền truy cập vào SQLServer) và họ chắc chắn có các kế hoạch giải thích khác nhau. Có lẽ chúng không có ý nghĩa khác biệt nhưng chúng trông khá khác nhau.
JimmyJames

@JimmyJames: đó không phải là cách đơn giản nếu bạn muốn hiệu suất ổn định và những "tối ưu hóa" như vậy rất nhạy cảm đối với phiên bản SQLServer. Và đừng phạm sai lầm lôi cuốn Oracle (phiên bản nào?). Trong lịch sử SQLServer thích NOT EXISTSnhưng Oracle NOT INtrong các truy vấn. Nhưng hôm nay nó phải được coi là lỗi trong trình tạo kế hoạch
Alex Yu
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.