Cách hiệu quả nhất để truy xuất phạm vi ngày


16

Cách hiệu quả nhất để lấy phạm vi ngày với cấu trúc bảng như thế này là gì?

create table SomeDateTable
(
    id int identity(1, 1) not null,
    StartDate datetime not null,
    EndDate datetime not null
)
go

Nói rằng bạn muốn một phạm vi cho cả hai StartDateEndDate. Vì vậy, nói cách khác, nếu StartDaterơi vào giữa @StartDateBegin@StartDateEnd, và EndDaterơi vào giữa @EndDateBegin@EndDateEnd, thì hãy làm gì đó.

Tôi biết có một vài cách có thể đi về vấn đề này, nhưng lời khuyên nào nhất?

Câu trả lời:


29

Đây là một vấn đề khó giải quyết nói chung, nhưng có một vài điều chúng ta có thể làm để giúp trình tối ưu hóa chọn một kế hoạch. Kịch bản lệnh này tạo một bảng có 10.000 hàng với phân phối các hàng giả ngẫu nhiên đã biết để minh họa:

CREATE TABLE dbo.SomeDateTable
(
    Id          INTEGER IDENTITY(1, 1) PRIMARY KEY NOT NULL,
    StartDate   DATETIME NOT NULL,
    EndDate     DATETIME NOT NULL
);
GO
SET STATISTICS XML OFF
SET NOCOUNT ON;
DECLARE
    @i  INTEGER = 1,
    @s  FLOAT = RAND(20120104),
    @e  FLOAT = RAND();

WHILE @i <= 10000
BEGIN
    INSERT dbo.SomeDateTable
        (
        StartDate, 
        EndDate
        )
    VALUES
        (
        DATEADD(DAY, @s * 365, {d '2009-01-01'}),
        DATEADD(DAY, @s * 365 + @e * 14, {d '2009-01-01'})
        )

    SELECT
        @s = RAND(),
        @e = RAND(),
        @i += 1
END

Câu hỏi đầu tiên là làm thế nào để lập chỉ mục bảng này. Một tùy chọn là cung cấp hai chỉ mục trên các DATETIMEcột, vì vậy trình tối ưu hóa ít nhất có thể chọn tìm kiếm trên StartDatehoặc EndDate.

CREATE INDEX nc1 ON dbo.SomeDateTable (StartDate, EndDate)
CREATE INDEX nc2 ON dbo.SomeDateTable (EndDate, StartDate)

Đương nhiên, sự bất bình đẳng trên cả hai StartDateEndDatecó nghĩa là chỉ một cột trong mỗi chỉ mục có thể hỗ trợ tìm kiếm trong truy vấn mẫu, nhưng đây là cách tốt nhất chúng ta có thể làm. Chúng tôi có thể xem xét làm cho cột thứ hai trong mỗi chỉ mục INCLUDEthay vì một khóa, nhưng chúng tôi có thể có các truy vấn khác có thể thực hiện tìm kiếm bằng nhau trên cột hàng đầu và tìm kiếm bất bình đẳng trên cột thứ hai. Ngoài ra, chúng tôi có thể nhận được số liệu thống kê tốt hơn theo cách này. Dù sao...

DECLARE
    @StartDateBegin DATETIME = {d '2009-08-01'},
    @StartDateEnd DATETIME = {d '2009-10-15'},
    @EndDateBegin DATETIME = {d '2009-08-05'},
    @EndDateEnd DATETIME = {d '2009-10-22'}

SELECT
    COUNT_BIG(*)
FROM dbo.SomeDateTable AS sdt
WHERE
    sdt.StartDate BETWEEN @StartDateBegin AND @StartDateEnd
    AND sdt.EndDate BETWEEN @EndDateBegin AND @EndDateEnd

Truy vấn này sử dụng các biến, vì vậy, nói chung, trình tối ưu hóa sẽ đoán tính chọn lọc và phân phối, dẫn đến ước tính số lượng thẻ được đoán là 81 hàng . Trong thực tế, truy vấn tạo ra 2076 hàng, sự khác biệt có thể quan trọng trong một ví dụ phức tạp hơn.

Trên SQL Server 2008 SP1 CU5 trở lên (hoặc R2 RTM CU1), chúng tôi có thể tận dụng Tối ưu hóa nhúng tham số để có được ước tính tốt hơn, chỉ bằng cách thêm OPTION (RECOMPILE)vào SELECTtruy vấn ở trên. Điều này gây ra một quá trình biên dịch ngay trước khi lô thực thi, cho phép SQL Server 'nhìn thấy' các giá trị tham số thực và tối ưu hóa cho các giá trị đó. Với thay đổi này, ước tính cải thiện thành 468 hàng (mặc dù bạn cần kiểm tra kế hoạch thời gian chạy để thấy điều này). Ước tính này tốt hơn 81 hàng, nhưng vẫn chưa hoàn thành. Các tiện ích mở rộng mô hình được bật bởi cờ theo dõi 2301 có thể giúp ích trong một số trường hợp, nhưng không phải với truy vấn này.

Vấn đề là nơi các hàng đủ điều kiện của hai phạm vi tìm kiếm trùng nhau. Một trong những giả định đơn giản hóa được thực hiện trong thành phần ước tính chi phí và giá trị của trình tối ưu hóa là các biến vị ngữ là độc lập (vì vậy nếu cả hai đều có độ chọn lọc là 50%, kết quả của việc áp dụng cả hai được coi là đủ điều kiện 50% 50% = 25% số hàng ). Trong trường hợp loại tương quan này là một vấn đề, chúng ta thường có thể làm việc xung quanh nó với các số liệu thống kê nhiều cột và / hoặc được lọc. Với hai phạm vi với điểm bắt đầu và điểm kết thúc chưa biết, điều này trở nên không thực tế. Đây là nơi đôi khi chúng ta phải dùng đến cách viết lại truy vấn thành một biểu mẫu xảy ra để đưa ra ước tính tốt hơn:

SELECT COUNT(*) FROM
(
    SELECT
        sdt.Id
    FROM dbo.SomeDateTable AS sdt
    WHERE 
        sdt.StartDate BETWEEN @StartDateBegin AND @StartDateEnd
    INTERSECT
    SELECT
        sdt.Id
    FROM dbo.SomeDateTable AS sdt 
    WHERE
        sdt.EndDate BETWEEN @EndDateBegin AND @EndDateEnd
) AS intersected (id)
OPTION (RECOMPILE)

Hình thức này xảy ra để tạo ra ước tính thời gian chạy là 2110 hàng (so với năm 2076 thực tế). Trừ khi bạn có TF 2301, trong trường hợp đó, các kỹ thuật mô hình nâng cao hơn sẽ nhìn xuyên qua thủ thuật và đưa ra ước tính chính xác như trước: 468 hàng.

Một ngày SQL Server có thể nhận được hỗ trợ riêng cho các khoảng thời gian. Nếu điều đó đi kèm với sự hỗ trợ thống kê tốt, các nhà phát triển có thể sợ các kế hoạch truy vấn điều chỉnh như thế này ít hơn một chút.


5

Tôi không biết một giải pháp nhanh cho tất cả các phân phối dữ liệu, nhưng nếu tất cả các phạm vi của bạn ngắn, chúng tôi thường có thể tăng tốc nó. Ví dụ: nếu các phạm vi ngắn hơn một ngày, thay vì truy vấn này:

SELECT  TaskId ,    
        TaskDescription ,
        StartedAt ,    
        FinishedAt    
FROM    dbo.Tasks    
WHERE   '20101203' BETWEEN StartedAt AND FinishedAt

chúng ta có thể thêm một điều kiện nữa:

SELECT  TaskId ,    
        TaskDescription ,
        StartedAt ,    
        FinishedAt    
FROM    dbo.Tasks    
WHERE   '20101203' BETWEEN StartedAt AND FinishedAt
    AND StartedAt >= '20101202'
    AND FinishedAt <= '20101204' ;

Do đó, thay vì quét toàn bộ bảng, truy vấn sẽ chỉ quét phạm vi hai ngày, nhanh hơn. Nếu phạm vi có thể dài hơn, chúng ta có thể lưu trữ chúng dưới dạng chuỗi của những cái ngắn hơn. Chi tiết tại đây: Điều chỉnh các truy vấn SQL với sự trợ giúp của các ràng buộc

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.