Выбор случайных записей
в основном записи выбираются методом: получаем общее число записей ( SELECT COUNT(*) FROM .. WHERE ..)
и дальше n запросов типа (SELECT * FROM .. WHERE .. LIMIT $rnd,1);
помоему 10 таких запросов - очень нагрузочное место и нагрузка, кажется, растет при увелечении кол-ва записей в таблице:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE ir2_catalog_item ALL NULL NULL NULL NULL 86 Using where
т.к. записи меняются сравнительно редко(выбирать случайные надо намного чаще чем обновлять данные)у меня возникла мысля создать доб-таблицу c ключами удовлетворяющими условию и где PRIMARY KEY - последовательно меняется от 1 до кол-ва записей.
в результате для получения случайных записей из таблицы вышла такая ф-я:
{
global $cfg;
if($cfg["dbconn"]===false) connect_to_db();
if($cfg["dbconn"]===false) return false;
$tbl_rnd=SQL.$rnd_prefix.md5($where);//имя таблицы для быстрого выбора случайных записей
//при необходимости создаем данную таблицу
$query= "CREATE TABLE IF NOT EXISTS `$tbl_rnd` (
`key` INT NOT NULL auto_increment,
`id` INT NOT NULL DEFAULT 0,
PRIMARY KEY (`key`))
SELECT 0 AS `key`, `main`.`$key` AS `id`
FROM `$tbl` AS `main`
WHERE $where";
@mysql_query($query);
//кол-во записей в таблице
$row=mysql_fetch_row(mysql_query("SELECT COUNT(*) FROM `$tbl_rnd`"));
if(!$row)return false;
$count=(int)$row[0];
//генерация случайных ключей
$keys=array();
mt_srand();
$i=1;
while(($i<=$num)&&($i<=$count))
{
$k=mt_rand($i,$count);
while(in_array($k,$keys))$k--;//для того чтобы ключи были уникальными
$keys[]=$k;
}
if(count($keys)==0)return null;
//построение ответа
$query="SELECT $select FROM `$tbl_rnd` AS `rnd`
LEFT JOIN `$tbl` AS `main` ON `main`.`$key`=`rnd`.`id`
$left_join
WHERE `rnd`.`key` IN (".implode(',',$keys).")";
$res=db_query($query);
$ret = array();
while($row = mysql_fetch_array($res))
{
$ret[] = $row;
}
return $ret;
}
здесь получается один жутко нагрузочный запрос по созданию новой таблицы, но он исполняется посути один раз после обновления записей.
и помоему максимально оптимальный запрос на выборку данных:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE rnd range PRIMARY PRIMARY 4 NULL 3 Using where
1 SIMPLE main eq_ref PRIMARY PRIMARY 4 w035.rnd.id 1
а т.к. в других проектах я такой метод не встречал, возникает вопрос: а каие недостатки данного метода я недосмотрел?
сканает такой вариант? )
Который является ответом на этот топик с вариантом создания процедуры для MySQl http://habrahabr.ru/blogs/mysql/54176/
В обоих топиках самое интересное как всегда в комментариях.
сгенери сколько тебе нужно rand'омных ID (раз уж они последовательные) и сделай SELECT * WHERE id IN (..., ..., ..., ...)
именно для этих целей и генерилась дополнительная таблица в которой id идут последовательно.
Гуглить пробовал.
http://habrahabr.ru/blogs/mysql/55864/ - это раньше ненаходил.
наверно из за коментария про сентетический ключ (http://habrahabr.ru/blogs/mysql/54176/) и возникла такая мысль. Раньше использовал то что предложено в статье, но хочется найти метод пооптимальнее.
из того что ненравется по поводу синтетического ключа:
допустим захотелось добавить модуль показующий товары из какойто категории, в результате надо добавить дополнительное поле в таблицу с товарами, и функцию генерации данного ключа - после нескольких подобных изменений есть большой риск превратитить функцию изменения товара в свалку кода следящего чтобы правельно генерировались синтетические ключи для разных устовий.
идею с ускорением ORDER BY RAND() пока еще полноценно продумать неуспел, но там возможна сложность если надо выбирать из нескольких разных наборов и зарание неизвестны размеры данных наборов и всей таблицы