2014-01-17 2 views
0

Редакцией: Так что это вопрос я использую:оптимизировать MySQL запросов с пунктом IN 10000 записей

SELECT * 
    FROM contacts 
    WHERE id in 
     (
    SELECT DISTINCT contacts.id 
    from contacts INNER 
    JOIN contacts2tags ON contacts.id = contacts2tags.contactid 
    WHERE (tagid in (178))) 

Он работает очень медленно. Предложения по его оптимизации? Я добавил индексы, но он по-прежнему нуждается в улучшении!

контакты таблица содержит идентификатор, first_name, last_name, .й тегов таблицы содержит идентификатор, имя. contacts2tags таблица содержит ContactID и TagID, которые являются такими же, как и contacts.id tags.id соответственно EXPLAIN: enter image description here

Пожалуйста, обратите внимание на: optimise mysql query with LIKE operator for 10k records

Это было глупо с моей стороны, чтобы опубликовать часть запрос здесь. Извините, что: P

+2

Вы можете поставить создать синтаксис из таблиц и контактов, а также объяснения из запроса. Так как youre используя имеющийся будет filesort и соблазнительный. Таким образом, это также зависит от емкости вашего сервера. –

+0

Надеюсь, у вас есть индекс на c.id и индекс на t.tagid, и в этом случае я ожидаю, что MySQL найдет записи в таблице contacts2tags, а затем присоединяет их к контактам. Если на t.tagid нет индекса, но вместо этого у вас есть один на t.contactid, он либо должен будет выполнять поиск без ключа в той или иной таблице, в зависимости от того, что он хочет использовать первым. – Kickstart

+0

спасибо. У меня есть индексы как для tagid, так и для id – user415

ответ

0

Я просто сравнил запросы
выберите контрольный показатель (1000000, 1 in (1,2,3,4,5)); занял 0.122 сек.
выбрать контрольный показатель (1000000, (1 = 1 или 1 = 2 или 1 = 3 или 1 = 4 или 1 = 5)); взял 0.088 сек

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

0

Использование или вместо IN.

Ваш запрос должен быть: SELECT, c.id из списка контактов с внутренним соединением contacts2tags т на c.id = t.contactid ГДЕ (t.tagid = 7 или t.tagid = 4) GROUP BY c.id HAVING count (отличное t.tagid) = 2

0

В плане, который вы показали нам, оптимизатор ожидает, что он должен будет получить 3 строки данных. Если его «медленный» (вы не сказали, как медленно), то, по-видимому, план не оптимален, или ваши данные очень искажены.

Первое, что я хотел бы проверить, является ли статистика индекса актуальной. Затем я попробую ...

SELECT count(*) 
    FROM contacts c 
inner join contacts2tags t 
    on c.id = t.contactid 
    WHERE t.tagid in (7,4) 

Чтобы узнать, сколько строк СУБД фактически обрабатывает для разрешения запроса. Если это число очень велико, вы вряд ли получите большую часть улучшения производительности от настройки запроса.

.... но один из возможных решений было бы ....

SELECT c.id 
FROM contacts c, 
    contacts2tags t4, 
    contacts2tags t7, 
WHERE c.id = t4.contactid 
AND c.id = t7.contactid 
AND t4.contactid=t7.contactid 
AND t4.tagid=4 
AND t7.tagid=7; 
+0

извините, фактическое число строк равно 11000. Я редактирую сообщение с фактическим моментальным снимком (как на самом сервере) – user415

+0

У вас действительно нет первичного ключа на contacts.id ?? ?? !!!! – symcbean

+0

, конечно, у меня есть – user415

0

Не может видеть необходимость использования суб запроса в вашем обновленном запросе. Попробуйте следующее (хотя предпочтительно используйте имена требуемых столбцов из контактов, а не из контактов. *).

SELECT DISTINCT contacts.* 
FROM contacts 
INNER JOIN contacts2tags ON contacts.id = contacts2tags.contactid 
WHERE tagid IN (178) 

Убедитесь, что на таблице контактов2tags указан указатель на tagid.

Если contactid/tagid на контактах2tags уникален (на что я надеюсь), тогда нет необходимости в DISTINCT. Это можно выполнить, добавив уникальный индекс покрытия для tagid/contactid (в этом порядке, чтобы этот ключ использовался в предложении WHERE).

+0

Это не может быть хорошо ?! Предполагая, что для каждого тега имеется несколько идентификаторов, вы получите несколько записей контактов, которые вы затем исправите, снова используя DISTINCT, давая серверу гораздо больше работы, чем это необходимо. – deroby

+0

Альтернативой является использование соединения с подзапросом, результатом которого является неиндексирование соединения или использование IN с дополнительным запросом, как в исходном сообщении, которое снова не индексируется. В этом случае он, вероятно, выполнит запрос против контактов2tags с индексированным столбцом tagid, а затем присоединяется к контактам с использованием поля первичного ключа. Выделенный является неприятным, но на самом деле не может быть оправдан с любой эффективностью, если в предложении IN есть более одного тега. – Kickstart

0

Мне было интересно, почему вы сначала подключаетесь к контактам и контактам2tags в подзапросе, а затем используете это, чтобы снова фильтровать контакты!?!

Я предполагаю, что вы уже оптимизировали DISTINCT на поле id (lean) id вместо того, чтобы делать это после всех контактов. * Запись.

Во всяком случае, то, что вы на самом деле нужно делать ИМХО следующее:

SELECT * 
FROM contacts 
WHERE EXISTS (SELECT * 
       FROM contacts2tags 
       WHERE contacts2tags.contactid = contacts.id 
        AND tagid in (178)) 

Это не двойные контакты записи, как процессор запросов знает, что может остановить поиск, когда он находит первый удар в таблице contacts2tags.

Что касается использования IN() против использования или ... Я сомневаюсь, что он будет делать много различий, как внутри страны, что, вероятно, получает переведенный к тому же в любом случае (?!)

+0

эй, пожалуйста, посмотрите http://stackoverflow.com/questions/21154636/optimise-mysql-query-with-like-operator-for-10k-records/21155012#21155012. Я думаю, поскольку в контактах2tags есть много записей table также, запрос стал еще медленнее, когда я использовал WHERE EXISTS (..), или это может быть иная причина. Я - любитель в MySQL. Спасибо за опору с этим сообщением. : D – user415

+0

Другое сообщение выглядит в основном о LIKE и текстовом сопоставлении; Я сомневаюсь, что WHERE EXISTS() имеет какое-то отношение к этому. В моем (на основе MSSQL) примере WHERE EXISTS() никогда не должно быть медленнее, чем JOINING, особенно если этот JOIN не потребует дополнительного DISTINCT позже. Но, может быть, mysql свойственна? – deroby

Смежные вопросы