/ / Jak zindeksować dwie kolumny daty dla tego rodzaju zapytania - mysql, projekt bazy danych, data, indeksowanie

Jak zindeksować dwie kolumny daty dla tego rodzaju zapytania - mysql, projekt bazy danych, data, indeksowanie

Mam tabelę MySQL jak poniżej:

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óra jest najczęściej zadawana w ten sposób:

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

Jak najlepiej indeksować tabelę? Czy powinienem utworzyć dwa indeksy, jeden dla date_from i jeden dla date_to lub czy połączony indeks w obu kolumnach jest lepszy?

Odpowiedzi:

4 dla odpowiedzi № 1

Dla zapytania:

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

Indeks złożony (date_from, date_to) jest bezużyteczny.

Utwórz oba indeksy: (date_from) i (date_to) i niech za każdym razem decyduje optymalizator SQLjeden do użycia. 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.


(W celu 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ść NOW() <= date_from jest wystarczająco wysoki, optymalizator zdecyduje się na toindeksu, niż wykonanie pełnego skanu na stole lub użycie innego indeksu. Dzieje się tak, ponieważ jest to indeks obejmujący, co oznacza, że ​​nie trzeba pobierać żadnych danych z tabeli, wymagane jest tylko odczytanie z danych indeksu.

Niewielka uwaga (niezwiązana z wydajnością, tylko poprawność zapytania). Twój stan jest równoważny 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 tego chcesz, czy chcesz tego:

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

The NOW() funkcja zwraca a DATETIME, podczas CURRENT_DATE() zwraca a DATE, bez części czasu.


2 dla odpowiedzi nr 2

Powinieneś utworzyć indeks obejmujący date_from,date_to i object_id 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);

1 dla odpowiedzi nr 3

Ile wierszy odpowiada rozmiarowi twojego stołuzapytanie o zwrot? Jeśli jest to więcej niż 10 procent, nie zawracałbym sobie głowy tworzeniem indeksu, w takim przypadku twój byłby prawie tak blisko 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 śledzić z powrotem do danych 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 dla odpowiedzi nr 4

Utwórz indeks z opcją (date_from, date_to), ponieważ ten pojedynczy indeks może być użyty dla kryteriów WHERE

Jeśli utworzysz oddzielne indeksy, MySQL będzie musiał użyć jednego lub drugiego zamiast obu