2012-02-17 29 views
5

Tôi đang gặp một MySQL-Table như thế này:Làm thế nào để chỉ số hai cột ngày cho các loại hình truy vấn

CREATE TABLE `dates` (
`id` int UNSIGNED NULL AUTO_INCREMENT , 
`object_id` int UNSIGNED NOT NULL , 
`date_from` date NOT NULL , 
`date_to` date NULL , 
`time_from` time NULL , 
`time_to` time NULL , 
PRIMARY KEY (`id`) 
); 

mà được truy vấn chủ yếu theo cách này:

SELECT object_id FROM `dates` 
WHERE NOW() BETWEEN date_from AND date_to 

Làm thế nào để chỉ số bảng tốt nhất? Tôi có nên tạo hai chỉ mục, một cho số date_from và một cho date_to hoặc là chỉ mục kết hợp trên cả hai cột tốt hơn không?

+0

Tôi cảm thấy date_from là tốt hơn để tạo chỉ mục thay vì kết hợp –

+0

Bạn [có thể] cảm thấy sai. Giả sử có 10 hàng cho một số đối tượng. 8 có ngày kết thúc trong quá khứ, 1 là "hiện tại" và 1 là "tương lai". Có bao nhiêu trong số đó được lọc bởi "NOW()> date_from" (câu trả lời: chỉ một) và số lượng được lọc theo "NOW()

Trả lời

4

Đối với truy vấn:

WHERE NOW() >= date_from 
    AND NOW() <= date_to 

Một số hợp chất (date_from, date_to) là vô ích.

Tạo cả hai chỉ mục: (date_from)(date_to) và để trình tối ưu hóa SQL quyết định mỗi lần sử dụng. Tùy thuộc vào giá trị và chọn lọc, trình tối ưu hóa có thể chọn một hoặc một chỉ mục khác. Hoặc không ai trong số họ. Không có cách nào dễ dàng để tạo ra một chỉ mục sẽ xem xét cả hai điều kiện.


(Chỉ số không gian có thể được sử dụng để tối ưu hóa điều kiện như vậy, nếu bạn có thể dịch ngày sang vĩ độ và kinh độ).

Cập nhật

Sai lầm của tôi. Chỉ mục trên (date_from, date_to, object_id) có thể và thực sự được sử dụng trong một số trường hợp cho truy vấn này. Nếu độ chọn lọc của NOW() <= date_from đủ cao, trình tối ưu hóa chọn sử dụng chỉ mục này, hơn là quét toàn bộ trên bảng hoặc sử dụng một chỉ mục khác. Điều này là bởi vì nó là một chỉ số bao gồm, có nghĩa là không có dữ liệu là cần thiết để được lấy từ bảng, chỉ đọc từ dữ liệu chỉ mục được yêu cầu.

Ghi chú nhỏ (không liên quan đến hiệu suất, chỉ tính đúng của truy vấn). tình trạng của bạn là tương đương với:

WHERE CURRENT_DATE() >= date_from 
    AND (CURRENT_DATE() + INTERVAL 1 DAY <= date_to 
     OR (CURRENT_DATE() = NOW() 
     AND CURRENT_DATE() = date_to 
      ) 
    ) 

Bạn có chắc chắn bạn muốn điều đó hay bạn muốn điều này:

WHERE CURRENT_DATE() >= date_from 
    AND CURRENT_DATE() <= date_to 

Chức năng NOW() trả về một DATETIME, trong khi CURRENT_DATE() trả về một DATE, mà không có sự bán thời gian.

+0

Cảm ơn câu trả lời của bạn - về cơ bản tôi có hai loại truy vấn: hoặc tôi chọn 'object_id' để nhận tất cả các ngày liên quan cho đối tượng của tôi hoặc bằng cách chọn phạm vi ngày có ngày được chọn (có thể là' NOW() 'hoặc bất kỳ ngày nào khác) là giữa 'date_from' và' date_to' để tôi nhận được tất cả các hàng xảy ra ngày hôm đó. – acme

0

Tạo một chỉ mục với (date_from, date_to) như chỉ số duy nhất sẽ được sử dụng cho các tiêu chí ĐÂU

Nếu bạn tạo chỉ số riêng biệt sau đó MySQL sẽ phải sử dụng một hay khác thay vì cả hai

1

Có bao nhiêu hàng liên quan đến kích thước bảng của bạn truy vấn của bạn trả về? Nếu đó là hơn 10 phần trăm tôi sẽ không bận tâm để tạo ra một chỉ mục, trong trường hợp như vậy của bạn khá gần với một bảng quét anyway. Nếu nó thấp hơn 10%, thì trong trường hợp này, sẽ sử dụng một chỉ mục là (date_from, date_to, object_id) để kết quả truy vấn có thể được xây dựng hoàn toàn từ thông tin trong chỉ mục, mà không có cơ sở dữ liệu havind để theo dõi trở lại dữ liệu bảng để lấy giá trị cho object_id.

Tùy thuộc vào kích thước bảng của bạn, điều này có thể sử dụng hết rất nhiều không gian. Nếu bạn có thể tha thứ, hãy thử.

+0

Tôi không biết rằng trường được chọn sau đó được lấy từ chỉ mục, tốt để biết! Tôi đoán số lượng hàng là năm chữ số và các kết quả phù hợp dưới 10 phần trăm. Vì vậy, điều này có vẻ giống như con đường để đi. – acme

2

Bạn nên tạo chỉ mục bao gồm date_from, date_to và object_id như được giải thích bởi ypercube. Thứ tự của các trường trong chỉ mục phụ thuộc vào việc bạn sẽ có nhiều dữ liệu hơn cho quá khứ hay tương lai. Như được chỉ ra bởi Erwin để đáp lại bình luận của Sanjay, trường date_to sẽ được chọn lọc hơn nếu bạn có nhiều ngày trong quá khứ và ngược lại.

CREATE INDEX ON (date_to, date_from, object_id); 
+0

Ok, cảm ơn bạn đã chỉ ra điều này! – acme

Các vấn đề liên quan