CHỌN COUNT (*) trên một chế độ xem là các đơn đặt hàng có cường độ chậm hơn so với CHỌN * trên cùng một chế độ xem


7

Cái nhìn

CREATE VIEW [dbo].[vProductList]
WITH SCHEMABINDING
AS 

SELECT
     p.[Id]
    ,p.[Name]
    ,price.[Value] as CalculatedPrice
    ,orders.[Value] as OrdersWithThisProduct
FROM 
    products as p 
    INNER JOIN productMetadata as price ON p.Id = price.ProductId AND price.MetaId = 1
    INNER JOIN productMetadata as orders ON p.Id = orders.ProductId AND orders.MetaId = 2

Để đơn giản, giả sử rằng productMetadatacác cột ProductId, MetaId, Valuecó ~ 87m hàng và có khoảng 400k hàng trong productsbảng.

Các truy vấn chung chống lại quan điểm này hoạt động hoàn hảo:

SELECT * FROM vProductList WHERE CalculatedPrice > 500

Kết quả truy vấn trong 2-4 giây (trên vpn và từ xa, vì vậy tôi rất tốt với điều đó).

Thay đổi số trên thành số đếm cũng nhanh không kém:

SELECT COUNT(*) from vProductList WHERE CalculatedPrice > 500

chạy trong cùng thời gian với lựa chọn thô, một lần nữa tôi thấy ổn. Có khoảng 10k sản phẩm đáp ứng tiêu chí này.

Tôi đã gặp hai trường hợp riêng biệt, nơi mọi thứ trở nên thực sự kỳ quặc và mất TUYỆT VỜI.

Đầu tiên

Thực hiện truy vấn đối với một trong các cột từ bảng cơ sở trong dạng xem:

SELECT * FROM vProductList WHERE Name = 'Hammer' 

Truy vấn này mất một chút thời gian để chạy (20-30 giây) và trả về kết quả ~ 30k; tuy nhiên, một thay đổi nhỏ đối với truy vấn đã nói:

SELECT COUNT(*) FROM vProductList WHERE Name = 'Hammer' 

mất mười ba PHÚT để trả lại số đếm ~ 30k.

Thứ hai

Làm một WHERE INtruy vấn con

SELECT * FROM vProductList WHERE Id IN (SELECT ProductId FROM TableThatHasFKToProductId and ColumnInTable = 'Yes')

Truy vấn này trả về ~ 300k hàng và mất hai phút để trả về (phần lớn thời gian đó chỉ đơn giản là dành để tải dữ liệu vào SSMS tôi tin); tuy nhiên, thay đổi điều đó thành SELECT COUNT(*)kết quả trong một truy vấn mất hai mươi phút.

SELECT COUNT(*) FROM vProductList WHERE Id IN (SELECT ProductId FROM TableThatHasFKToProductId and ColumnInTable = 'Yes')

Tại sao nó SELECT *nhanh hơn SELECT COUNT?

Tôi đang sử dụng Tổng thời gian thực hiện do SSMS cung cấp cho tất cả các thời gian được liệt kê ở đây.

Kế hoạch thực hiện

Lập kế hoạch cho SELECT 1 FROM v WHERE IN (...)

Lập kế hoạch cho SELECT COUNT(0) FROM v WHERE IN (...)

Lưu ý: Tôi đã thử sử dụng PasteThePlan nhưng nó vẫn báo cho biết gói của tôi không hợp lệ xml.

Câu trả lời:


5

Từ các kế hoạch thực hiện được cung cấp, trong COUNTtrường hợp, trình tối ưu hóa chọn chiến lược tổng hợp cục bộ / toàn cầu xung quanh lần tham gia cuối cùng:

Tham gia cuối cùng

Thật không may, trình tối ưu hóa đánh giá quá cao hiệu quả của tập hợp cục bộ. Ước tính 136 hàng điều khiển tham gia Vòng lặp lồng nhau, trong khi đó có tới 136.115 khi chạy.

Ước tính

Việc tìm kiếm chỉ mục 366.115 có thể không phải là vấn đề quá lớn đối với phiên bản SQL Server cục bộ, nhưng các thống kê chờ trong kế hoạch cho thấy các giới hạn I / O (và có thể là bộ nhớ) của cấu hình Cơ sở dữ liệu Azure SQL hiện tại của bạn:

Thống kê chờ

Kế hoạch cho SELECT 1thấy một chiến lược tham gia băm và hợp nhất độc quyền, tạo ra kết quả tốt hơn trong trường hợp này với bộ nhớ và / hoặc khả năng I / O rất hạn chế.

Bạn có thể thấy hiệu suất tốt hơn cho truy vấn đầu tiên với một OPTION (HASH JOIN, MERGE JOIN)gợi ý, nhưng vấn đề cơ bản là ước tính phân phối dữ liệu / thẻ dữ liệu kém được điều khiển bởi số lượng lớn các phép nối.

Đừng bị nhầm lẫn bởi tỷ lệ phần trăm chi phí được hiển thị đối với mỗi nhà khai thác kế hoạch - những con số này hiện được lấy từ ước tính chi phí của trình tối ưu hóa (sử dụng mô hình trừu tượng). Các con số không phản ánh điều kiện thời gian chạy hoặc chi phí.

Độ lệch lớn giữa số lượng hàng ước tính và thực tế thường có thể dẫn đến các vấn đề. Điều này đặc biệt đúng đối với việc đánh giá thấp khiến trình tối ưu hóa chọn chiến lược không mở rộng tốt trên một thiết lập phần cứng cụ thể.

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.