Cột CTE gây ra tràn - Chỉ đặt hàng!


7
;WITH
cte_Date ( DateCode_FK ) AS (
    SELECT  DATEADD( DAY, 
                1 - ROW_NUMBER() OVER ( 
                        ORDER BY so1.object_id ),
                GETDATE() )
    FROM    sys.objects so1
    CROSS APPLY sys.objects so2 )
SELECT  TOP 10 d.DateCode_FK
FROM    cte_Date d
ORDER BY d.DateCode_FK DESC;

Không có gì là một truy vấn quá thú vị, nhưng tôi nhận được một thông báo lỗi nếu tôi chạy nó với ORDER BYmệnh đề:

Msg 517, Cấp 16, Bang 1, Dòng 4

Việc thêm một giá trị vào cột 'datetime' đã gây ra tràn.

Tuy nhiên, không có ORDER BYđiều khoản, nó chỉ chạy tốt. Ngoài ra, nếu tôi chạy truy vấn trên các danh mục khác có trong cùng thể hiện trên cùng một máy chủ, thì truy vấn sẽ chạy tốt hoặc không có ORDER BYmệnh đề.

Tôi đã xem xét các tùy chọn cấu hình và mức độ tương thích giữa danh mục bị ảnh hưởng và danh mục mà truy vấn chạy như mong đợi, nhưng không tìm thấy bất cứ điều gì có thể đảm bảo sự khác biệt. Có ai khác gặp phải một vấn đề tương tự? Tôi có thể làm việc xung quanh nó bây giờ, nhưng lý tưởng nhất là cần có thể khắc phục vấn đề, bất kể đó là gì.

Gợi ý tiềm năng - nếu bạn có số lượng đối tượng tương đối lớn trong danh mục (> 5000), bạn có thể tái tạo lỗi ... Điều này xảy ra trên danh mục lớn nhất của tôi và có vẻ như nếu tôi đưa TOP vào CTE, vấn đề ORDER BY biến mất.

Câu trả lời:


9

SQL Server không đảm bảo thời gian hoặc số lượng đánh giá cho các biểu thức vô hướng. Điều này có nghĩa là một truy vấn có thể gây ra lỗi tùy thuộc vào thứ tự các thao tác trong kế hoạch thực hiện có thể (hoặc có thể không) làm như vậy trong thời gian chạy.

Kịch bản sử dụng CROSS APPLYnơi CROSS JOINcó thể được dự định, nhưng điểm quan trọng là số lượng hàng tiềm năng ROW_NUMBERđược tính toán phụ thuộc vào kích thước của sys.objectssản phẩm chéo.

Đối với một cơ sở dữ liệu có đủ các đối tượng, tràn DATEADDkết quả là một rủi ro dự kiến. Ví dụ: cái này có thể tái tạo bằng cơ sở dữ liệu mẫu AdventureWorks , có 637 mục nhập sys.objects. Kích thước của sản phẩm chéo là 637 * 637 = 405,769; sau đây ném một lỗi tràn:

SELECT DATEADD(DAY, 1 - 405769, GETDATE());

Người ta có thể lập luận rằng không cần phải cụ thể hóa kết quả của một biểu thức cho các hàng không được trả về (và do đó không đưa ra lỗi), nhưng đó không phải là cách mọi thứ hoạt động ngày nay.

Xem xét:

  • Cao nhất ROW_NUMBER sẽ cho giá trị thấp nhấtDateCode_FK trong DATEADD(DAY, 1 - ROW_NUMBER()...biểu thức
  • Bài thuyết trình ORDER BYDateCode_FK DESC
  • Chỉ cần 10 hàng đầu tiên theo thứ tự trình bày là bắt buộc

Nếu trình tối ưu hóa chứa logic để lý giải rằng số hàng thấp hơn dẫn đến giá trị cao hơn DateCode_FK , Sắp xếp rõ ràng sẽ không cần thiết. Chỉ mười hàng sẽ cần phải chảy qua kế hoạch thực hiện. Mười số hàng thấp nhất được đảm bảo để tạo ra mười DateCode_FKgiá trị cao nhất .

Bất kể, ngay cả khi có Sắp xếp, đối số là SQL Server không được đưa ra lỗi vì không có hàng nào trong số mười hàng thực sự được trả về có liên quan đến lỗi tràn. Như tôi đã nói ở trên, "đó không phải là cách mọi thứ hoạt động ngày nay" .


Một công thức thay thế để tránh lỗi (mặc dù nó vẫn không được đảm bảo để làm như vậy - xem chú thích mở đầu của tôi), làm cho việc đánh số hàng xác định và sử dụng CROSS JOIN:

WITH cte_Date (DateCode_FK) AS
(
    SELECT TOP (10)
        DATEADD
        (
            DAY, 
            1 - ROW_NUMBER() OVER ( 
                ORDER BY 
                    so1.[object_id],
                    so2.[object_id]),
            GETDATE()
        )
    FROM sys.objects AS so1
    CROSS JOIN sys.objects AS so2
    ORDER BY
        ROW_NUMBER() OVER (
            ORDER BY 
                so1.[object_id],
                so2.[object_id]) ASC
)
SELECT TOP (10) -- Redundant TOP
    d.DateCode_FK
FROM cte_Date AS d
ORDER BY 
    d.DateCode_FK DESC;

Dán kế hoạch

Kế hoạch

Các kết quả


1

Tôi đoán kỳ nghỉ nôn nao.

Phần ORDER BYbên ngoài của truy vấn đôi khi buộc việc xây dựng danh sách đầy đủ để sắp xếp chính xác nó. Với 5k + hàng được trả về sys.objects, DATETIMEloại dữ liệu tràn ra trong khi cố gắng xây dựng ngày trên 25MM ngày.

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.