Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757
Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737 Форумы портала PHP.SU :: Помогите оптимизировать запрос
SELECT utt.name, utt.id FROM utt INNER JOIN nms ON nms.id = utt.id
WHERE utt.id > 1 AND (nms.type = 'foto' OR nms.type = 'album') ORDER BY RAND() LIMIT 0,15
$row_count = mysql_result(mysql_query("SELECT COUNT(*) FROM utt"));
$query = array();
while (count($query) < 15){
$query[]='(SELECT utt.name, utt.id FROM utt INNER JOIN nms ON nms.id = utt.id WHERE utt.id > 1 AND (nms.type = foto OR nms.type = album LIMIT '.rand($row_count).', 1)';
}
$query = implode(' UNION ', $query);
$res = mysql_query($query);
подскажите все ли правильно?
Altynayka
Отправлено: 03 Апреля, 2012 - 15:24:54
Частый гость
Покинул форум
Сообщений всего: 208
Дата рег-ции: Март 2008
Покинул форум
Сообщений всего: 9095
Дата рег-ции: Июнь 2007 Откуда: Berlin
Помог: 707 раз(а)
10 ms? Не так и плохо для случайной выборки. Посмотрите, что отображает EXPLAIN SELECT (хотя, думаю, с ним все будет в порядке)
Цитата:
$mas = array_unique($mas);
- это мне непонятно, зачем делается. У Вас id - не первичный ключ? Если все первичный, то априори значения будут уникальными.
Затем, выборка всех id - требует много памяти. И это тоже может ухудшать производительность.
----- Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
Altynayka
Отправлено: 03 Апреля, 2012 - 15:58:28
Частый гость
Покинул форум
Сообщений всего: 208
Дата рег-ции: Март 2008
Помог: 0 раз(а)
да, но он как-то скачет от 10 до 20. "explain" -обязательно попробую.
нет не первичный ключ в том то и дело, убрала связку с другой таблицей, где и был первичным ключом, но из-за этого время увеличивается.
Цитата:
Затем, выборка всех id - требует много памяти. И это тоже может ухудшать производительность.
- я понимаю, но пропадет весь смысл в случайной выборке...
Покинул форум
Сообщений всего: 11926
Дата рег-ции: Июль 2009 Откуда: Россия, Санкт-Петербург
Помог: 618 раз(а)
Смотрите, что explain пишет, какой индекс использует, из каких выбирает, сколько строк затрагивает. Сколько вообще строк возвращается. может, эффективнее будет select distinct, вместо array_unique
----- PostgreSQL DBA
Altynayka
Отправлено: 05 Апреля, 2012 - 11:37:24
Частый гость
Покинул форум
Сообщений всего: 208
Дата рег-ции: Март 2008
Помог: 0 раз(а)
Select distinct - пробовала -время увеличивается.
EuGen
Отправлено: 05 Апреля, 2012 - 12:42:50
Профессионал
Покинул форум
Сообщений всего: 9095
Дата рег-ции: Июнь 2007 Откуда: Berlin
Помог: 707 раз(а)
Altynayka
Вообще, задача "выбрать случайные N строк из таблицы" - несмотря на простую формулировку, не имеет простого решения.
По поводу Вашего решения - на недостатки я указывал - ведь Вы загружаете в память весь набор идентификаторов, и потому работа замедляется.
Существует несколько подходов к решению задачи, но нет "идеального". Среди решений я бы выделил два основных направления:
- Использующие только SQL. К таким относятся ORDER BY RAND() и все подобное. Впрочем, удалось найти и более оригинальные решения, например
этот вариант будет существенно быстрее, однако же он дает возможность выбрать лишь одну запись, и таким образом, в случае N записей сложность возрастает линейно.
- Варианты, использующие различные внешние средства. Например, php-генерация запроса. Первый из них - использовать UNION и LIMIT. Подойдет только для небольших таблиц, так как LIMIT M,1 заставляет СУБД выбирать M строк с тем, чтобы потом оставить одну, то есть производительность ухудшается линейно с увеличением размера таблицы:
return'SELECT * FROM test LIMIT '.(int)$x.', 1'."\n";
},$rgResult));
//var_dump($sQuery);
минус его еще и в том, что SELECT COUNT(*) должен быть строго привязан к последующему коду, что порождает необходимость блокировки таблицы (иначе может случиться так, что сгенерируется случайное число, равное максимальному а за время обработки данных в массиве запись с этим номером была уже удалена) Следующий - хороший на мой взгляд, вариант - вводить дополнительное поле, которое будет являться номером строки "как есть", то есть будет всегда идти по порядку. В этом случае худшее, что есть в предыдущем варианте - а именно выборку по LIMIT (да впридачу еще и с UNION) - можно заменить на выборку по ключу, с IN - а это куда быстрее. Минус этого подхода очевиден - это введение дополнительного ключа (что замедляет операции вставки) а так же необходимость следить за соблюдением правильной нумерации. Это приводит либо к введению триггеров, либо к контролю за полем на уровне того же PHP. И последний вариант, который, по моему мнению, заслуживает внимания - это перемешивание записей таблицы регулярно (например, постановка в планировщик cron). Тогда исходная задача сведется к выборке N подряд записей начиная со случайной. Либо же, если перемешивание идет часто, N подряд просто с 1-й записи. Минус тоже легко заметить - способ непригоден для активно используемых таблиц и для проектов с загрузкой "24/7", так как перемешать записи в таблице - весьма ресурсоемкая операция.
----- Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
Все гости форума могут просматривать этот раздел. Только зарегистрированные пользователи могут создавать новые темы в этом разделе. Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.