2013-07-23 12 views
6

Na prostej, ale bardzo dużej tabeli Innodb, mam unikalny indeks na kolumnie A i chcę uzyskać listę (całkowitą) kolumny B w kolejności (liczba całkowita) kolumny ADlaczego MySQL Innodb "Tworzenie indeksu sortowania", gdy istnieje unikalny indeks?

Bardzo proste zapytanie, jestem przeglądanie milionów rekordów.

SELECT B FROM hugeTable ORDER BY A LIMIT 10000 OFFSET 500000

ten trwa 10 sekund na zapytania na bardzo szybkim serwerze?

Filesort: Yes Filesort_on_disk: Yes Merge_passes: 9

To nie ma sensu dla mnie, dlaczego nie można go używać Indeks A?

Objaśnienie pokazuje proste, niemożliwe klawisze i pliki.

Odpowiedz

10

Jeśli wartości dla kolumny B nie są dostępne na stronach indeksu, wówczas MySQL będzie musiał uzyskać dostęp do stron w tabeli podstawowej. Także tam nie ma predykatu, który filtruje, które wiersze są brane pod uwagę, a to oznacza, że ​​MySQL widzi, że WSZYSTKIE wiersze muszą zostać zwrócone. To może wyjaśnić, dlaczego indeks nie jest używany.

Należy również zauważyć, że operacje LIMIT są przetwarzane na końcu instrukcji, jako prawie ostatni krok w planie wykonania, z pewnymi wyjątkami.

8.2.1.3. Optimizing LIMIT Queries http://dev.mysql.com/doc/refman/5.5/en/limit-optimization.html

Podejrzewam, że zapytanie mogłoby skorzystać z indeksu przewodnim, na przykład „ON hugetable (A,B)”, aby uniknąć operacji sortowania.

W przypadku braku indeksu obejmującego można spróbować przepisać zapytanie w taki sposób, aby sprawdzić, czy skorzysta z indeksu w kolumnie A, i uniknąć operacji sortowania w milionach wierszy (aby uzyskać pierwsze 510 000 wierszy zwróconych w kolejności):

SELECT i.B 
    FROM (SELECT j.A 
      FROM hugeTable j 
      ORDER 
      BY j.A 
      LIMIT 10000 OFFSET 500000 
     ) k 
    JOIN hugetable i 
    ON i.A = k.A 
ORDER 
    BY k.A 

proponuję zrobić EXPLAIN tylko na zapytania widoku inline (alias jako K), i zobaczyć, czy to widać „Using index”.

Zewnętrzne zapytanie prawdopodobnie nadal będzie miało operację "Using filesort", ale co najmniej będzie to dotyczyło tylko 10 000 wierszy.

(UWAGA: Możesz spróbować "ORDER BY i.A" zamiast "k.A" na zewnętrznej kwerendy, i sprawdzić, czy to robi różnicę.)


DODATEK

Nie odpowiadając konkretnie na twoje pytanie, ale pod względem wydajności tego zapytania, jeśli jest to "przekierowanie" przez zestaw wierszy, inną opcją do rozważenia, aby przejść do "następnej" strony jest użycie wartości "A" z ostatni wiersz pobrany w poprzednim zapytaniu jako "punkt początkowy" dla t następny wiersz.

Oryginalne zapytanie wygląda na to, że zaczyna "strona 51" (10 000 wierszy na stronę, strona 51 to wiersze od 510,001 do 520 000).

Jeśli miałbyś również zwrócić wartość "A" i zachować ją dla ostatniego rzędu.Aby dostać się „obok” stronę, zapytanie może faktycznie być:

SELECT i.B, k.A 
    FROM (SELECT j.A 
      FROM hugeTable j 
      WHERE j.A > $value_of_A_from_row_520000 
     -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
      LIMIT 10000 
     ) k 
    JOIN hugetable i 
    ON i.A = k.A 
    ORDER 
    BY k.A 

Jeśli również przechowywane wartości dla A z „pierwszego rzędu”, które można użyć do tworzenia kopii zapasowych stronę. To naprawdę działa tylko w przypadku przekazania jednej strony lub cofnięcia o jedną stronę. Przeskakując na inną stronę, musiałbyś użyć oryginalnej formy zapytania, licząc wiersze.

Powiązane problemy