Câu hỏi này đã được đăng lên #sqlhelp bởi Jake Manske và tôi đã thu hút sự chú ý của Erik Darling.
Tôi không nhớ đã từng gặp sự cố hiệu suất với sys.partitions
. Suy nghĩ ban đầu của tôi (được nhắc lại bởi Joey D'Antoni) là một bộ lọc trên data_compression
cột nên tránh quét dư thừa và giảm khoảng một nửa thời gian chạy truy vấn. Tuy nhiên, vị từ này không bị đẩy xuống và lý do tại sao cần một chút giải nén.
Tại sao sys.partitions chậm?
Nếu bạn nhìn vào định nghĩa cho sys.partitions
, về cơ bản đó là những gì Jake đã mô tả - một UNION ALL
của tất cả các phân vùng kho hàng và kho hàng, với BA tham chiếu rõ ràng đến sys.sysrowsets
(nguồn viết tắt tại đây):
TẠO XEM sys.partitions NHƯ VỚI partition_columnstore (... cols ...) AS (SELECT ... cols ..., cmprlevel AS data_compression ... FROM sys.sysrowsets rs NGOÀI RA ÁP DỤNG OpenRowset (BẢNG ALUCOUNT, rs .rowsetid, 0, 0, 0) ct -------- *** ^^^^^^^^^^^^^^^ *** TRÁI THAM GIA sys.syspalvalues cl ... Ở ĐÂU .. . sysconv (bit, rs.status &0x00010000) =1 - Chỉ xem xét các chỉ mục cơ sở columnstore), phân vùng_rowstore (... cols ...) AS (SELECT ... cols ..., cmprlevel AS data_compression ... FROM sys.sysrowsets rs -------- *** ^^^^^^^^^^^^^^^ *** TRÁI THAM GIA sys.syspalvalues cl ... WHERE ... sysconv (bit, rs .status &0x00010000) =0 - Bỏ qua chỉ mục cơ sở columnstore và các hàng mồ côi.) CHỌN ... cột ... từ phân vùng_rowstore p NGOÀI RA ÁP DỤNG OpenRowset (BẢNG ALUCOUNT, p.partition_id, 0, 0, p.object_id) ct union tất cả SELECT ... cols ... FROM partition_columnstore as P1 LEFT JOIN (CHỌN ... cols ... FROM sys.sysrowsets rs OUTER APP LY OpenRowset (TABLE ALUCOUNT, rs.rowsetid, 0, 0, 0) ct ------- *** ^^^^^^^^^^^^^^ ***) ...Quan điểm này có vẻ được kết hợp với nhau, có thể là do lo ngại về khả năng tương thích ngược. Nó chắc chắn có thể được viết lại để hiệu quả hơn, đặc biệt là để chỉ tham chiếu đến
sys.sysrowsets
vàTABLE ALUCOUNT
đối tượng một lần. Nhưng bạn hoặc tôi không thể làm gì nhiều về điều đó ngay bây giờ.Cột
cmprlevel
đến từsys.sysrowsets
(một tiền tố bí danh trên tham chiếu cột sẽ hữu ích). Bạn hy vọng rằng một vị từ chống lại một cột ở đó sẽ xảy ra một cách hợp lý trước bất kỳOUTER APPLY
nào và có thể ngăn chặn một trong các lần quét, nhưng đó không phải là điều xảy ra. Chạy truy vấn đơn giản sau:CHỌN * TỪ sys.partitions AS p INNER THAM GIA sys.objects AS o ON p.object_id =o.object_id WHERE o.is_ms_shipped =0;Mang lại kế hoạch sau khi có các chỉ mục cột trong cơ sở dữ liệu (bấm để phóng to):
Lập kế hoạch cho sys.partitions, với các chỉ mục columnstore hiện diện
Và kế hoạch sau đây khi không có (bấm vào để phóng to):
Lập kế hoạch cho sys.partitions, không có chỉ mục cột nào
Đây là cùng một kế hoạch ước tính, nhưng SentryOne Plan Explorer có thể đánh dấu khi một thao tác bị bỏ qua trong thời gian chạy. Điều này xảy ra cho lần quét thứ ba trong trường hợp thứ hai, nhưng tôi không biết rằng có bất kỳ cách nào để giảm số lần quét thời gian chạy đó hơn nữa; lần quét thứ hai xảy ra ngay cả khi truy vấn trả về không hàng.
Trong trường hợp của Jake, anh ấy có rất nhiều của các đối tượng, vì vậy việc thực hiện quét này thậm chí hai lần là đáng chú ý, gây đau đớn và một lần là quá nhiều. Và thành thật mà nói, tôi không biết liệu
TABLE ALUCOUNT
, một lệnh gọi lặp lại nội bộ và không có tài liệu, cũng phải quét một số đối tượng lớn hơn này nhiều lần.Nhìn lại nguồn, tôi tự hỏi liệu có bất kỳ vị từ nào khác có thể được chuyển đến chế độ xem có thể ép buộc hình dạng kế hoạch hay không, nhưng tôi thực sự không nghĩ rằng có bất cứ điều gì có thể có tác động.
Chế độ xem khác có hoạt động không?
Tuy nhiên, chúng tôi hoàn toàn có thể thử một góc nhìn khác. Tôi đã tìm kiếm các dạng xem khác có chứa các tham chiếu đến cả
sys.sysrowsets
vàALUCOUNT
và có nhiều thứ hiển thị trong danh sách, nhưng chỉ có hai cái là hứa hẹn:sys.internal_partitions
vàsys.system_internals_partitions
.sys.internal_partitions
Tôi đã thử
sys.internal_partitions
đầu tiên:CHỌN * TỪ sys.internal_partitions AS p INNER JOIN sys.objects AS o ON p.object_id =o.object_id WHERE o.is_ms_shipped =0;Nhưng kế hoạch cũng không khả quan hơn (bấm vào để phóng to):
Lập kế hoạch cho sys.internal_partitions
Chỉ có hai lần quét đối với
sys.sysrowsets
lần này, nhưng việc quét dù sao cũng không liên quan vì truy vấn không đến gần tạo ra các hàng mà chúng tôi quan tâm. Chúng tôi chỉ thấy các hàng cho các đối tượng liên quan đến cột (như tài liệu đã nêu).sys.system_internals_partitions
Hãy thử
sys.system_internals_partitions
. Tôi hơi cảnh giác về điều này, vì nó không được hỗ trợ (xem cảnh báo ở đây), nhưng hãy đợi tôi một chút:CHỌN * TỪ sys.system_internals_partitions AS p INNER JOIN sys.objects AS o ON p.object_id =o.object_id WHERE o.is_ms_shipped =0;Trong cơ sở dữ liệu có chỉ mục columnstore, có một quá trình quét đối với
sys.sysschobjs
, nhưng bây giờ chỉ có một quét chống lạisys.sysrowsets
(bấm để phóng to):Lập kế hoạch cho sys.system_internals_partitions, với các chỉ mục cột có sẵn
Nếu chúng tôi chạy cùng một truy vấn trong cơ sở dữ liệu mà không có chỉ mục columnstore, thì kế hoạch thậm chí còn đơn giản hơn, với tìm kiếm đối với
sys.sysschobjs
(bấm để phóng to):Lập kế hoạch cho sys.system_internals_partitions, không có chỉ mục cột nào
Tuy nhiên, điều này không hoàn toàn những gì chúng ta đang theo đuổi, hoặc ít nhất không hoàn toàn là những gì Jake đang theo đuổi, bởi vì nó cũng bao gồm các đồ tạo tác từ các chỉ mục của Columnstore. Nếu chúng tôi thêm các bộ lọc này, đầu ra thực tế bây giờ khớp với truy vấn trước đó, đắt hơn nhiều của chúng tôi:
CHỌN * TỪ sys.system_internals_partitions AS p INNER JOIN sys.objects AS o ON p.object_id =o.object_id WHERE o.is_ms_shipped =0 VÀ p.is_columnstore =0 VÀ p.is_orphaned =0;Như một phần thưởng, quét chống lại
sys.sysschobjs
đã trở thành một tìm kiếm ngay cả trong cơ sở dữ liệu với các đối tượng columnstore. Hầu hết chúng ta sẽ không nhận thấy sự khác biệt đó, nhưng nếu bạn đang ở trong một trường hợp giống như trường hợp của Jake, bạn chỉ có thể (nhấp để phóng to):Kế hoạch đơn giản hơn cho sys.system_internals_partitions, với các bộ lọc bổ sung
sys.system_internals_partitions
hiển thị một tập hợp cột khác vớisys.partitions
(một số khác hoàn toàn, một số khác có tên mới) vì vậy, nếu bạn đang sử dụng đầu ra ở phía dưới, bạn sẽ phải điều chỉnh cho phù hợp. Bạn cũng sẽ muốn xác thực rằng nó trả về tất cả thông tin bạn muốn trên các chỉ mục rowstore, bộ nhớ được tối ưu hóa và cột, và đừng quên về những đống phiền phức đó. Và cuối cùng, hãy sẵn sàng bỏ đis
tronginternals
rất nhiều lần.Kết luận
Như tôi đã đề cập ở trên, chế độ xem hệ thống này không được hỗ trợ chính thức, vì vậy chức năng của nó có thể thay đổi bất cứ lúc nào; nó cũng có thể được di chuyển theo Kết nối quản trị viên chuyên dụng (DAC) hoặc bị xóa hoàn toàn khỏi sản phẩm. Vui lòng sử dụng phương pháp này nếu
sys.partitions
không hoạt động tốt cho bạn nhưng hãy đảm bảo rằng bạn có một kế hoạch dự phòng. Và đảm bảo rằng nó được ghi lại như một thứ mà bạn kiểm tra hồi quy khi bắt đầu thử nghiệm các phiên bản SQL Server trong tương lai hoặc sau khi bạn nâng cấp, đề phòng.