Скорость SQL-запросов с двумя внутренними объединениями и concat - PullRequest
0 голосов
/ 15 марта 2011

У меня есть три таблицы:

  • книга;
  • авторы;
  • list_items (содержит списки бестселлеров из New York Times)

Я использую этот запрос, чтобы получить автора, чьи книги оставались в списках бестселлеров в течение максимального количества недель:

SELECT authors.full_name, COUNT(*) FROM authors
 INNER JOIN books ON books.author LIKE CONCAT('%', authors.full_name, '%')
 INNER JOIN list_items ON list_items.book_title = books.title
 GROUP BY authors.full_name ORDER BY count(*) DESC LIMIT 1

Этот запрос занимает около 6 минут, в то время как аналогичный запрос без второго JOIN занимает гораздо меньше секунды. Как оптимизировать мой запрос?
UPDATE EXPLAIN это:

table      type   possible_keys key      key_len ref         rows   Extra
authors    ALL    <NULL>        <NULL>   <NULL>  <NULL>      2555   Using temporary; Using filesort
list_items ALL    book_name     <NULL>   <NULL>  <NULL>   31040  Using join buffer
books      eq_ref PRIMARY      PRIMARY  767     list_items. 1      Using where
                                                book_title

Ответы [ 2 ]

1 голос
/ 18 марта 2011

Я не думаю, что вам нужно использовать дополнительный оператор выбора. Я взял ваше быстрое утверждение и удалил внутреннее предложение выбора. Не уверен, насколько это повлияет на время выполнения, но это немного чище, imho.

SELECT COUNT(*), authors.full_name
FROM list_items
INNER JOIN books ON books.title = list_items.title
INNER JOIN relations ON books.id = relations.book_id
INNER JOIN authors ON authors_id = relations.author_id
GROUP BY authors.full_name
ORDER BY COUNT(*);
0 голосов
/ 18 марта 2011

В конце концов я решил эту проблему путем реструктуризации схемы базы данных.

Корневая проблема была в поле books.author, которое могло содержать несколько имен авторов, следовательно, CONCAT в начальном запросе.Я добавил новую таблицу, чтобы применить многие ко многим отношениям , где authors.id и books.id были связаны.

Тогда я использовал этот запрос вместо:

SELECT COUNT (*), items.full_name
    FROM list_items
         INNER JOIN
         (SELECT books.title, authors.full_name
            FROM books INNER JOIN relations ON books.ID = relations.book_id
                 INNER JOIN authors ON authors.ID = relations.author_id
                 ) items ON items.title = list_items.book_title
GROUP BY items.full_name
ORDER BY COUNT (*) DESC;

Время выполнения сократилось до 0,4 секунд.

...