Cập nhật:
Xem bài viết này trong blog của tôi để biết chiến lược lập chỉ mục hiệu quả cho truy vấn của bạn bằng cách sử dụng các cột được tính toán:
Ý tưởng chính là chúng tôi chỉ tính toán length
được làm tròn và startDate
cho bạn các phạm vi và sau đó tìm kiếm chúng bằng cách sử dụng các điều kiện bình đẳng (tốt cho B-Tree
chỉ mục)
Trong MySQL
và trong SQL Server 2008
bạn có thể sử dụng SPATIAL
chỉ mục (R-Tree
).
Chúng đặc biệt tốt cho các điều kiện như "chọn tất cả các bản ghi có một điểm nhất định bên trong phạm vi của bản ghi", đây chỉ là trường hợp của bạn.
Bạn lưu trữ start_date
và end_date
là phần đầu và phần cuối của LineString
(chuyển đổi chúng thành UNIX
dấu thời gian của một giá trị số khác), lập chỉ mục chúng bằng SPATIAL
lập chỉ mục và tìm kiếm tất cả LineString
như vậy s có hộp giới hạn tối thiểu (MBR
) chứa giá trị ngày được đề cập, sử dụng MBRContains
.
Xem mục này trong blog của tôi về cách thực hiện việc này trong MySQL
:
và tổng quan ngắn gọn về hiệu suất cho SQL Server
:
Có thể áp dụng giải pháp tương tự để tìm kiếm một IP
nhất định chống lại các phạm vi mạng được lưu trữ trong cơ sở dữ liệu.
Tác vụ này, cùng với truy vấn của bạn, là một ví dụ thường được sử dụng khác về điều kiện như vậy.
Đồng bằng B-Tree
chỉ mục sẽ không tốt nếu các phạm vi có thể trùng lặp.
Nếu họ không thể (và bạn biết điều đó), bạn có thể sử dụng giải pháp tuyệt vời do @AlexKuznetsov
đề xuất
Cũng lưu ý rằng hiệu suất truy vấn này hoàn toàn phụ thuộc vào phân phối dữ liệu của bạn.
Nếu bạn có nhiều bản ghi trong B
và một số bản ghi trong A
, bạn chỉ có thể tạo chỉ mục trên B.dates
và để TS/CIS
trên A
đi.
Truy vấn này sẽ luôn đọc tất cả các hàng từ A
và sẽ sử dụng Index Seek
trên B.dates
trong một vòng lặp lồng nhau.
Nếu dữ liệu của bạn được phân phối theo cách khác, i. e. bạn có rất nhiều hàng trong A
nhưng ít trong B
và các phạm vi nói chung là ngắn, sau đó bạn có thể thiết kế lại các bảng của mình một chút:
A
start_date interval_length
, tạo chỉ mục tổng hợp trên A (interval_length, start_date)
và sử dụng truy vấn này:
SELECT *
FROM (
SELECT DISTINCT interval_length
FROM a
) ai
CROSS JOIN
b
JOIN a
ON a.interval_length = ai.interval_length
AND a.start_date BETWEEN b.date - ai.interval_length AND b.date