[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: WHERE ... OR надо упорядочить
FatCat
Есть запрос к базе. Обычный запрос вывода новостей с форума. В упрощенном виде что-то типа:
$query = "SELECT t.*, p.* FROM topics t, posts p WHERE p.topic_id=t.tid AND t. start_time>".(time()-86400)." AND p.new_post=1";

Последнее условие (p.new_post=1) обеспечивает вывод текста первого сообщения.
Иногда нужно выводить текст не первого сообщения, а сообщения, помеченного вручную (сохраняется в таблице сообщений в поле icon_id). Добавляю условие p.icon_id>0. Запрос:
$query = "SELECT t.*, p.* FROM topics t, posts p WHERE p.topic_id=t.tid AND t. start_time>".(time()-86400)." AND ( p.icon_id>0 OR p.new_post=1 )";

Получаю теперь 2 строки результатов на каждую тему: строка с первым сообщением и строка с помеченным вручную сообщением.
Я конечно могу средствами php отбросить строку с первым сообщением для тех тем, в которых есть помеченные сообщения:
$DB->query($query);
$rowz = array();
while ( $row = $DB->fetch_row() )if( !$rowz[ $row['tid'] ] or $row['icon_id'] > 0 )$rowz[ $row['tid'] ] = $row;

Но логика подсказывает, что грябчить всё что попало из базы, а затем отсеивать лишнее - не продуктивно.
Не соображу как средствами SQL осуществить строгий выбор: если существует p.icon_id>0, то отдавать эту строку, и только если не существует, тогда отдавать строку по условию p.new_post=1.



Спустя 15 минут, 31 секунда (2.08.2012 - 22:40) inpost написал(а):
ORDER BY p.new_post=1 DESC (или ASC) , в таком случае данная запись попадёт в конец по сортировке, а первой будет с p.icon_id, и в конце ещё дописать LIMIT 1, в таком случае p.new_post в сортировке будет последней и выберется лишь в том случае, если она будет последний.
Или ORDER BY FIELD(`p.new_post`,1) . Один из этих вариантов будет верен. Я не помню, будет ли первый вариант работать smile.gif

Спустя 2 часа, 33 минуты, 35 секунд (3.08.2012 - 01:14) FatCat написал(а):
Цитата (inpost @ 3.08.2012 - 00:40)
ORDER BY p.new_post=1 DESC

Ты имеешь в виду ORDER BY p.new_post ASC? Это ничего не даст. Это изменит порядок строк, но строки будут те же самые.


Цитата (inpost @ 3.08.2012 - 00:40)
и в конце ещё дописать LIMIT 1

Лимиты там не допишешь. Мы не знаем сколько тем создано за сутки. Нужны все; не нужно двух строк по одной теме.

Спустя 7 часов, 38 минут, 43 секунды (3.08.2012 - 08:52) svs14 написал(а):
не знаю или поможет, но может стоит здесь глянуть.
http://www.mysql.ru/docs/man/Control_flow_functions.html

Спустя 25 минут, 36 секунд (3.08.2012 - 09:18) Placido написал(а):
Не знаю, как насчет оптимальности, но можно "извратиться" таким образом)
$query = "SELECT t.*, p.* 
FROM topics t
JOIN posts p ON p.topic_id = t.tid
WHERE t.start_time>"
.(time()-86400)."
AND IF((SELECT COUNT(*) FROM posts WHERE icon_id > 0) > 0, p.icon_id > 0, p.new_post = 1)"
;

Спустя 9 минут, 50 секунд (3.08.2012 - 09:28) vagrand написал(а):
тс, никак ты это не сделаеш одним запросом. Тут нужно менять структуру хранения данных или делать два запроса

Спустя 7 минут, 44 секунды (3.08.2012 - 09:36) Placido написал(а):
Цитата (vagrand @ 3.08.2012 - 10:28)
тс, никак ты это не сделаеш одним запросом.

Мой запрос доказывает обратное.

Спустя 2 часа, 59 минут, 15 секунд (3.08.2012 - 12:35) vagrand написал(а):
Placido

твой запрос положит бд даже при средних нагрузках

Спустя 17 минут, 48 секунд (3.08.2012 - 12:53) Placido написал(а):
Цитата (vagrand @ 3.08.2012 - 13:35)
Placido

твой запрос положит бд даже при средних нагрузках

Значит, все-таки, можно сделать одним запросом? Это я насчет голословности утверждений типа "никак ты это не сделаеш одним запросом" (sic). Свои слова необходимо хоть чем-то подкреплять. Это, кстати, касается и "положит БД даже при средних нагрузках". При каких нагрузках? С какими индексами? Какую БД и т.д. Где Explain в подтверждение? По поводу спорности оптимальности запроса я сразу написал, я показал только принцип - при желании можно попробовать его оптимизировать (ответом снова будет "никак ты это не оптимизируеШ?").

Спустя 2 часа, 19 секунд (3.08.2012 - 14:53) vagrand написал(а):
Placido

О каких индексах может идти ресь если у тебя в WHERE подзапрос?

Спустя 3 часа, 4 минуты, 2 секунды (3.08.2012 - 17:57) Placido написал(а):
Цитата (vagrand @ 3.08.2012 - 15:53)
Placido

О каких индексах может идти ресь если у тебя в WHERE подзапрос?

И снова ничем не подтвержденное утверждение. Какая проблема в том, что в WHERE подзапрос? Чем это мешает использованию индексов?

Вот EXPLAIN подобного запроса на таблице в 10000 записей:

user posted image

Время выполнения запроса - 0,016 сек.

Твои аргументы?

Спустя 42 минуты, 56 секунд (3.08.2012 - 18:40) inpost написал(а):
FatCat
Сделай вообще через 2 отдельных запроса. Когда тестировал различные JOIN, то они как-то дубово реализованы в мускуле и в связи с этим 2 отдельных селекта работали быстрее. То есть выборку первую, далее проверяешь через mysql_num_rows, если записи не выбрались - тогда второй запрос.

Спустя 1 час, 39 минут, 38 секунд (3.08.2012 - 20:20) FatCat написал(а):
Цитата (vagrand @ 3.08.2012 - 11:28)
Тут нужно менять структуру хранения данных или делать два запроса

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


Цитата (inpost @ 3.08.2012 - 20:40)
Сделай вообще через 2 отдельных запроса

1 запрос, отдающий 20 строк, мне нравится больше 2 запросов по 10 строк.
Отсортировать массив из 20 ячеек не сложно и средствами php.


_____________
Бесплатному сыру в дырки не заглядывают...
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.