Ответ 1
Кажется, что подзапросы очень медленные, как упоминалось в этой статье http://www.mysqlperformanceblog.com/2010/10/25/mysql-limitations-part-3-subqueries.
Вы должны попытаться избежать подзапросов и использовать соединение вместо этого.
У меня есть таблица вроде этого
name | personal_number
-----------------------------------------
Jon | 222
Alex | 555
Jon | 222
Jimmy | 999
Мне нужно получить каждое имя, которое персональное_состояние повторяется в таблице более 1, то есть результат должен быть:
Jon
Jon
Итак, вариант 1):
SELECT name FROM mytable WHERE personal_number IN (
SELECT personal_number FROM mytable GROUP BY personal_number
HAVING COUNT(*) > 1
)
Вариант 2):
SELECT personal_number FROM mytable GROUP BY personal_number
HAVING COUNT(*) > 1
)
Затем, используя php, извлеченные персональные_нимеры соединяются как строка (soemthing like this '222', '222'
) и запускают другой запрос
SELECT name FROM mytable WHERE personal_number IN( here joined string )
Вариант 2 работает примерно в 10 раз быстрее, чем вариант 1, это для меня неожиданно, я думал, что один запрос будет быстрее, но...
(В таблице 500 000 строк, столбец personal_number
не проиндексирован)
Итак, что вы имеете в виду о таких случаях? почему вариант 2 намного быстрее, чем вариант 1?
Кажется, что подзапросы очень медленные, как упоминалось в этой статье http://www.mysqlperformanceblog.com/2010/10/25/mysql-limitations-part-3-subqueries.
Вы должны попытаться избежать подзапросов и использовать соединение вместо этого.
Первый запрос имеет тяжелый подзапрос. Вы должны избегать этого. Лучшим решением для вашей проблемы является только один запрос:
SELECT name FROM mytable GROUP BY personal_number HAVING COUNT(*) > 1;
Этот запрос возвращает вам каждое повторное имя только один раз. Если вы хотите отображать имя дубликата столько раз, сколько они встречались, вы должны использовать следующий запрос:
SELECT name, COUNT(*) AS count FROM mytable GROUP BY personal_number HAVING COUNT(*) > 1;
И затем в PHP сделайте что-то вроде этого:
foreach ($rows as $row) {
for ($i = 0; $i++; $i < $row['count']) {
echo $row['name'] . "\n";
}
}
Это должно быть быстрее:
SELECT name FROM mytable join (
SELECT personal_number FROM mytable GROUP BY personal_number
HAVING COUNT(*) > 1
)a using (personel_number)
Изменить: если это быстрее, чем вариант 1, то это означает, что в варианте 1 mysql снова и снова воспроизводит внутреннюю таблицу для каждой записи.
Так как индексация не выполняется, так что 1 медленный, так как он должен соответствовать личным_знакам из выбранных персональных номеров. Если индексирование выполняется, оно потребляет меньше времени, чем раньше. Вариант 2 является прямым запросом, следовательно, он быстрее.