Tôi đang gặp khó khăn trong việc hiểu tại sao SQL Server sẽ đưa ra một ước tính có thể dễ dàng được chứng minh là không phù hợp với số liệu thống kê.
Tính nhất quán
Không có sự đảm bảo chung về tính nhất quán. Ước tính có thể được tính trên các cây con khác nhau (nhưng tương đương về mặt logic) tại các thời điểm khác nhau, sử dụng các phương pháp thống kê khác nhau.
Không có gì sai với logic nói rằng việc tham gia hai cây con giống hệt nhau phải tạo ra một sản phẩm chéo, nhưng cũng không có gì để nói rằng sự lựa chọn lý luận là âm thanh hơn bất kỳ thứ gì khác.
Dự toán ban đầu
Trong trường hợp cụ thể của bạn, ước tính cardinality ban đầu cho phép nối không được thực hiện trên hai cây con giống hệt nhau . Hình dạng cây lúc đó là:
Đăng nhập
LogOp_GbAgg
LogOp_LeftOuterJoin
LogOp_Get TBL: ar
Đăng nhập
LogOp_Get TBL: tcr
ScaOp_Comp x_cmpEq
ScaOp_Identifier [tcr] .rId
Giá trị ScaOp_Const = 508
ScaOp_Logical x_lopAnd
ScaOp_Comp x_cmpEq
ScaOp_Identifier [ar] .fId
ScaOp_Identifier [tcr] .fId
ScaOp_Comp x_cmpEq
ScaOp_Identifier [ar] .bId
ScaOp_Identifier [tcr] .bId
AncOp_PrjList
AncOp_PrjEl Expr1003
ScaOp_AggFunc stopMax
ScaOp_Convert int
ScaOp_Identifier [tcr] .isS
Đăng nhập
LogOp_GbAgg
LogOp_LeftOuterJoin
LogOp_Get TBL: ar
Đăng nhập
LogOp_Get TBL: tcr
ScaOp_Comp x_cmpEq
ScaOp_Identifier [tcr] .rId
Giá trị ScaOp_Const = 508
ScaOp_Logical x_lopAnd
ScaOp_Comp x_cmpEq
ScaOp_Identifier [ar] .fId
ScaOp_Identifier [tcr] .fId
ScaOp_Comp x_cmpEq
ScaOp_Identifier [ar] .bId
ScaOp_Identifier [tcr] .bId
AncOp_PrjList
AncOp_PrjEl Expr1006
ScaOp_AggFunc stopMin
ScaOp_Convert int
ScaOp_Identifier [ar] .isT
AncOp_PrjEl Expr1007
ScaOp_AggFunc stopMax
ScaOp_Convert int
ScaOp_Identifier [tcr] .isS
ScaOp_Comp x_cmpEq
ScaOp_Identifier Expr1006
Giá trị ScaOp_Const = 1
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [ar] .fId
ScaOp_Identifier QCOL: [ar] .fId
Là người đầu tiên tham gia đầu vào đã có một tổng unprojected đơn giản hóa đi, và lần thứ hai tham gia vào có vị t.isT = 1
đẩy dưới nó, nơi t.isT
là MIN(CONVERT(INT, ar.isT))
. Mặc dù vậy, tính toán chọn lọc cho isT
vị từ có thể sử dụng CSelCalcColumnInInterval
trên biểu đồ:
CSelCalcColumnInInterval
Cột: COL: Expr1006
Biểu đồ được tải cho cột QCOL: [ar] .isT từ số liệu thống kê với id 3
Độ chọn lọc: 4.85248e-005
Bộ sưu tập số liệu thống kê được tạo:
CStCollFilter (ID = 11, CARD = 1)
CStCollgroupBy (ID = 10, CARD = 20608)
CStCollOuterJoin (ID = 9, CARD = 20608 x_jtLeftOuter)
CStCollBaseTable (ID = 3, CARD = 20608 TBL: ar)
CStCollFilter (ID = 8, CARD = 1)
CStCollBaseTable (ID = 4, CARD = 28 TBL: tcr)
Kỳ vọng (chính xác) là cho 20.608 hàng được giảm xuống 1 hàng theo vị từ này.
Tham gia dự toán
Câu hỏi bây giờ trở thành cách 20.608 hàng từ đầu vào tham gia khác sẽ khớp với một hàng này:
Đăng nhập
CStCollgroupBy (ID = 7, CARD = 20608)
CStCollOuterJoin (ID = 6, CARD = 20608 x_jtLeftOuter)
...
CStCollFilter (ID = 11, CARD = 1)
CStCollgroupBy (ID = 10, CARD = 20608)
...
ScaOp_Comp x_cmpEq
ScaOp_Identifier QCOL: [ar] .fId
ScaOp_Identifier QCOL: [ar] .fId
Có một số cách khác nhau để ước tính sự tham gia nói chung. Chúng ta có thể, ví dụ:
- Lấy biểu đồ mới tại mỗi toán tử kế hoạch trong mỗi cây con, căn chỉnh chúng tại liên kết (nội suy các giá trị bước khi cần thiết) và xem chúng khớp với nhau như thế nào; hoặc là
- Thực hiện căn chỉnh biểu đồ 'thô' đơn giản hơn (sử dụng các giá trị tối thiểu và tối đa, không phải từng bước); hoặc là
- Tính toán các lựa chọn riêng biệt cho các cột tham gia (từ bảng cơ sở và không có bất kỳ bộ lọc nào), sau đó thêm vào hiệu ứng chọn lọc của (các) vị từ không tham gia.
- ...
Tùy thuộc vào công cụ ước tính cardinality đang sử dụng và một số phương pháp phỏng đoán, bất kỳ trong số đó (hoặc một biến thể) có thể được sử dụng. Xem Sách trắng của Microsoft Tối ưu hóa các gói truy vấn của bạn với Công cụ ước tính số lượng thẻ SQL Server 2014 để biết thêm.
Lỗi?
Bây giờ, như đã lưu ý trong câu hỏi, trong trường hợp này, phép nối đơn cột 'đơn giản' (bật fId
) sử dụng CSelCalcExpressionComparedToExpression
máy tính:
Kế hoạch tính toán:
CSelCalcExpressionComparedToExpression [ar] .fId x_cmpEq [ar] .fId
Biểu đồ được tải cho cột QCOL: [ar] .bId từ số liệu thống kê với id 2
Biểu đồ được tải cho cột QCOL: [ar] .fId từ số liệu thống kê với id 1
Độ chọn lọc: 0
Tính toán này đánh giá rằng việc tham gia 20.608 hàng với 1 hàng được lọc sẽ có độ chọn lọc bằng 0: không có hàng nào khớp (được báo cáo là một hàng trong các kế hoạch cuối cùng). Điều này có sai không? Vâng, có lẽ có một lỗi trong CE mới ở đây. Người ta có thể lập luận rằng 1 hàng sẽ khớp với tất cả các hàng hoặc không có hàng, vì vậy kết quả có thể hợp lý, nhưng có lý do để tin khác.
Các chi tiết thực sự khá khó khăn, nhưng kỳ vọng ước tính sẽ dựa trên fId
biểu đồ chưa được lọc , được sửa đổi bởi tính chọn lọc của bộ lọc, đưa ra 20608 * 20608 * 4.85248e-005 = 20608
các hàng là rất hợp lý.
Theo cách tính này có nghĩa là sử dụng máy tính CSelCalcSimpleJoinWithDistinctCounts
thay vì CSelCalcExpressionComparedToExpression
. Không có cách nào để làm điều này, nhưng nếu bạn tò mò, bạn có thể bật cờ theo dõi không có giấy tờ 9479:
Lưu ý phép nối cuối cùng tạo ra 20.608 hàng từ hai đầu vào một hàng, nhưng điều đó không gây ngạc nhiên. Đó là kế hoạch tương tự được sản xuất bởi CE ban đầu theo TF 9481.
Tôi đã đề cập đến các chi tiết rất khó (và tốn thời gian để điều tra), nhưng theo như tôi có thể nói, nguyên nhân gốc rễ của vấn đề có liên quan đến vị ngữ rId = 508
, với độ chọn lọc bằng không. Ước tính không này được nâng lên thành một hàng theo cách thông thường, dường như đóng góp cho ước tính chọn lọc bằng 0 tại câu hỏi khi nó chiếm các vị từ thấp hơn trong cây đầu vào (do đó tải số liệu thống kê cho bId
).
Cho phép tham gia bên ngoài để giữ ước tính bên trong không có hàng (thay vì tăng lên một hàng) (vì vậy tất cả các hàng bên ngoài đủ điều kiện) sẽ đưa ra ước tính tham gia 'không có lỗi' với máy tính. Nếu bạn thích khám phá điều này, cờ theo dõi không có giấy tờ là 9473 (một mình):
Hành vi của ước tính cardinality tham gia CSelCalcExpressionComparedToExpression
cũng có thể được sửa đổi để không tính đến `` bId` với một cờ biến thể không có giấy tờ khác (9494). Tôi đề cập đến tất cả những điều này bởi vì tôi biết bạn có hứng thú với những điều như vậy; không phải vì họ đưa ra một giải pháp. Cho đến khi bạn báo cáo vấn đề với Microsoft và họ giải quyết vấn đề đó (hoặc không), thể hiện truy vấn khác nhau có lẽ là cách tốt nhất để chuyển tiếp. Bất kể hành vi đó là cố ý hay không, họ nên quan tâm để nghe về hồi quy.
Cuối cùng, để thu dọn một thứ khác được đề cập trong kịch bản sao chép: vị trí cuối cùng của Bộ lọc trong kế hoạch câu hỏi là kết quả của một cuộc thăm dò dựa trên chi phí GbAggAfterJoinSel
di chuyển tổng hợp và bộ lọc lên trên phép nối, vì đầu ra nối có nhỏ như vậy số hàng. Bộ lọc ban đầu bên dưới tham gia, như bạn mong đợi.