Index na wielu polach, a kolejność tych pól

Dzisiaj walczyłem z dość prostym, aczkolwiek powolnym zapytaniem SQL. Problem pewnie polegał na tym, że dane były pobierane z tabeli o ~50k rekordach, sortowane, grupowane itd.

Owe zapytanie wyglądało mniej więcej tak:

SELECT
*,
CONCAT(firstname ,' ', lastname) as fullname
FROM
users
GROUP BY fullname
ORDER BY lastname ASC
LIMIT 0, 10;

Co ciekawe to zapytanie było strasznie powolne – czas wykonania 1,7s.  Dodatkowo zapytanie EXPLAIN dobiło faktem, że zapytanie typu SIMPLE musi wykorzystywać tabele tymczasową.

Aby całość przyspieszyć założono indeks na pola firstname i lastname

ALTER TABLE users ADD INDEX `firstname-lastname` (`firstname`, `lastname`)

Oraz odpowiednio zmodyfikowaliśmy zapytanie:

SELECT
*,
CONCAT(firstname ,' ', lastname) as fullname
FROM
users
GROUP BY firstname, lastname
ORDER BY firstname, lastname ASC
LIMIT 0, 10;

Całość działała poprawnie i, co najważniejsze, szybko. Okazało się, że zapytanie ma jedną wadę. Sortowanie ma być najpierw po polu lastname, a potem po polu firstname. Okazuje się, że prosta zamiana kolejnością pól w wyrażeniu ORDER BY skutkuje spowolnieniem czasu wykonywania.

Fakt, czy będziemy grupować najpierw po polu firstname, a później po polu lastname nie miał znaczenia, dlatego postanowiono na zamianę kolejności tych pól, oraz poprawienie indeksu.

ALTER TABLE users DROP INDEX `firstname-lastname`, ADD INDEX `lastname-firstname` (`lastname`, `firstname`)

Dodatkowo drobna zmiana zapytania na:

SELECT
*,
CONCAT(firstname ,' ', lastname) as fullname
FROM
users
GROUP BY lastname, firstname
ORDER BY lastname, firstname ASC
LIMIT 0, 10;

I całość śmiga, aż miło :)

Okazuje się, że dla serwera MySQL kolejność pól w zakładanym indeksie ma wpływ na późniejszy czas wykonywania zapytań.

Ten wpis umieszczono w kategorii MySQL i otagowano jako , . Możesz dodać go do zakładek permalink. Dodaj komentarz lub dodaj odpowiedź (trackback): Trackback URL.

2 Komentarze

  1. ZyZ
    Opublikowano 4 February, 2009 at 01:16 | Permalink

    Hi

    >>Całość działała poprawnie i, co najważniejsze, szybko. Okazało się, że zapytanie ma jedną wadę.
    >>Sortowanie ma być najpierw po polu lastname, a potem po polu firstname. Okazuje się, że prosta
    >>zamiana kolejnością pól w wyrażeniu ORDER BY skutkuje spowolnieniem czasu wykonywania.

    Zachowanie mysql bylo jak najbardziej przewidywalne. Czego mi brakuje w tym poscie to wyjasnienia dlaczego cos dziala lub nie dziala.

    Jesli masz index (col1, col2) i robisz GROUP BY col1,col2 to automatycznie mysql robi
    GROUP BY col1,col2 ORDER BY col1 ASC, col2 ASC wiec twoje zapytanie z

    GROUP BY firstname, lastname
    ORDER BY firstname, lastname ASC

    nie powoduje wykonania zadnego nowego sortowania. Po prostu dopisales cos co juz zostalo dopisane nie wprost. Jesli nie chcesz, by grupowanie robilo automatycznie ORDER BY wyraznie to sygnalizujesz przez ORDER BY NULL.

    >>Okazuje się, że dla serwera MySQL kolejność pól w zakładanym indeksie ma wpływ na późniejszy
    >>czas wykonywania zapytań.

    sluszna uwaga :-D Mysle, ze czesciej powinienes zagladac do
    http://dev.mysql.com/doc/refman/5.1/en/index.html
    http://www.mysqlperformanceblog.com/

    polecam rowniez wiedze w pigulce czyli 2-3 rozdzialy (tj. Benchmarking, Indexes, Query Optimization) z “High Performance MySQL” By Jeremy Zawodny, Derek J. Balling

    Pozdrawiam,
    Marcin

  2. radmen
    Opublikowano 5 February, 2009 at 09:44 | Permalink

    Ano racja. mysqlperformanceblog właśnie dodałem do subskrypcji, a co do manuala to odwieczna prawda, choć nie zawsze jest na to czas :)

Skomentuj

Twój adres email nie zostanie opublikowany i nie będzie rozpowszechniany. Wymagane pola są oznaczone *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>