2015-10-12 4 views
1

У меня есть запрос, который что-то вдоль линий:MySQL Slow ВЫБРАТЬ Query

SELECT * FROM table1 
WHERE confirmed = 0 
AND resource = 123 
AND id IN (
    SELECT id FROM table2 WHERE resource = 123 
    AND added > 1440000000 
) 

Это занимает около 3 минут, чтобы бежать, но я понятия не имею, почему. Вот почему я запутался ...

SELECT id FROM table2 WHERE resource = 123 
AND added > 1440000000 

По этому подзапросу результатов по данному продукту нет. Ни одного. Итак, я думал, что если бы я это сделал:

SELECT * FROM table1 
WHERE confirmed = 0 
AND resource = 123 
AND id IN (
0 
) 

Это должно занимать примерно то же самое время, чтобы работать. Кроме того, он не возвращает 0 результатов, как ожидалось. Что происходит? Чем отличается сравнение пустого результата запроса с 0?

Номера строк также очень низкие. Я запустил объяснение, и он использует подтвержденный ключ для таблицы 1 и первичный ключ из таблицы 2. Количество строк равно 5500/20000 соответственно.

Любые идеи были бы очень благодарны! Спасибо!

+1

Потому что для каждой строки 'SELECT', выполненные в вашем заявлении. Не подходит ли здесь 'JOIN'? Поправьте меня, если я пропустил что-л. –

+0

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

+0

Вы уверены, что ресурс и добавленные поля индексируются в вашей базе данных? – itoctopus

ответ

1

Ваш запрос будет работать быстрее с использованием явного join. Если подзапрос не возвращает повторяющиеся значения:

SELECT t1.* 
FROM table1 t1 JOIN 
    (SELECT id FROM table2 WHERE resource = 123 AND added > 1440000000 
    ) t2 
    ON t1.id = t2.id 
WHERE confirmed = 0 AND resource = 123; 

Кроме того, MySQL часто лучше оптимизировать NOT EXISTS:

SELECT t1.* 
FROM table1 t1 
WHERE confirmed = 0 AND resource = 123 AND 
     NOT EXISTS (SELECT 1 
        FROM table2 t2 
        WHERE t2.id = t1.id AND t2.resource = 123 AND t2.added > 1440000000 
       ); 

Этот запрос будет работать быстрее с индексом на table2(id, resource, added).

+0

Спасибо, Гордон, это очень полезно. Я предполагаю, что, хотя подзапрос не возвращает никаких результатов, он все равно занимает достаточно много времени для запуска. Я поменяю свой запрос и надеюсь, что он выполнит эту работу. – Ben

1

IN (SELECT ...) Оптимизирует очень плохо до 5.6. 5.6 лучше, но все равно не очень.

JOIN (SELECT ...) необходимо сначала вычислить и потребовать временную таблицу. Так что это не так хорошо, как простой JOIN, как показано ниже.

SELECT * 
    FROM table1 AS t1 
    JOIN table2 AS t2 ON t2.id = t1.id 
    WHERE t1.confirmed = 0 
     AND t1.resource = 123 
     AND t2.resource = 123 
     AND t2.added > 1440000000 

И есть

table2: INDEX(resource, added) 
table1: INDEX(resource, confirmed) 
+0

Другие обсуждения: [Index Cookbook] (http://mysql.rjweb.org/doc.php/index_cookbook_mysql). –