2012-11-26 4 views
5

Jeśli utworzyć dwa następujące indeksyKolejność, w jakiej tworzone są wskaźniki, wpływa na indeks wybrany przez optymalizator zapytań?

ALTER TABLE requests ADD INDEX daily_ips(exec_date, ip_address); 
ALTER TABLE requests ADD INDEX is_cached(exec_date, cached); 

Wyjście show index from requests jest następujący

Table  Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment 
requests 1   daily_ips 1    exec_date A   413   NULL NULL YES BTREE  
requests 1   daily_ips 2    ip_address A   218334  NULL NULL YES BTREE  
requests 1   is_cached 1    exec_date A   165   NULL NULL YES BTREE  
requests 1   is_cached 2    cached  A   165   NULL NULL YES BTREE  

Mam następujące zapytanie

EXPLAIN SELECT exec_date, 
    100 * SUM(CASE WHEN cached = 'no' THEN 1 ELSE 0 END)/SUM(1) cached_no, 
    100 * SUM(CASE WHEN cached != 'no' THEN 1 ELSE 0 END)/SUM(1) cached_yes 
FROM requests 
GROUP BY exec_date; 

id select_type table type possible_keys key   key_len ref rows Extra 
1 SIMPLE requests index NULL   daily_ips 263 NULL 436695 

Jednak chciałbym zmusić zapytanie optymalizator do korzystania z indeksu is_cached zamiast indeksu daily_ips.

Jeśli usunąć indeks daily_ips i dodać go ponownie

ALTER TABLE requests DROP INDEX daily_ips; 
ALTER TABLE requests ADD INDEX daily_ips(exec_date, ip_address); 

Następnie uruchom samą EXPLAIN oświadczenie, optymalizator kwerendy wybiera indeks is_cached.

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE requests index NULL is_cached 6 NULL 440493 Using index 

Czy oczekuje się, że optymalizator zapytań wybierze indeks na podstawie kolejności, w jakiej został dodany?

Jak określić optymalizator zapytań, którego indeksu użyć?

+0

Uważam, że indeks jest używany tylko do skanowania tabeli. Jeśli chcesz faktycznie korzystać z indeksu, przeinstaluj go na dwa zapytania, które liczą się z warunkiem, który jest w pamięci podręcznej. (Choć bufor musi być pierwszym kluczem w indeksie oczywiście.) Zasadniczo CASE powoduje wykonanie skanowania tabeli. – Corbin

+1

Zaktualizowałem moją odpowiedź, sprawdzając, czy –

+0

@Corbin Nie jestem pewien, czy rozumiem, w jaki sposób chciałbym wykonać polecenie, które polecasz. Jak dokładnie mogę zrestrukturyzować zapytanie na 2 zapytania (jakikolwiek przykładowy kod byłby mile widziany)? – user784637

Odpowiedz

2

Możesz określić, który indeks sholud będzie używany przez zapytanie do uruchomienia.

Spróbuj tego:

EXPLAIN SELECT exec_date, 
    100 * SUM(CASE WHEN cached = 'no' THEN 1 ELSE 0 END)/SUM(1) cached_no, 
    100 * SUM(CASE WHEN cached != 'no' THEN 1 ELSE 0 END)/SUM(1) cached_yes 
FROM requests USE INDEX(is_cached) 
GROUP BY exec_date; 

differnce między USE INDEX i FORCE INDEX:

Określając USE INDEX (index_list), można powiedzieć, MySQL używać tylko jednego z wymienionych indeksów, aby znaleźć wiersze w tabeli . Alternatywna składnia IGNORE INDEX (index_list) może być użyta do tego, aby MySQL nie używał jakiegoś konkretnego indeksu lub indeksów. Wskazówki te są przydatne, jeśli EXPLAIN pokazuje, że MySQL używa niewłaściwego indeksu z listy możliwych indeksów.

Można również użyć FORCE INDEX, który działa jak USE INDEX (index_list), ale z dodatkiem, że skanowanie tabeli jest bardzo kosztowne. Innymi słowy, skanowanie tabeli jest używane tylko wtedy, gdy nie ma możliwości użycia jednego z podanych indeksów do znalezienia wierszy w tabeli.

UPDATE

Spróbuj tego zapytania:

SELECT exec_date, 
     100 * SUM(IF(cached = 0, 1, 0))/SUM(1) cached_no, 
     100 * SUM(IF(cached = 1, 1, 0))/SUM(1) cached_yes 
FROM (SELECT exec_date, IF(cached = 'no', 0, 1) cached 
     FROM requests GROUP BY exec_date) AS A 
+1

Dzięki! Jakąkolwiek różnicę między "USE INDEX" i "FORCE INDEX"? – user784637

+1

Sprawdź moją zaktualizowaną odpowiedź –

+0

Jeśli odpowiedź jest satysfakcjonująca, zaakceptuj odpowiedź i awansuj ją. –

2

aby wymusić jeden indeks na anothe można użyć FORCE INDEX dyrektywy:

EXPLAIN SELECT exec_date, 
    100 * SUM(CASE WHEN cached = 'no' THEN 1 ELSE 0 END)/SUM(1) cached_no, 
    100 * SUM(CASE WHEN cached != 'no' THEN 1 ELSE 0 END)/SUM(1) cached_yes FROM requests FORCE INDEX(`is_cached`) GROUP BY exec_date; 

MySQL optymalizator wybiera indeks która zwraca mniej wierszy do skan, w twoim przypadku liczba ta jest bardzo zbliżona dla obu indeksów (436695 vs 440493).

Powiązane problemy