2012-02-17 18 views
5

Mam MySQL tabela tak:Jak indeks dwie kolumny dat dla tego rodzaju zapytania

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`) 
); 

który zapytał głównie w ten sposób:

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

Jak mogę indeks najlepszy stół? Czy powinienem utworzyć dwa indeksy, jeden dla date_from i jeden dla date_to lub jest połączony indeks na obu kolumnach lepiej?

+0

Czuję date_from lepiej jest utworzyć indeks zamiast połączonego –

+0

[prawdopodobnie] czujesz się źle. Powiedzmy, że dla jakiegoś obiektu jest 10 wierszy. 8 ma datę zakończenia w przeszłości, 1 to "current", a 1 "future". Ile z nich zostanie odfiltrowanych przez "NOW()> date_from" (odpowiedź: tylko jedna) i ilu zostanie odfiltrowanych przez "NOW()

Odpowiedz

4

dla zapytania:

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

indeks związek (date_from, date_to) jest bezużyteczny.

Utwórz oba indeksy: (date_from) i (date_to) i pozwól, aby optymalizator SQL decydował za każdym razem, którego użyć. W zależności od wartości i selektywności optymalizator może wybrać jeden lub drugi indeks. Ani żadnego z nich. Nie ma łatwego sposobu na stworzenie indeksu, który uwzględni oba warunki.


(Do zoptymalizowania takiego warunku można użyć indeksu przestrzennego, jeśli można przetłumaczyć daty na szerokość i długość geograficzną).

Aktualizacja

Mój błąd. Indeks na (date_from, date_to, object_id) może i jest rzeczywiście używany w niektórych sytuacjach dla tego zapytania. Jeśli selektywność parametru NOW() <= date_from jest wystarczająco wysoka, optymalizator zdecyduje się użyć tego indeksu, zamiast wykonywać pełne skanowanie na stole lub używając innego indeksu. Dzieje się tak dlatego, że jest to indeks obejmujący, co oznacza, że ​​nie ma potrzeby pobierania danych z tabeli, wymagane jest tylko odczytanie z danych indeksu.

Drobna uwaga (niezwiązana z wydajnością, tylko poprawność zapytania). Twój stan jest równoznaczne z:

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

Czy na pewno chcesz, czy chcesz to:

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

Funkcja NOW() zwraca DATETIME, natomiast CURRENT_DATE() zwraca DATE, bez części czasu.

+0

Dziękuję za odpowiedź - zasadniczo mam dwa rodzaje zapytań: albo wybieram przez "id_obiektu", aby uzyskać wszystkie powiązane daty dla mojego obiektu, albo wybierając zakres dat, w którym wybrany dzień (czy to 'TERAZ()' lub każda inna data) jest pomiędzy 'date_from' i' date_to', więc otrzymuję wszystkie wiersze, które zdarzają się tego dnia. – acme

0

Utwórz indeks z (date_from, date_to) jako tego jednego wskaźnika byłby użyteczny dla kryteriów WHERE

Jeśli utworzyć oddzielne indeksy następnie MySQL będzie musiał użyć jednego lub drugiego zamiast zarówno

1

Ile wierszy w stosunku do rozmiaru tabeli zwraca zapytanie? Jeśli jest to więcej niż 10 procent, nie zawracałbym sobie głowy tworzeniem indeksu, w takim przypadku twój prawie tak blisko do skanowania tabeli. Jeśli jest to znacznie poniżej 10 procent, to w tym przypadku użyłby indeksu zawierającego (date_from, date_to, object_id), więc wynik zapytania może być zbudowany w całości z informacji w indeksie, bez bazy danych havind, aby powrócić do dane tabeli, aby uzyskać wartość dla id_obiektu.

W zależności od wielkości stołu może to zająć dużo miejsca. Jeśli możesz oszczędzić, spróbuj.

+0

Nie wiedziałem, że wybrane pole jest następnie pobierane z indeksu, dobrze wiedzieć! Przypuszczam, że liczba wierszy jest pięciocyfrowa, a dopasowania są mniejsze niż 10 procent. To wydaje się być drogą do zrobienia. – acme

2

Powinieneś utworzyć indeks obejmujący date_from, date_to i id_obiektu, jak wyjaśniono przez ypercube. Kolejność pól w indeksie zależy od tego, czy będziesz mieć więcej danych dotyczących przeszłości czy przyszłości. Jak zauważył Erwin w odpowiedzi na komentarz Sanjay, pole date_to będzie bardziej selektywne, jeśli masz więcej dat w przeszłości i na odwrót.

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

Ok, dzięki za wskazanie tego! – acme

Powiązane problemy