Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Составление SQL-запросов > [MySQL] Случайная сортировка с условием


Автор: Sanchezzz 17.8.2012, 06:57
Добрый день. Есть динамически составленный запрос который составляется через большую функцию впыхе которая на выходе выдает такое

Код

SELECT SQL_CALC_FOUND_ROWS ce.* , v1.value as `create_film` ce  FROM `cblock_element` 
INNER JOIN ( 
     SELECT * FROM cblock_type_value WHERE id_type_feald=8 AND id_lang=1 AND CAST(value as SIGNED)=2011
) v1 ON( v1.id_element = ce.id_element )
WHERE ce.`id_cblock_g` = 1 AND ce.parent_id IN (2,3,184,187,317,556,555,595,950,957) AND ce.is_dir=0
GROUP BY id_element
ORDER BY  ce.`sort` ASC , ce.time DESC
LIMIT 0,24


Условий может быть сколько угодно (до60) они добавляются в запрос примерно так 
Код
 INNER JOIN ( 
     SELECT * FROM cblock_type_value WHERE id_type_feald=8 AND id_lang=1 AND CAST(value as SIGNED)>=2000 and  CAST(value as SIGNED)<=2012 --итд ...
) v1 ON( v1.id_element = ce.id_element )


Cлучайная выборка выполняется с помощью варварского метода  ORDER BY RAND() хотелось бы переделать под элегантный быстрый вариант.
Подскажите как лучше реализовать случайную выборку

Автор: Akina 17.8.2012, 08:01
Цитата(Sanchezzz @  17.8.2012,  07:57 Найти цитируемый пост)
Cлучайная выборка выполняется с помощью варварского метода  ORDER BY RAND()

Нормальный метод

Цитата(Sanchezzz @  17.8.2012,  07:57 Найти цитируемый пост)
хотелось бы переделать под элегантный быстрый вариант.

Элегантных вариантов масса. Но быстрый - не получится. SQL_CALC_FOUND_ROWS - а, значит, выборка всех записей, и никакой LIMIT не поможет.

Кстати, если inner join - нахрена вложенный селект?

Автор: Sanchezzz 17.8.2012, 10:26
SQL_CALC_FOUND_ROWS только считает статистику сколько всего возможно было выбрано если не использовался лимит с ткущим условием выборки это быстрее чем тоже самое с count(*) в отдельным запросе. (я планирую его убирать при рандомных выборках + с лимитом начало позиции оставляя только просто LIMIT N )

И если мне не изменяет память от прочитаного когда то давно то SQL_CALC_FOUND_ROWS  в myIsam бреется из собственной хранения информации о таблице когда для InnoDB наоборот считается тем самым выполнения делается дольше но результат такой же.

Цитата

Кстати, если inner join - нахрена вложенный селект? 


Структура такая хранения данных о объекте в одной таблице ( Мусора ) 
выборка происходит по принцепу обращения к одной и тойже таблице много раз по условию которое строится по специальному объекту класса в пхп

1 критерия условия поиска по нужному полю
Код

$filter->setType('INNER' , 'create_film')>set('create_film' , '>' , 2011)->setAnd('create_film' , '<' , 2012)->setSort('create_film','DESC');

На выходе получаем часть фильтра который потом склеиваем с 2 и 3 куском фильтра в последовательности вызова.
Код

INNER JOIN ( 
     SELECT * FROM cblock_type_value WHERE id_type_feald=8 AND id_lang=1 AND CAST(value as SIGNED) > 2011 and CAST(value as SIGNED) < 2012
) v1 ON( v1.id_element = ce.id_element )

2 критерия поиска по другому полю
Код

$filter->setType('INNER' , 'ratind')>setDoSel()->set('ratind' , '>' , '0.9', '' , '' )->setOr('ratind' , '<' , '09')->setDoSelEnd();

на выходе получаем 
Код

INNER JOIN ( 
     SELECT * FROM cblock_type_value WHERE id_type_feald=7 AND id_lang=1 AND ( value > '09 ' OR value < '0.9' )
) v2 ON( v2.id_element = ce.id_element )


Эти 2 части запросов складываются в той последовательности в какой они были вызваны на выходе получаем полный запрос

Код

SELECT SQL_CALC_FOUND_ROWS ce.* , v1.value as `create_film`  v2.value as `ratind`   FROM `cblock_element` ce

INNER JOIN ( 
     SELECT * FROM cblock_type_value WHERE id_type_feald=8 AND id_lang=1 AND CAST(value as SIGNED)=2011
) v1 ON( v1.id_element = ce.id_element )

INNER JOIN ( 
     SELECT * FROM cblock_type_value WHERE id_type_feald=7 AND id_lang=1 AND ( value > '09 ' OR value < '0.9' )
) v2 ON( v2.id_element = ce.id_element )

WHERE ce.`id_cblock_g` = 1 AND ce.parent_id IN (2,3,184,187,317,556,555,595,950,957) AND ce.is_dir=0
GROUP BY id_element
ORDER BY  `create_film`DESC
LIMIT 0,24

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

Автор: Akina 17.8.2012, 10:36
Чем 
Код

select *
from a
inner join
(
select *
from b 
where b.x='1'
) с on a.y=с.y
where a.z='2'

отличается от
Код

select *
from a, b
where b.x='1' and a.y=b.y and a.z='2'

?


Автор: Sanchezzz 17.8.2012, 10:39
Есть соображения пока только такие:
Обвернуть все в дополнительный SELECT b перенести rand() во временную таблицу с меньшим количеством данных
Код

 select * from (селект, условия выборки + ЛИМИТ N ) t1 ORDER BY RAND() 


Добавлено через 10 минут и 59 секунд
Цитата

отличается от
Код

select *
from a, b
where b.x='1' and a.y=b.y and a.z='2'

?

Нечем оба одинаково работаю за исключением того что мы не создаем лишнею временную таблицу

Автор: Akina 17.8.2012, 10:56
Цитата(Sanchezzz @  17.8.2012,  11:39 Найти цитируемый пост)
мы не создаем лишнею временную таблицу 

Просил быстрее? используй.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)