MySQL: вложенная проблема выбора скорости - PullRequest
0 голосов
/ 08 июня 2011

У меня есть следующие таблицы:

|ELEMENTS|
------------
|id_element|
|id_catalog|
|value|


|CATALOG|
------------
|id_catalog|
|catalog_name|
|show|
|status|

Я пытался добавить разные индексы (несколько вариантов):

1) ELEMENT: pair(id_element, id_catalog) and id_element and id_catalog
2) ELEMENT: pair(id_element, id_catalog) and id_element
3) ELEMENT: pair(id_element, id_catalog) and id_catalog
4) ELEMENT: id_element and id_catalog

1) CATALOG: pair(show, status) and id_catalog
2) CATALOG: id_catalog and show and status

Выполнить после выбора:

SELECT DISTINCT `id_element` FROM `ELEMENTS`
       WHERE (id_catalog IN (SELECT `id_catalog` FROM `CATALOG` WHERE status=1 AND show = 1)) limit 10

Если есть несколько строк, то это работает очень быстро.Но если он пуст - это займет больше 4 секунд.

В то же время "SELECT id_catalog FROM CATALOG WHERE status=1 AND show = 1" работает быстро, есть строки и пусто.

В таблице ELEMENTS 100 000 записей. В таблице CATALOG 15 000 записей

Также я попытался "присоединиться", но это заняло больше времени, чем раньше.

Почему работает пустой запростак долго, и что я должен сделать, чтобы увеличить скорость?

Вот объясните ответ:

id | select_type          | table                  | type              | possible_keys             | key        | key_len | ref    | rows   | Extra
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1  | 'PRIMARY',           |'ELEMENTS'              | 'index'           | ''                        | null       | null    | null   | 270044 | 'Using where; Using temporary'
2  | 'DEPENDENT SUBQUERY' | 'CATALOG'              | 'unique_subquery' | 'PRIMARY,pair,id_catalog' | 'PRIMARY'  | '4'     | 'func' | 1      | 'Using where'

Ответы [ 5 ]

2 голосов
/ 08 июня 2011

Почему бы просто не написать объединение, чтобы помочь оптимизатору выполнить свою работу?

SELECT DISTINCT id_element
FROM elements JOIN catalog ON elements.id_catalog=catalog.id_catalog
WHERE status=1 AND show = 1
LIMIT 10

(не проверено)

2 голосов
/ 08 июня 2011

Полагаю, что индексирование CATALOG(status,show) позволит быстро ответить на подвыбор.

А затем некоторый индекс в элементах ELEMENTS (id_catalog) ускорит ответ на главный вопрос.

Может быть, это зависит от статистики по этим столбцам: если они недостаточно избирательны, вы все равно получите много строк.

Не могли бы вы показать вывод EXPLAIN при использовании двух индексов выше?

1 голос
/ 08 июня 2011

Я бы поставил эти индексы там:

CREATE INDEX idx_element_1 ON ELEMENT (id_catalog);
CREATE INDEX idx_catalog_1 ON CATALOG (status, show);

Также они, хотя они могут и не понадобиться для вашего запроса (вероятно, это должны быть первичные ключи, если у вас нет дубликатов):

CREATE INDEX idx_element_2 ON ELEMENT (id_element);
CREATE INDEX idx_catalog_2 ON CATALOG (id_catalog);

Не могли бы вы удалить другие индексы, создать их и проверить результаты запроса?

1 голос
/ 08 июня 2011

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

SELECT DISTINCT(e.id_element)
FROM ELEMENTS e
WHERE EXISTS (
    SELECT *
    FROM CATALOG c
    WHERE c.id_catalog = e.id_catalog
    AND c.status = 1
    AND c.show = 1)
LIMIT 10;

Это уменьшит количество времени, которое MySQL тратит на поиск каталога для каждого элемента, налагая LIMIT 1 на внутренний запрос, но вы всегда рискуете долго искать, когда, возможно, совпадений нет.

0 голосов
/ 10 июня 2011

Спасибо всем.Я решил это путем денормализации таблицы.Потому что в этой таблице слишком много данных, которые разделены.Я решил объединить это в один стол.И теперь это работает отлично.Теперь запрос всегда занимает 0,03 секунды.

...